/ Arduino_Phone / Arduino_Phone / Arduino_Phone.ino
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  }