Arduino_Phone.ino
1 // SPDX-FileCopyrightText: 2019 Anne Barela for Adafruit Industries 2 // 3 // SPDX-License-Identifier: MIT 4 5 /* 6 does: 7 * can make calls on the speaker & mic 8 todo: 9 * status notification updates in loop() 10 * dim screen when no touches in 1 minute 11 * receive calls 12 * receive texts 13 * candy crush 14 15 */ 16 17 18 #include <SPI.h> 19 #include <Wire.h> // this is needed even tho we aren't using it 20 #include "Adafruit_GFX.h" 21 #include "Adafruit_ILI9341.h" 22 #include <Adafruit_STMPE610.h> 23 #include <SoftwareSerial.h> 24 #include "Adafruit_FONA.h" 25 26 #define FONA_RX 2 27 #define FONA_TX 3 28 #define FONA_RST 4 29 30 SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX); 31 Adafruit_FONA fona = Adafruit_FONA(FONA_RST); 32 33 34 // For the Adafruit TFT shield, these are the default. 35 #define TFT_DC 9 36 #define TFT_CS 10 37 38 // Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC 39 Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); 40 41 // The STMPE610 uses hardware SPI on the shield, and #8 42 #define STMPE_CS 8 43 Adafruit_STMPE610 ts = Adafruit_STMPE610(STMPE_CS); 44 45 // This is calibration data for the raw touch data to the screen coordinates 46 #define TS_MINX 150 47 #define TS_MINY 130 48 #define TS_MAXX 3800 49 #define TS_MAXY 4000 50 51 /******************* UI details */ 52 #define BUTTON_X 40 53 #define BUTTON_Y 100 54 #define BUTTON_W 60 55 #define BUTTON_H 30 56 #define BUTTON_SPACING_X 20 57 #define BUTTON_SPACING_Y 20 58 #define BUTTON_TEXTSIZE 2 59 60 // text box where numbers go 61 #define TEXT_X 10 62 #define TEXT_Y 10 63 #define TEXT_W 220 64 #define TEXT_H 50 65 #define TEXT_TSIZE 3 66 #define TEXT_TCOLOR ILI9341_MAGENTA 67 // the data (phone #) we store in the textfield 68 #define TEXT_LEN 12 69 char textfield[TEXT_LEN+1] = ""; 70 uint8_t textfield_i=0; 71 72 // We have a status line for like, is FONA working 73 #define STATUS_X 10 74 #define STATUS_Y 65 75 76 /* create 15 buttons, in classic candybar phone style */ 77 char buttonlabels[15][5] = {"Send", "Clr", "End", "1", "2", "3", "4", "5", "6", "7", "8", "9", "*", "0", "#" }; 78 uint16_t buttoncolors[15] = {ILI9341_DARKGREEN, ILI9341_DARKGREY, ILI9341_RED, 79 ILI9341_BLUE, ILI9341_BLUE, ILI9341_BLUE, 80 ILI9341_BLUE, ILI9341_BLUE, ILI9341_BLUE, 81 ILI9341_BLUE, ILI9341_BLUE, ILI9341_BLUE, 82 ILI9341_ORANGE, ILI9341_BLUE, ILI9341_ORANGE}; 83 Adafruit_GFX_Button buttons[15]; 84 85 // Print something in the mini status bar with either flashstring 86 void status(const __FlashStringHelper *msg) { 87 tft.fillRect(STATUS_X, STATUS_Y, 240, 8, ILI9341_BLACK); 88 tft.setCursor(STATUS_X, STATUS_Y); 89 tft.setTextColor(ILI9341_WHITE); 90 tft.setTextSize(1); 91 tft.print(msg); 92 } 93 // or charstring 94 void status(char *msg) { 95 tft.fillRect(STATUS_X, STATUS_Y, 240, 8, ILI9341_BLACK); 96 tft.setCursor(STATUS_X, STATUS_Y); 97 tft.setTextColor(ILI9341_WHITE); 98 tft.setTextSize(1); 99 tft.print(msg); 100 } 101 102 void setup() { 103 Serial.begin(9600); 104 Serial.println("Arduin-o-Phone!"); 105 106 // clear the screen 107 tft.begin(); 108 tft.fillScreen(ILI9341_BLACK); 109 110 // eep touchscreen not found? 111 if (!ts.begin()) { 112 Serial.println("Couldn't start touchscreen controller"); 113 while (1); 114 } 115 Serial.println("Touchscreen started"); 116 117 // create buttons 118 for (uint8_t row=0; row<5; row++) { 119 for (uint8_t col=0; col<3; col++) { 120 buttons[col + row*3].initButton(&tft, BUTTON_X+col*(BUTTON_W+BUTTON_SPACING_X), 121 BUTTON_Y+row*(BUTTON_H+BUTTON_SPACING_Y), // x, y, w, h, outline, fill, text 122 BUTTON_W, BUTTON_H, ILI9341_WHITE, buttoncolors[col+row*3], ILI9341_WHITE, 123 buttonlabels[col + row*3], BUTTON_TEXTSIZE); 124 buttons[col + row*3].drawButton(); 125 } 126 } 127 128 // create 'text field' 129 tft.drawRect(TEXT_X, TEXT_Y, TEXT_W, TEXT_H, ILI9341_WHITE); 130 131 status(F("Checking for FONA...")); 132 // Check FONA is there 133 fonaSS.begin(4800); // if you're using software serial 134 135 // See if the FONA is responding 136 if (! fona.begin(fonaSS)) { // can also try fona.begin(Serial1) 137 status(F("Couldn't find FONA :(")); 138 while (1); 139 } 140 status(F("FONA is OK!")); 141 142 // Check we connect to the network 143 while (fona.getNetworkStatus() != 1) { 144 status(F("Looking for service...")); 145 delay(100); 146 } 147 status(F("Connected to network!")); 148 149 // set to external mic & headphone 150 fona.setAudio(FONA_EXTAUDIO); 151 } 152 153 154 void loop(void) { 155 TS_Point p; 156 157 if (ts.bufferSize()) { 158 p = ts.getPoint(); 159 } else { 160 // this is our way of tracking touch 'release'! 161 p.x = p.y = p.z = -1; 162 } 163 164 // Scale from ~0->4000 to tft.width using the calibration #'s 165 if (p.z != -1) { 166 p.x = map(p.x, TS_MINX, TS_MAXX, 0, tft.width()); 167 p.y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height()); 168 Serial.print("("); Serial.print(p.x); Serial.print(", "); 169 Serial.print(p.y); Serial.print(", "); 170 Serial.print(p.z); Serial.println(") "); 171 } 172 173 // go thru all the buttons, checking if they were pressed 174 for (uint8_t b=0; b<15; b++) { 175 if (buttons[b].contains(p.x, p.y)) { 176 //Serial.print("Pressing: "); Serial.println(b); 177 buttons[b].press(true); // tell the button it is pressed 178 } else { 179 buttons[b].press(false); // tell the button it is NOT pressed 180 } 181 } 182 183 // now we can ask the buttons if their state has changed 184 for (uint8_t b=0; b<15; b++) { 185 if (buttons[b].justReleased()) { 186 // Serial.print("Released: "); Serial.println(b); 187 buttons[b].drawButton(); // draw normal 188 } 189 190 if (buttons[b].justPressed()) { 191 buttons[b].drawButton(true); // draw invert! 192 193 // if a numberpad button, append the relevant # to the textfield 194 if (b >= 3) { 195 if (textfield_i < TEXT_LEN) { 196 textfield[textfield_i] = buttonlabels[b][0]; 197 textfield_i++; 198 textfield[textfield_i] = 0; // zero terminate 199 200 fona.playDTMF(buttonlabels[b][0]); 201 } 202 } 203 204 // clr button! delete char 205 if (b == 1) { 206 207 textfield[textfield_i] = 0; 208 if (textfield > 0) { 209 textfield_i--; 210 textfield[textfield_i] = ' '; 211 } 212 } 213 214 // update the current text field 215 Serial.println(textfield); 216 tft.setCursor(TEXT_X + 2, TEXT_Y+10); 217 tft.setTextColor(TEXT_TCOLOR, ILI9341_BLACK); 218 tft.setTextSize(TEXT_TSIZE); 219 tft.print(textfield); 220 221 // its always OK to just hang up 222 if (b == 2) { 223 status(F("Hanging up")); 224 fona.hangUp(); 225 } 226 // we dont really check that the text field makes sense 227 // just try to call 228 if (b == 0) { 229 status(F("Calling")); 230 Serial.print("Calling "); Serial.print(textfield); 231 232 fona.callPhone(textfield); 233 } 234 235 delay(100); // UI debouncing 236 } 237 } 238 }