Advertisement
Guest User

Untitled

a guest
Jun 3rd, 2016
339
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 49.99 KB | None | 0 0
  1. #include <Arduino.h>
  2.  
  3. #include <u8g_i2c.h>
  4. #include <i2c_t3.h>
  5. #include <DS1307RTC.h> //this works with out clock (DS3231) but we will have to implemnt our own alarm functions
  6. #include <EEPROM.h>
  7. #include <Time.h>
  8. #include <Snooze.h>
  9.  
  10. #define HWSERIAL Serial1
  11.  
  12. SnoozeBlock config;
  13.  
  14. //needed for calculating Free RAM on ARM based MC's
  15. #ifdef __arm__
  16.   extern "C" char* sbrk(short incr);
  17. #else  // __ARM__
  18.   extern char *__brkval;
  19.   extern char __bss_end;
  20. #endif  // __arm__
  21.  
  22. //u8g lib object without the c++ wrapper due to lack of support of the OLED
  23. u8g_t u8g;
  24.  
  25. //input vars
  26. bool button_ok = false;
  27. bool lastb_ok = false;
  28. bool button_up = false;
  29. bool lastb_up = false;
  30. bool button_down = false;
  31. bool lastb_down = false;
  32.  
  33. #define CONFIRMATION_TIME 80 //length in time the button has to be pressed for it to be a valid press
  34. #define INPUT_TIME_OUT 60000 //60 seconds
  35. #define TOUCH_THRESHOLD 1200 // value will change depending on the capacitance of the material
  36.  
  37. //need to use 4,2,1 as no combination of any of the numbers makes the same number, where as 1,2,3 1+2 = 3 so there is no individual state.
  38. #define UP_ONLY  4
  39. #define OK_ONLY  2
  40. #define DOWN_ONLY  1
  41. #define UP_OK  (UP_ONLY|OK_ONLY)
  42. #define UP_DOWN  (UP_ONLY|DOWN_ONLY)
  43. #define DOWN_OK  (OK_ONLY|DOWN_ONLY)
  44. #define ALL_THREE (UP_ONLY|OK_ONLY|DOWN_ONLY)
  45. #define NONE_OF_THEM  0
  46.  
  47. //#define isButtonPressed(pin)  (digitalRead(pin) == LOW) this was old with buttons
  48. #define isButtonPressed(pin) (touchRead(pin) > TOUCH_THRESHOLD)
  49.  
  50. short lastVector = 0;
  51. long prevButtonPressed = 0;
  52.  
  53. //serial retrieval vars
  54. char message[100]; // serial read buffer
  55. char *messagePtr; //this could be local to the receiving loop
  56. char finalData[250];//data set buffer
  57. short finalDataIndex = 0; //index is required as we dunno when we stop
  58. short messageIndex = 0;
  59. bool readyToProcess = false;
  60. bool receiving = false;
  61. bool checkingTag = false;
  62. char messageBuffer[3];
  63.  
  64. //date contants
  65. String PROGMEM months[12] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
  66. String PROGMEM days[7] = {"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
  67. const short PROGMEM dayInMonth[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; //does not account for leap year
  68.  
  69. //weather vars
  70. bool weatherData = false;
  71. char weatherDay[4];
  72. char weatherTemperature[4];
  73. char weatherForecast[25];
  74. short timeWeGotWeather[2] = {0,0};
  75.  
  76.  
  77. //time and date constants
  78. tmElements_t tm;
  79. time_t t;
  80. const short PROGMEM clockRadius = 32;
  81. const short PROGMEM clockUpdateInterval = 1000;
  82.  
  83. //time and date vars
  84. bool gotUpdatedTime = false;
  85. short clockArray[3] = {0,0,0};
  86. short dateArray[4] = {0,0,0,0};
  87.  
  88. long prevMillis = 0;
  89.  
  90. //notification data structure
  91. typedef struct{
  92.   char packageName[15];
  93.   char title[15];
  94.   char text[150];
  95.   short dateReceived[2];
  96.   short textLength;
  97. } Notification;
  98.  
  99. //notification vars
  100. short notificationIndex = 0;
  101. short PROGMEM notificationMax = 10;
  102. Notification notifications[10]; //reflect notification index to account for one kless here
  103. bool wantNotifications = true;
  104. bool shouldRemove = false;
  105.  
  106. //pin constants
  107. const short PROGMEM OK_BUTTON = 17;
  108. const short PROGMEM DOWN_BUTTON = 16;
  109. const short PROGMEM UP_BUTTON = 15;
  110. const short PROGMEM BATT_READ = A6;
  111. const short PROGMEM VIBRATE_PIN = 10;
  112. const short PROGMEM CHARGING_STATUS_PIN = 9;
  113. const short PROGMEM BT_POWER = 21; // pin 5 is broken, need to reflow? as voltage is only 1.3v so using pin 21
  114.  
  115. //navigation constants
  116. const short PROGMEM HOME_PAGE = 0;
  117. const short PROGMEM NOTIFICATION_MENU = 1;
  118. const short PROGMEM NOTIFICATION_BIG = 2;
  119. const short PROGMEM TIMER = 4;
  120. const short PROGMEM SETTINGS = 5;
  121. const short PROGMEM ALARM_PAGE = 6;
  122. const short PROGMEM SHUTDOWN = 7;
  123.  
  124. const short PROGMEM ALERT = 10;
  125.  
  126. //UI constants
  127. const short PROGMEM MENU_ITEM_HEIGHT = 16;
  128. const short PROGMEM FONT_HEIGHT = 12; //need to add this to the y for all DrawStr functions
  129.  
  130. //navigation vars
  131. short pageIndex = 0;
  132. short menuSelector = 0;
  133. short widgetSelector = 0;
  134. const short numberOfNormalWidgets = 7; // actually 3, 0,1,2.
  135. const short numberOfDebugWidgets = 1;
  136. short numberOfWidgets = 0;
  137. short numberOfPages = 6; // actually 7 (0-6 = 7)
  138.  
  139. const short x = 6;
  140. short y = 0;
  141. short Y_OFFSET = 0;
  142.  
  143. short lineCount = 0;
  144. short currentLine = 0;
  145.  
  146. //batt monitoring
  147. float batteryVoltage = 0;
  148. short batteryPercentage = 0;
  149. bool isCharging = false;
  150. bool prevIsCharging = false;
  151. bool isCharged = false;
  152. bool started = false; //flag to identify whether its the start or the end of a charge cycle
  153.  
  154. bool shutdown = false;
  155. bool readyForShutdown = false;
  156. short shutDownCounter = -1; // when we free up some space add a page to count down till shutdown, allowing the shutdown to be cancelled
  157.  
  158.  
  159. //timer variables
  160. short timerArray[3] = {0,0,0}; // h/m/s
  161. bool isRunning = false;
  162. short timerIndex = 0;
  163.  
  164.  
  165. bool locked = false;
  166.  
  167. //connection
  168. bool isConnected = false;
  169. short connectedTime = 0;
  170.  
  171. //settings
  172. const short numberOfSettings = 2;
  173. String PROGMEM settingKey[numberOfSettings] = {"Favourite Widget:","Debug Widgets:"};
  174. const short PROGMEM settingValueMin[numberOfSettings] = {0,0};
  175. const short PROGMEM settingValueMax[numberOfSettings] = {numberOfPages,1};
  176. short settingValue[numberOfSettings] = {0,0}; //default
  177.  
  178. //alert popup
  179. short lastPage = -1;
  180. char alertText[20]; //20 chars that fit
  181. short alertTextLen = 0;
  182. short alertVibrationCount = 0;
  183. bool vibrating = false;
  184. long prevAlertMillis = 0;
  185.  
  186. short loading = 3; // time the loading screen is show for
  187.  
  188. //drawing buffers used for character rendering
  189. char numberBuffer[3]; //2 numbers //cahnged to 3 till i find what is taking 3 digits and overflowing
  190. const short charsThatFit = 20; //only with default font. 0-20 = 21 chars
  191. char lineBuffer[21]; // 21 chars                             ^^
  192. short charIndex = 0;
  193.  
  194. //alarm vars
  195. bool activeAlarms[2] = {false,false};
  196. short alarmTime[3] = {0,0,0}; //alarm time: hours, mins, dateDay
  197. const short PROGMEM alarmMaxValues[3] = {23,59,6};
  198. short alarmToggle = 0; // alarm1 = 0, alarm2 = 1
  199. short prevAlarmToggle = 1;
  200. short alarmIndex = 0;
  201. const short ALARM_ADDRESS = 20;//start at 30, each alarm has 4 stored values, active,hours,mins,dateDay
  202.  
  203. //used for power saving
  204. //bool idle = false;
  205.  
  206. //Logo for loading
  207. const byte PROGMEM LOGO[] = {
  208.   0x00, 0x00, 0x00, 0x1e, 0x00, 0x0f, 0x3e, 0x80, 0x0f, 0x3e, 0x80, 0x0f,
  209.    0x7e, 0xc0, 0x0f, 0x6e, 0xc0, 0x0e, 0xee, 0xc0, 0x0e, 0xce, 0x60, 0x0e,
  210.    0xce, 0x61, 0x0e, 0xce, 0x71, 0x0e, 0x8e, 0x31, 0x0e, 0x8e, 0x3b, 0x0e,
  211.    0x0e, 0x1b, 0x0e, 0x0e, 0x1f, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
  212.    0x0e, 0x0e, 0x0e, 0x0e, 0x00, 0x0e, 0x0e, 0x00, 0x0e, 0x0e, 0x00, 0x0e,
  213.    0x0e, 0x00, 0x0e, 0x0e, 0x00, 0x0e, 0x0e, 0x00, 0x0e, 0x00, 0x00, 0x00
  214. };
  215.  
  216. //icons
  217. const byte PROGMEM BLUETOOTH_CONNECTED[] = {
  218.    0x31, 0x52, 0x94, 0x58, 0x38, 0x38, 0x58, 0x94, 0x52, 0x31
  219. };
  220.  
  221. const byte PROGMEM CHARGING[] = {
  222.   0x00, 0x00, 0x00, 0x00, 0xf0, 0x03, 0x10, 0x02, 0x18, 0x1e, 0x1e, 0x02,
  223.    0x1e, 0x02, 0x18, 0x1e, 0x10, 0x02, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00
  224. };
  225.  
  226. const byte PROGMEM CHARGED[] = {
  227.    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x24, 0x09, 0x24, 0x19,
  228.    0x24, 0x19, 0x24, 0x09, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  229.  };
  230.  
  231. void setup(void) {
  232.   Serial.begin(9600);
  233.   HWSERIAL.begin(9600);
  234.  
  235.   pinMode(OK_BUTTON,INPUT_PULLUP);
  236.   pinMode(DOWN_BUTTON,INPUT_PULLUP);
  237.   pinMode(UP_BUTTON,INPUT_PULLUP);
  238.  
  239.   pinMode(BATT_READ,INPUT);
  240.   pinMode(CHARGING_STATUS_PIN,INPUT_PULLUP);
  241.  
  242.   pinMode(BT_POWER,OUTPUT);
  243.   pinMode(VIBRATE_PIN,OUTPUT);
  244.  
  245.   //turn on BT
  246.   digitalWrite(BT_POWER, HIGH);
  247.  
  248.   u8g_prepare();
  249.  
  250.   for(short i = 0; i < numberOfSettings; i++){
  251.     settingValue[i] = readFromEEPROM(i);
  252.   }
  253.  
  254.   //eeprom reset
  255.   /*for(short j=0; j < EEPROM.length(); j ++){
  256.     saveToEEPROM(j,0);
  257.   }*/
  258.  
  259.   activeAlarms[0] = readFromEEPROM(ALARM_ADDRESS);
  260.   activeAlarms[1] = readFromEEPROM(ALARM_ADDRESS + 5);
  261.  
  262.   messagePtr = &message[0]; // could have used messagePtr = message
  263.  
  264.   //setup batt read pin
  265.   analogReference(DEFAULT);
  266.   analogReadResolution(10);// 2^10 = 1024
  267.   analogReadAveraging(32);//smoothing
  268.  
  269.   config.pinMode(DOWN_BUTTON, TSI, touchRead(DOWN_BUTTON) + 250);
  270.  
  271.   //HWSERIAL.print("AT"); to cut the connection so we have to reconnect if the watch crashes
  272.  
  273.   HWSERIAL.print("AT");
  274.  
  275.   Serial.println(F("MabezWatch OS Loaded!"));
  276. }
  277.  
  278. void u8g_prepare(void) {
  279.   u8g_InitComFn(&u8g, &u8g_dev_sh1106_128x64_2x_i2c, u8g_com_hw_i2c_fn);
  280.   u8g_SetFont(&u8g, u8g_font_6x12);
  281. }
  282.  
  283. /*
  284. * Draw generic menu method
  285. */
  286.  
  287. void showMenu(short numberOfItems,void itemInMenuFunction(short),bool showSelector){
  288.   for(short i=0; i < numberOfItems + 1;i++){
  289.     short startY = 0;
  290.     if(i==menuSelector && showSelector){
  291.         u8g_DrawStr(&u8g,0,y+Y_OFFSET+FONT_HEIGHT,">");
  292.     }
  293.     if(i!=numberOfItems){
  294.         itemInMenuFunction(i); //draw our custom menuItem
  295.     } else {
  296.       u8g_DrawStr(&u8g,x + 3,y + Y_OFFSET+FONT_HEIGHT, "Back");
  297.     }
  298.     y += MENU_ITEM_HEIGHT;
  299.     u8g_DrawFrame(&u8g,x,startY,128,y +Y_OFFSET);
  300.   }
  301.   y = 0;
  302. }
  303.  
  304. /*
  305. * System tick method
  306. */
  307.  
  308. void updateSystem(){
  309.   long currentInterval = millis();
  310.   if((currentInterval - prevMillis) >= clockUpdateInterval){
  311.     prevMillis = currentInterval;
  312.  
  313.     //update RTC info
  314.     RTC.read(tm);
  315.     clockArray[0] = tm.Hour;
  316.     clockArray[1] = tm.Minute;
  317.     clockArray[2] = tm.Second;
  318.     dateArray[0] = tm.Day;
  319.     dateArray[1] = tm.Month;
  320.     dateArray[2] = tmYearToCalendar(tm.Year);
  321.     dateArray[3]  = tm.Wday;
  322.  
  323.  
  324.     // update battery stuff
  325.     batteryVoltage = getBatteryVoltage();
  326.     batteryPercentage = ((batteryVoltage - 3)/1.2)*100; // Gives a percentage range between 4.2 and 3 volts
  327.     isCharging = !digitalRead(CHARGING_STATUS_PIN);
  328.  
  329.     if((isCharging != prevIsCharging)){
  330.       if(started){ //flag to find if its the start or the end of a charge
  331.         isCharged = true;
  332.         started = false;
  333.       } else {
  334.         started = true;
  335.       }
  336.       prevIsCharging = isCharging;
  337.     } else if(batteryPercentage <= 95 && isCharged){ //reset the charged flag
  338.       isCharged = false;
  339.     }
  340.  
  341.     //make sure we never display a negative percentage
  342.     if(batteryPercentage < 0){
  343.       batteryPercentage = 0;
  344.     } else if(batteryPercentage > 100){
  345.       batteryPercentage = 100;
  346.     }
  347.  
  348.     //check if we have space for new notifications
  349.     if(notificationIndex < (notificationMax - 4) && !wantNotifications){
  350.       //Serial.println("Ready to receive notifications.");
  351.       HWSERIAL.print("<n>");
  352.       wantNotifications = true;
  353.     }
  354.  
  355.     //loading screen counter
  356.     if(loading > 0){
  357.       loading--;
  358.     }
  359.  
  360.     //timer countdown algorithm
  361.     if(isRunning){
  362.       if(timerArray[2] > 0){
  363.         timerArray[2]--;
  364.       } else {
  365.         if(timerArray[1] > 0){
  366.           timerArray[1]--;
  367.           timerArray[2] = 59;
  368.         } else {
  369.           if(timerArray[0] > 0){
  370.             timerArray[0]--;
  371.             timerArray[1] = 59;
  372.             timerArray[2] = 59;
  373.           } else {
  374.             isRunning = false;
  375.             createAlert("Timer Finished!",15,5);
  376.           }
  377.         }
  378.       }
  379.     }
  380.  
  381.     if(shutDownCounter > 0){
  382.       shutDownCounter--;
  383.     } else if(shutDownCounter == 0) {
  384.       shutdown = true;
  385.     }
  386.  
  387.     //check and prepare for shutdown
  388.     if(shutdown){
  389.       if(readyForShutdown){
  390.         Serial.println("Shutting down...");
  391.         shutDown();
  392.         //shutdown = false;
  393.         //readyForShutdown = false;
  394.       } else {
  395.         Serial.println("Shut down called, blanking display...");
  396.         readyForShutdown = true;
  397.       }
  398.     }
  399.  
  400.     /*Serial.println(F("=============================================="));
  401.     if(isConnected){
  402.       connectedTime++;
  403.       Serial.print(F("Connected for "));
  404.       Serial.print(connectedTime);
  405.       Serial.println(F(" seconds."));
  406.     } else {
  407.       Serial.print(F("Connected Status: "));
  408.       Serial.println(isConnected);
  409.       connectedTime = 0;
  410.     }
  411.  
  412.     Serial.print("Battery Level: ");
  413.     Serial.print(batteryPercentage);
  414.     Serial.println("%");
  415.  
  416.  
  417.     Serial.print("Battery Status: ");
  418.     if(isCharged){
  419.       Serial.println("Fully charged");
  420.     } else if(isCharging){
  421.       Serial.println("Charging");
  422.     } else {
  423.       Serial.println("Running down");
  424.     }
  425.  
  426.     Serial.print(F("Number of Notifications: "));
  427.     Serial.println(notificationIndex);
  428.     Serial.print(F("Time: "));
  429.     Serial.print(clockArray[0]);
  430.     Serial.print(F(":"));
  431.     Serial.print(clockArray[1]);
  432.     Serial.print(F(":"));
  433.     Serial.print(clockArray[2]);
  434.     Serial.print(F("    Date: "));
  435.     Serial.print(dateArray[0]);
  436.     Serial.print(F("/"));
  437.     Serial.print(dateArray[1]);
  438.     Serial.print(F("/"));
  439.     Serial.println(dateArray[2]);
  440.  
  441.     Serial.print(F("Free RAM:"));
  442.     Serial.println(FreeRam());
  443.     Serial.println(F("=============================================="));
  444.  
  445.     */
  446.  
  447.     //Alarm checks
  448.     if(activeAlarms[0]){
  449.       if(RTC.alarm(ALARM_1)){
  450.         createAlert("ALARM1",6,10);
  451.         Serial.println("ALARM 1 HAD GONE OFF");
  452.         activeAlarms[0] = false;
  453.         saveToEEPROM(ALARM_ADDRESS,activeAlarms[0]);
  454.       }
  455.     }
  456.     if(activeAlarms[1]){
  457.       if(RTC.alarm(ALARM_2)){
  458.         createAlert("ALARM2",6,10);
  459.         Serial.println("ALARM 2 HAD GONE OFF");
  460.         activeAlarms[1] = false;
  461.         saveToEEPROM(ALARM_ADDRESS + 5,activeAlarms[1]);
  462.       }
  463.     }
  464.  
  465.  
  466.     HWSERIAL.print("<b>");
  467.     HWSERIAL.print(batteryPercentage);
  468.     HWSERIAL.print(",");
  469.     HWSERIAL.print(batteryVoltage);
  470.     HWSERIAL.print(",");
  471.     HWSERIAL.print(isCharging);
  472.   }
  473.  
  474.   if(((currentInterval - prevAlertMillis) >= 250) && alertVibrationCount > 0){ //quarter a second
  475.     prevAlertMillis = currentInterval;
  476.     vibrating = !vibrating;
  477.     alertVibrationCount--;
  478.     if(vibrating){
  479.       digitalWrite(VIBRATE_PIN, HIGH);
  480.     } else {
  481.       digitalWrite(VIBRATE_PIN, LOW);
  482.     }
  483.     if(alertVibrationCount == 0 && vibrating){ //make we don't leave it vibrating
  484.       vibrating = false;
  485.     }
  486.   }
  487. }
  488.  
  489. /*
  490. * Main Loop
  491. */
  492.  
  493. void loop(void) {                                                                                  
  494.   u8g_FirstPage(&u8g);
  495.   do {
  496.     if(loading > 0){ // make sure we dont miss the 0
  497.       u8g_DrawXBMP(&u8g,55,12,21,24,LOGO);
  498.       u8g_DrawStr(&u8g,42,55,"Loading...");
  499.     } else if(!shutdown){
  500.       switch(pageIndex){
  501.         case 0: homePage(clockArray[0],clockArray[1],clockArray[2]); break;
  502.         case 1: notificationMenuPage(); break;
  503.         case 2: notificationFullPage(menuSelector); break;
  504.         case 4: timerPage(); break;
  505.         case 5: settingsPage(); break;
  506.         case 6: alarmPage(); break;
  507.         case 7: shutDownPage(); break;
  508.         case 10: alertPage(); break;
  509.       }
  510.     }
  511.   } while( u8g_NextPage(&u8g) );
  512.     handleInput();
  513.     while(HWSERIAL.available()){
  514.       message[messageIndex] = char(HWSERIAL.read());//store char from serial command
  515.       messageIndex++;
  516.       if(messageIndex >= 99){
  517.         //this message is too big something went wrong flush the message out the system and break the loop
  518.         Serial.println(F("Error message overflow, flushing buffer and discarding message."));
  519.         messageIndex = 0;
  520.         memset(message, 0, sizeof(message)); //resetting array
  521.         HWSERIAL.flush();
  522.         break;
  523.       }
  524.       delay(1);
  525.   }
  526.   if(!HWSERIAL.available()){
  527.     if(messageIndex > 0){
  528.       Serial.print(F("Message: "));
  529.       for(short i=0; i < messageIndex; i++){
  530.         Serial.print(message[i]);
  531.       }
  532.       Serial.println();
  533.  
  534.  
  535.       if(startsWith(message,"OK",2)){
  536.           if(startsWith(message,"OK+C",4)){
  537.             isConnected = true;
  538.             Serial.println(F("Connected!"));
  539.           } else if(startsWith(message,"OK+L",4)){
  540.             isConnected = false;
  541.             Serial.println(F("Disconnected!"));
  542.             //reset vars like got updated time and weather here also
  543.           } else {
  544.             //the message was broken and we have no way of knowing if we connected or not so just send the disconnect and try again manually
  545.             Serial.println(F("Error connecting, retry."));
  546.             HWSERIAL.print("AT");
  547.           }
  548.           messageIndex = 0;
  549.           memset(message, 0, sizeof(message));
  550.         }
  551.       if(!receiving && startsWith(message,"<",1)){
  552.         receiving = true;
  553.       }else if(receiving && (message=="<n>" || message=="<d>" || message=="<w>")) {
  554.         Serial.println(F("Message data missing, ignoring."));
  555.         //we never recieved the end tag of a previous message
  556.         //reset vars
  557.         messageIndex = 0;
  558.         memset(message, 0, sizeof(message));
  559.         resetTransmissionVariables();
  560.       }else if((messageIndex < 2) && receiving){//doesn't contain a full tag and we are receiving
  561.         //store this message and combine the next one and check if it equals <f>
  562.         if(!checkingTag){
  563.           for(short j = 0; j < messageIndex; j++){
  564.             messageBuffer[j] = message[j];
  565.           }
  566.           checkingTag = true;
  567.         } else {
  568.           short currentAmount = sizeof(messageBuffer);
  569.           if((currentAmount + (messageIndex + 1)) == 3){ //make sure it's a tag and it doesnt exceed the array index
  570.             //we have found a tag
  571.             for(short k = (currentAmount - 1); k < (3 - (messageIndex + 1)); k++){
  572.                 messageBuffer[k] = message[k];
  573.             }
  574.             //if its an <f> then we finish else we carry on
  575.             if(startsWith(messageBuffer,"<f>",3)){
  576.               Serial.println("We Found a finish tag that got corrupted!");
  577.               // make ready to process true cuz were done
  578.               readyToProcess = true;
  579.             }
  580.             //reset checkingTag flag
  581.             checkingTag = false;
  582.             //reset array
  583.             memset(messageBuffer,0,sizeof(messageBuffer));
  584.           }
  585.         }
  586.       }
  587.       if(!startsWith(message,"<f>",3)){
  588.         if(startsWith(message,"<i>",3)){
  589.           // move pointer on to remove out first 3 chars
  590.           messagePtr += 3;
  591.           while(*messagePtr != '\0'){ //'\0' is the end of string character. when we recieve things in serial we need to add this at the end
  592.             finalData[finalDataIndex] = *messagePtr; // *messagePtr derefereces the pointer so it points to the data
  593.             messagePtr++; // this increased the ptr location in this case by one, if it were an short array it would be by 4 to get the next element
  594.             finalDataIndex++;
  595.           }
  596.           //reset the messagePtr once done
  597.           messagePtr = message;
  598.         } else {
  599.           if(!((finalDataIndex+messageIndex) >= 249)){ //check the data will fit short he char array
  600.             for(short i=0; i < messageIndex; i++){
  601.               finalData[finalDataIndex] = message[i];
  602.               finalDataIndex++;
  603.             }
  604.           } else {
  605.             Serial.println(F("FinalData is full, but there was more data to add. Discarding data."));
  606.             messageIndex = 0;
  607.             memset(message, 0, sizeof(message));
  608.             resetTransmissionVariables();
  609.           }
  610.         }
  611.       } else {
  612.         receiving = false;
  613.         readyToProcess = true;
  614.       }
  615.       //reset index
  616.       messageIndex = 0;
  617.       memset(message, 0, sizeof(message)); // clears array
  618.     }
  619.   }
  620.  
  621.   if(readyToProcess){
  622.     Serial.print(F("Received: "));
  623.     Serial.println(finalData);
  624.     if(startsWith(finalData,"<n>",3)){
  625.       if(notificationIndex < (notificationMax - 1)){ // 0-7 == 8
  626.         getNotification(finalData,finalDataIndex);
  627.         vibrate(2); //vibrate
  628.         if(notificationIndex > (notificationMax - 2)){ //tell the app we are out of space and hold the notifications
  629.           HWSERIAL.print("<e>");
  630.           wantNotifications = false;
  631.         }
  632.       } else {
  633.         Serial.println(F("Max notifications Hit."));
  634.       }
  635.     } else if(startsWith(finalData,"<w>",3)){
  636.       getWeatherData(finalData,finalDataIndex);
  637.     } else if(startsWith(finalData,"<d>",3)){
  638.       getTimeFromDevice(finalData,finalDataIndex);
  639.     }
  640.     resetTransmissionVariables();
  641.   }
  642.   // update the system
  643.   updateSystem();
  644.  
  645.   // service the COP // if we don't update this the wacthdog will reset our teensy (For hangs and crashes)
  646.   //SIM_SRVCOP = 0x55;
  647.   //SIM_SRVCOP = 0xAA;
  648. }
  649.  
  650. /*
  651. * Page Methods
  652. */
  653.  
  654. void alarmPage(){
  655.   u8g_DrawStr(&u8g, 24,23,"H");
  656.   u8g_DrawStr(&u8g, 54,23,"M");
  657.   u8g_DrawStr(&u8g, 84,23,"D");
  658.  
  659.   intTo2Chars(alarmTime[0]);
  660.   u8g_DrawStr(&u8g, 24,35,numberBuffer);
  661.   intTo2Chars(alarmTime[1]);
  662.   u8g_DrawStr(&u8g, 54,35,numberBuffer);
  663.   //draw day of week set up to a week in advance
  664.   short dayAhead = dateArray[3] - 1; //set current day
  665.   for(short i = 0; i < alarmTime[2]; i++){ // add the exra days
  666.     dayAhead++;
  667.     if(dayAhead > 6){
  668.       dayAhead = 0;
  669.     }
  670.   }
  671.  
  672.   //check if alarms are active
  673.   if(alarmToggle!=prevAlarmToggle){
  674.     for(short k = 0; k < 2; k++){
  675.       alarmTime[k] = 0;
  676.     }
  677.     short address = 0;
  678.     if(alarmToggle == 0 && activeAlarms[alarmToggle]){
  679.       address = ALARM_ADDRESS + 1;
  680.     } else if(alarmToggle == 1 && activeAlarms[alarmToggle]) {
  681.       address = ALARM_ADDRESS + 5;
  682.     }
  683.     alarmTime[0] = readFromEEPROM(address);
  684.     address++;
  685.     alarmTime[1] = readFromEEPROM(address);
  686.     address++;
  687.     short date = readFromEEPROM(address);
  688.     address++;
  689.     short monthSet = readFromEEPROM(address);
  690.     if(date == dateArray[0]){
  691.       alarmTime[2] = 0;
  692.     } else {
  693.       alarmTime[2] = (date + dayInMonth[monthSet - 1]) - dateArray[0];
  694.     }
  695.     prevAlarmToggle = alarmToggle;
  696.   }
  697.  
  698.   u8g_DrawStr(&u8g, 84,35,days[dayAhead].c_str());
  699.  
  700.   if(alarmToggle == 0){
  701.     u8g_DrawStr(&u8g, 0,0 + FONT_HEIGHT,"One");
  702.   } else {
  703.     u8g_DrawStr(&u8g, 0,0 + FONT_HEIGHT,"Two");
  704.   }
  705.  
  706.  
  707.   if(!activeAlarms[alarmToggle]){
  708.     u8g_DrawStr(&u8g, 34,54,"Set");
  709.   } else {
  710.     u8g_DrawStr(&u8g, 30,54,"Unset");
  711.   }
  712.  
  713.   u8g_DrawStr(&u8g, 70,54,"Swap");
  714.  
  715.  
  716.   drawSelectors(alarmIndex);
  717. }
  718.  
  719. void shutDownPage(){
  720.   u8g_SetFont(&u8g, u8g_font_6x12);
  721.   u8g_DrawStr(&u8g,25,1 + FONT_HEIGHT,"Shutting Down");
  722.   u8g_DrawStr(&u8g,30,14 + FONT_HEIGHT,"in");
  723.   intTo2Chars(shutDownCounter);
  724.   u8g_DrawStr(&u8g,45,14 + FONT_HEIGHT,numberBuffer);
  725.   u8g_DrawStr(&u8g,60,14 + FONT_HEIGHT,"seconds");
  726.   u8g_DrawStr(&u8g,10,35 + FONT_HEIGHT,"Press OK to cancel!");
  727. }
  728.  
  729. void timerPage(){
  730.   u8g_DrawStr(&u8g, 24,23,"H");
  731.   u8g_DrawStr(&u8g, 54,23,"M");
  732.   u8g_DrawStr(&u8g, 84,23,"S");
  733.  
  734.   intTo2Chars(timerArray[0]);
  735.   u8g_DrawStr(&u8g, 24,35,numberBuffer);
  736.   intTo2Chars(timerArray[1]);
  737.   u8g_DrawStr(&u8g, 54,35,numberBuffer);
  738.   intTo2Chars(timerArray[2]);
  739.   u8g_DrawStr(&u8g, 84,35,numberBuffer);
  740.  
  741.   drawSelectors(timerIndex);
  742.  
  743.   if(isRunning){
  744.     u8g_DrawStr(&u8g, 30,54,"Stop");
  745.   } else {
  746.     u8g_DrawStr(&u8g, 30,54,"Start");
  747.   }
  748.  
  749.   u8g_DrawStr(&u8g, 70,54,"Reset");
  750.  
  751.  
  752. }
  753.  
  754. void drawSelectors(short index){
  755.   if(locked){
  756.     switch (index) {
  757.       case 0: drawTriangle(22,10,8,2); drawTriangle(22,38,8,1); break;
  758.       case 1: drawTriangle(52,10,8,2); drawTriangle(52,38,8,1); break;
  759.       case 2: drawTriangle(82,10,8,2); drawTriangle(82,38,8,1); break;
  760.     }
  761.   } else {
  762.     switch (index) {
  763.       case 0: drawTriangle(22,8,8,1); break;
  764.       case 1: drawTriangle(52,8,8,1);break;
  765.       case 2: drawTriangle(82,8,8,1); break;
  766.       case 3: u8g_DrawFrame(&u8g,28,45,34,13); break; //draw rectangle around this option
  767.       case 4: u8g_DrawFrame(&u8g,68,45,34,13); break; //draw rectangle around this option
  768.     }
  769.   }
  770. }
  771.  
  772. void alertPage(){
  773.   u8g_SetFont(&u8g, u8g_font_6x12);
  774.   short xOffset = (alertTextLen * 6)/2;
  775.   u8g_DrawStr(&u8g,64 - xOffset, 32,alertText);
  776.   u8g_DrawStr(&u8g,64 - 60, 50,"Press OK to dismiss.");
  777.   //remeber to add vibrate if needed
  778. }
  779.  
  780. void notificationMenuPage(){
  781.   if(shouldRemove){
  782.     //remove the notification once read
  783.     removeNotification(menuSelector);
  784.     shouldRemove = false;
  785.     //menuSelector = 0; //dont put it back to zero as when new message com in the order will get screwed
  786.   }
  787.   if(notificationIndex == 0){
  788.     u8g_DrawStr(&u8g,30,32,"No Messages.");
  789.   }
  790.   showMenu(notificationIndex, notificationMenuPageItem,true);
  791. }
  792.  
  793. void settingsPage(){
  794.   bool showCursor = true;
  795.   if(locked){
  796.     showCursor = false;
  797.   }
  798.   showMenu(numberOfSettings,settingsMenuItem,showCursor);
  799. }
  800.  
  801. void notificationMenuPageItem(short position){
  802.   //draw title
  803.   u8g_DrawStr(&u8g,x+3,y+Y_OFFSET+FONT_HEIGHT,notifications[position].title);
  804.  
  805.   u8g_SetFont(&u8g, u8g_font_04b_03);
  806.   { //draw timestamp
  807.     intTo2Chars(notifications[position].dateReceived[0]);
  808.     u8g_DrawStr(&u8g,x+95,y + Y_OFFSET + FONT_HEIGHT,numberBuffer);
  809.     u8g_DrawStr(&u8g,x+103,y + Y_OFFSET + FONT_HEIGHT,":");
  810.     intTo2Chars(notifications[position].dateReceived[1]);
  811.     u8g_DrawStr(&u8g,x+106,y + Y_OFFSET + FONT_HEIGHT,numberBuffer);
  812.   }
  813.   u8g_SetFont(&u8g, u8g_font_6x12);
  814. }
  815.  
  816. void settingsMenuItem(short position){
  817.   u8g_DrawStr(&u8g,x+3,y+Y_OFFSET+FONT_HEIGHT,settingKey[position].c_str());
  818.   u8g_DrawStr(&u8g,x+3 + 104,y+Y_OFFSET+FONT_HEIGHT,itoa(settingValue[position],numberBuffer,10));
  819. }
  820.  
  821.  
  822. void notificationFullPage(short chosenNotification){
  823.   short lines = 0;
  824.   charIndex = 0; //make sure we rest index
  825.  
  826.   short textLength = notifications[chosenNotification].textLength;
  827.  
  828.   if(textLength > charsThatFit){
  829.     for(short i=0; i < textLength; i++){
  830.       if((charIndex >= charsThatFit) || i == (textLength - 1)){ // i == textLength so we catch what we ahve of a line if we dont have a complete line
  831.         lineBuffer[charIndex] = notifications[chosenNotification].text[i]; //catch the last char
  832.         u8g_DrawStr(&u8g,0,lines * 10 + FONT_HEIGHT + Y_OFFSET, lineBuffer); //draw the line
  833.         lines++;
  834.         charIndex = 0;
  835.         memset(lineBuffer,0,sizeof(lineBuffer)); //reset the buffer we only do this because if a line is not 20 chars long the previos lines chars will be displayed
  836.       } else {
  837.         lineBuffer[charIndex] = notifications[chosenNotification].text[i];
  838.         charIndex++;
  839.       }
  840.     }
  841.   } else {
  842.     u8g_DrawStr(&u8g,0,FONT_HEIGHT,notifications[chosenNotification].text);
  843.     lines++;
  844.   }
  845.   lineCount = (lines); //- 1);
  846.   intTo2Chars(lineCount);
  847.   u8g_DrawStr(&u8g,64,50 + FONT_HEIGHT,numberBuffer);
  848.   u8g_DrawStr(&u8g, 30, 50, String(textLength).c_str());
  849. }
  850.  
  851. void homePage(short hour, short minute,short second){
  852.   u8g_DrawCircle(&u8g,32,32,30,U8G_DRAW_ALL);
  853.   u8g_DrawCircle(&u8g,32,32,29,U8G_DRAW_ALL);
  854.   u8g_DrawStr(&u8g,59-32,2+ FONT_HEIGHT,"12");
  855.   u8g_DrawStr(&u8g,59-32 + 3,45+ FONT_HEIGHT,"6");
  856.   u8g_DrawStr(&u8g,7,32 + 3,"9");
  857.   u8g_DrawStr(&u8g,53,32   + 3,"3");
  858.  
  859.   if(clockArray[0] > 12){
  860.     u8g_DrawStr(&u8g,0,64,"PM");
  861.   } else {
  862.     u8g_DrawStr(&u8g,0,64,"AM");
  863.   }
  864.  
  865.  
  866.   float hours = (((hour * 30) + ((minute/2))) * (PI/180));
  867.   short x2 = 32 + (sin(hours) * (clockRadius/2));
  868.   short y2 = 32 - (cos(hours) * (clockRadius/2));
  869.   u8g_DrawLine(&u8g,32,32,x2,y2); //hour hand
  870.  
  871.   float minutes = ((minute * 6) * (PI/180));
  872.   short xx2 = 32 + (sin(minutes) * (clockRadius/1.4));
  873.   short yy2 = 32 - (cos(minutes) * (clockRadius/1.4));
  874.   u8g_DrawLine(&u8g,32,32,xx2,yy2);//minute hand
  875.  
  876.   float seconds = ((second * 6) * (PI/180));
  877.   short xxx2 = 32 + (sin(seconds) * (clockRadius/1.3));
  878.   short yyy2 = 32 - (cos(seconds) * (clockRadius/1.3));
  879.   u8g_DrawLine(&u8g,32,32,xxx2,yyy2);//second hand
  880.  
  881.   if(settingValue[1] == 1){
  882.     numberOfWidgets = numberOfNormalWidgets + numberOfDebugWidgets;
  883.   } else {
  884.     numberOfWidgets = numberOfNormalWidgets;
  885.   }
  886.  
  887.   switch(widgetSelector){
  888.     case 0: timeDateWidget(); break;
  889.     case 1: digitalClockWidget(); break;
  890.     case 2: weatherWidget(); break;
  891.     case 3: u8g_SetFont(&u8g, u8g_font_7x14); u8g_DrawStr(&u8g,70,39 + 3,"Messages"); u8g_SetFont(&u8g, u8g_font_6x12); break;
  892.     case 4: u8g_SetFont(&u8g, u8g_font_7x14); u8g_DrawStr(&u8g,80,39 + 3,"Timer"); u8g_SetFont(&u8g, u8g_font_6x12); break;
  893.     case 5: u8g_SetFont(&u8g, u8g_font_7x14); u8g_DrawStr(&u8g,75,42 + 3,"Alarms"); u8g_SetFont(&u8g, u8g_font_6x12); break;
  894.     case 6: u8g_SetFont(&u8g, u8g_font_7x14); u8g_DrawStr(&u8g,70,39 + 3,"Settings"); u8g_SetFont(&u8g, u8g_font_6x12); break;
  895.     case 7: u8g_SetFont(&u8g, u8g_font_6x12); u8g_DrawStr(&u8g,73,42 + 3,"Reset"); u8g_DrawXBMP(&u8g,110,36,8,10,BLUETOOTH_CONNECTED); break;
  896.     case 8: u8g_SetFont(&u8g, u8g_font_6x12); u8g_DrawStr(&u8g,75,42 + 3,"Shut down"); break;
  897.   }
  898.  
  899.   //status bar - 15 px high for future icon ref
  900.   u8g_DrawFrame(&u8g,75,0,53,15);
  901.   //separator line between notifications and bt icon on the status bar
  902.   u8g_DrawLine(&u8g,116,0,116,14);
  903.   //batt voltage and connection separator
  904.   u8g_DrawLine(&u8g,97,0,97,14);
  905.  
  906.   //notification indicator
  907.  
  908.   u8g_DrawStr(&u8g,119,-1 + FONT_HEIGHT,itoa(notificationIndex,numberBuffer,10));
  909.  
  910.   //battery voltage
  911.   if(!isCharging && !isCharged){
  912.     if(batteryPercentage != 100){
  913.       u8g_DrawStr(&u8g,77,11,itoa(batteryPercentage,numberBuffer,10));
  914.       u8g_DrawStr(&u8g,89,11,"%");
  915.     }
  916.   } else if(isCharged){
  917.     //fully charged symbol here
  918.     u8g_DrawXBMP(&u8g,79,1,14,12,CHARGED);
  919.   } else {
  920.     //draw symbol to show that we are charging here
  921.     u8g_DrawXBMP(&u8g,80,2,14,12,CHARGING);
  922.   }
  923.  
  924.   //connection icon
  925.   if(isConnected){
  926.     u8g_DrawXBMP(&u8g,102,2,8,10,BLUETOOTH_CONNECTED);
  927.   } else {
  928.     u8g_DrawStr(&u8g,102,11,"NC");
  929.   }
  930. }
  931.  
  932. /*
  933. * Home page widgets
  934. */
  935.  
  936. void timeDateWidget(){
  937.   //display date from RTC
  938.   u8g_SetFont(&u8g, u8g_font_7x14);
  939.   u8g_DrawStr(&u8g,72,20+14,days[dateArray[3] - 1].c_str());
  940.   intTo2Chars(dateArray[0]);
  941.   u8g_DrawStr(&u8g,72,34+14,numberBuffer);
  942.   u8g_DrawStr(&u8g,90,34+14,months[dateArray[1] - 1].c_str());
  943.   intTo2Chars(dateArray[2]);
  944.   u8g_DrawStr(&u8g,72,48+14,numberBuffer);
  945.   u8g_SetFont(&u8g, u8g_font_6x12);
  946. }
  947.  
  948. void digitalClockWidget(){
  949.   u8g_SetFont(&u8g, u8g_font_7x14);
  950.   u8g_DrawFrame(&u8g,68,28,60,16);
  951.   intTo2Chars(clockArray[0]);
  952.   u8g_DrawStr(&u8g,69,28+14,numberBuffer);
  953.   u8g_DrawStr(&u8g,83,28+14,":");
  954.   intTo2Chars(clockArray[1]);
  955.   u8g_DrawStr(&u8g,91,28+14,numberBuffer);
  956.   u8g_DrawStr(&u8g,105,28+14,":");
  957.   intTo2Chars(clockArray[2]);
  958.   u8g_DrawStr(&u8g,113,28+14,numberBuffer);
  959.   u8g_SetFont(&u8g, u8g_font_6x12);
  960. }
  961.  
  962. void weatherWidget(){
  963.   if(weatherData){
  964.     //change fonts
  965.     u8g_SetFont(&u8g, u8g_font_7x14);
  966.     u8g_DrawStr(&u8g,72,19+FONT_HEIGHT,weatherDay);
  967.  
  968.     u8g_SetFont(&u8g, u8g_font_04b_03);
  969.     intTo2Chars(timeWeGotWeather[0]);
  970.     u8g_DrawStr(&u8g,105,15+ FONT_HEIGHT,numberBuffer);
  971.     u8g_DrawStr(&u8g,113,15+ FONT_HEIGHT,":");
  972.     intTo2Chars(timeWeGotWeather[1]);
  973.     u8g_DrawStr(&u8g,116,15+ FONT_HEIGHT,numberBuffer);
  974.  
  975.     u8g_SetFont(&u8g, u8g_font_6x12);
  976.  
  977.     u8g_DrawStr(&u8g,72,28+FONT_HEIGHT,weatherTemperature);
  978.     u8g_DrawStr(&u8g,102,28+FONT_HEIGHT,"C");
  979.  
  980.     short index = 0;
  981.     charIndex = 0;
  982.     if(contains(weatherForecast,' ',sizeof(weatherForecast))){
  983.       for(short i=0; i < sizeof(weatherForecast); i++){
  984.         if(weatherForecast[i]==' ' || weatherForecast[i] == 0){ // == 0  find the end of the data
  985.           u8g_DrawStr(&u8g,72,(38+FONT_HEIGHT) + (index * 10),lineBuffer);//draw it
  986.           index++;
  987.           charIndex = 0; //reset index for next line
  988.           memset(lineBuffer,0,sizeof(lineBuffer));//reset buffer
  989.           if(index == 3){ //after 2 lines break
  990.             break;
  991.           }
  992.         } else {
  993.           lineBuffer[charIndex] = weatherForecast[i]; //fill buffer
  994.           charIndex++;
  995.         }
  996.       }
  997.     } else {
  998.       u8g_DrawStr(&u8g,72,38+FONT_HEIGHT,weatherForecast);
  999.     }
  1000.  
  1001.  
  1002.   } else {
  1003.     //print that weather is not available
  1004.     u8g_SetFont(&u8g, u8g_font_7x14);
  1005.     u8g_DrawStr(&u8g,70,34 + 3,"Weather");
  1006.     u8g_DrawStr(&u8g,70,50 + 3,"Data N/A");
  1007.     u8g_SetFont(&u8g, u8g_font_6x12);
  1008.   }
  1009. }
  1010.  
  1011. /*
  1012. * Input handling methods
  1013. */
  1014.  
  1015. void handleInput(){
  1016.   short  vector = getConfirmedInputVector();
  1017.     if(vector!=lastVector){
  1018.       if (vector == UP_DOWN){
  1019.         Serial.println(F("Dual click detected!"));
  1020.         handleDualClick();
  1021.       } else if (vector == UP_ONLY){
  1022.         handleUpInput();
  1023.       } else if(vector == DOWN_ONLY){
  1024.         handleDownInput();
  1025.       } else if(vector == OK_ONLY){
  1026.         handleOkInput();
  1027.       } else if(vector == ALL_THREE){
  1028.         Serial.println(F("Return to menu Combo"));
  1029.         pageIndex = HOME_PAGE; // take us back to the home page
  1030.         widgetSelector = settingValue[0];// and our fav widget
  1031.       }
  1032.       prevButtonPressed = millis();
  1033.       //idle = false;
  1034.     }
  1035.       if(vector == NONE_OF_THEM){
  1036.         if(((millis() - prevButtonPressed) > INPUT_TIME_OUT) && (prevButtonPressed != 0)){
  1037.           Serial.println(F("Time out input"));
  1038.           prevButtonPressed = 0;
  1039.           pageIndex = HOME_PAGE; // take us back to the home page
  1040.           widgetSelector = settingValue[0]; //and our fav widget
  1041.           Y_OFFSET = 0;// reset the Y_OFFSET so if we come off a page with an offset it doesnt get bugged
  1042.           currentLine = 0;
  1043.           //idle = true;
  1044.         }
  1045.       }
  1046.     lastVector = vector;
  1047. }
  1048.  
  1049. void handleDualClick(){
  1050.     pageIndex = HOME_PAGE;
  1051. }
  1052.  
  1053. void handleUpInput(){
  1054.   Serial.println(F("Increase Click Detected"));
  1055.   if(pageIndex == HOME_PAGE){
  1056.     widgetSelector++;
  1057.     if(widgetSelector > numberOfWidgets){
  1058.       widgetSelector = 0;
  1059.     }
  1060.   } else if(pageIndex == NOTIFICATION_MENU){
  1061.     menuUp(notificationIndex);
  1062.   } else if(pageIndex == NOTIFICATION_BIG){
  1063.     if( (lineCount - currentLine) >= 6){
  1064.     //this scrolls down
  1065.     Y_OFFSET -= FONT_HEIGHT;
  1066.     currentLine++;
  1067.   }
  1068.   } else if(pageIndex == TIMER){
  1069.     if(locked){
  1070.       timerArray[timerIndex]++;
  1071.     } else {
  1072.       timerIndex++;
  1073.       if(timerIndex > 4){
  1074.         timerIndex = 0;
  1075.       }
  1076.     }
  1077.   } else if(pageIndex == SETTINGS){
  1078.     //check if were locked first (changing value)
  1079.     if(locked){
  1080.       settingValue[menuSelector]++;
  1081.       if(settingValue[menuSelector] > settingValueMax[menuSelector]){
  1082.         settingValue[menuSelector] = settingValueMax[menuSelector];;
  1083.       }
  1084.     } else {
  1085.       menuUp(numberOfSettings);
  1086.     }
  1087.   } else if(pageIndex == ALARM_PAGE){
  1088.     if(locked){
  1089.       alarmTime[alarmIndex]++;
  1090.       if(alarmTime[alarmIndex] > alarmMaxValues[alarmIndex]){
  1091.         alarmTime[alarmIndex] = alarmMaxValues[alarmIndex];
  1092.       }
  1093.     } else {
  1094.       alarmIndex++;
  1095.       if(alarmIndex > 4){
  1096.         alarmIndex = 0; // 3 is max
  1097.       }
  1098.     }
  1099.   } else {
  1100.     Serial.println(F("Unknown Page."));
  1101.   }
  1102. }
  1103.  
  1104. void menuUp(short size){
  1105.   menuSelector++;
  1106.   //check here if we need scroll up to get the next items on the screen//check here if we nmeed to scroll down to get the next items
  1107.   if((menuSelector >= 4) && (((size + 1) - menuSelector) > 0)){//0,1,2,3 = 4 items
  1108.     //shift the y down
  1109.     Y_OFFSET -= MENU_ITEM_HEIGHT;
  1110.   }
  1111.   if(menuSelector >= size){
  1112.      //menuSelector = 0;
  1113.      menuSelector = size;
  1114.   }
  1115. }
  1116.  
  1117. void menuDown(){
  1118.   menuSelector--;
  1119.   if(menuSelector < 0){
  1120.      menuSelector = 0;
  1121.      //menuSelector = notificationIndex + 1;
  1122.   }
  1123.   //plus y
  1124.   if((menuSelector >= 3)){
  1125.     Y_OFFSET += MENU_ITEM_HEIGHT;
  1126.   }
  1127. }
  1128.  
  1129. void handleDownInput(){
  1130.   Serial.println(F("Decrease Click Detected"));
  1131.   if(pageIndex == HOME_PAGE){
  1132.     widgetSelector--;
  1133.     if(widgetSelector < 0){
  1134.       widgetSelector = numberOfWidgets;
  1135.     }
  1136.   } else if(pageIndex == NOTIFICATION_MENU){
  1137.     menuDown();
  1138.   } else if(pageIndex == NOTIFICATION_BIG){
  1139.     if(currentLine > 0){
  1140.     //scrolls back up
  1141.     Y_OFFSET += FONT_HEIGHT;
  1142.     currentLine--;
  1143.   }
  1144.   } else if(pageIndex == TIMER){
  1145.     if(locked){
  1146.       timerArray[timerIndex]--;
  1147.       if(timerArray[timerIndex] < 0){
  1148.         timerArray[timerIndex] = 0;
  1149.       }
  1150.     } else {
  1151.       timerIndex--;
  1152.       if(timerIndex < 0){
  1153.         timerIndex = 4;
  1154.       }
  1155.     }
  1156.   } else if(pageIndex == SETTINGS){
  1157.     if(locked){
  1158.       settingValue[menuSelector]--;
  1159.       if(settingValue[menuSelector] < settingValueMin[menuSelector]){
  1160.         settingValue[menuSelector] = settingValueMin[menuSelector];
  1161.       }
  1162.     } else {
  1163.       menuDown();
  1164.     }
  1165.   } else if(pageIndex == ALARM_PAGE){
  1166.     if(locked){
  1167.       alarmTime[alarmIndex]--;
  1168.       if(alarmTime[alarmIndex] < 0){
  1169.         alarmTime[alarmIndex] = 0;
  1170.       }
  1171.     } else {
  1172.       alarmIndex--;
  1173.       if(alarmIndex < 0){
  1174.         alarmIndex = 4; // 3 is max
  1175.       }
  1176.     }
  1177.   } else {
  1178.     Serial.println(F("Unknown Page."));
  1179.   }
  1180. }
  1181.  
  1182. void handleOkInput(){
  1183.   if(pageIndex == HOME_PAGE){
  1184.     if(widgetSelector == 3){
  1185.       pageIndex = NOTIFICATION_MENU;
  1186.     } else if(widgetSelector == 4){
  1187.       pageIndex = TIMER;
  1188.     } else if(widgetSelector == 5){
  1189.       pageIndex = ALARM_PAGE;
  1190.     } else if(widgetSelector == 6){
  1191.       pageIndex = SETTINGS;
  1192.     } else if(widgetSelector == 7){
  1193.       resetBTModule();
  1194.     } else if(widgetSelector == 8){
  1195.       shutDownCounter = 10; // 5 seconds to decide
  1196.       pageIndex = SHUTDOWN;
  1197.     }
  1198.     Y_OFFSET = 0;
  1199.   } else if(pageIndex == NOTIFICATION_MENU){
  1200.     if(menuSelector != notificationIndex){//last one is the back item
  1201.       Y_OFFSET = 0;
  1202.       pageIndex = NOTIFICATION_BIG;
  1203.     } else {
  1204.       menuSelector = 0; //reset the selector
  1205.       pageIndex = HOME_PAGE;// go back to list of notifications
  1206.     }
  1207.   } else if(pageIndex == NOTIFICATION_BIG){
  1208.     shouldRemove = true;
  1209.     if(menuSelector > 3){
  1210.       Y_OFFSET = -1* (menuSelector - 3) * MENU_ITEM_HEIGHT; //return to place
  1211.     } else {
  1212.       Y_OFFSET = 0;
  1213.     }
  1214.     lineCount = 0;//reset number of lines
  1215.     currentLine = 0;// reset currentLine back to zero
  1216.     pageIndex = NOTIFICATION_MENU;
  1217.   } else if(pageIndex == TIMER){
  1218.     if(timerIndex==3){
  1219.       isRunning = !isRunning; //start/stop timer
  1220.     } else if(timerIndex == 4){
  1221.       Serial.println(F("Resetting timer."));
  1222.       isRunning = false;
  1223.       timerArray[0] = 0;
  1224.       timerArray[1] = 0;
  1225.       timerArray[2] = 0;
  1226.     }else {
  1227.       locked = !locked; //lock or unlock into a digit so we can manipulate it
  1228.     }
  1229.   } else if(pageIndex == SETTINGS){
  1230.     if(menuSelector==(numberOfSettings)){ //thisis the back button
  1231.       menuSelector = 0;
  1232.       pageIndex = HOME_PAGE;
  1233.       //dont reset the widgetIndex to give the illusion we just came from there
  1234.     } else {
  1235.       locked = !locked;
  1236.       if(!locked){
  1237.         saveToEEPROM(menuSelector,settingValue[menuSelector]);
  1238.       }
  1239.     }
  1240.   } else if(pageIndex == ALERT){
  1241.     memset(alertText,0,sizeof(alertText)); //reset the alertText
  1242.     alertTextLen = 0; //reset the index
  1243.     pageIndex = lastPage; //go back
  1244.   } else if(pageIndex == ALARM_PAGE){
  1245.     //handle alarmInput
  1246.     if(alarmIndex == 3){
  1247.       activeAlarms[alarmToggle] = !activeAlarms[alarmToggle];
  1248.       if(activeAlarms[alarmToggle]){
  1249.         if((dateArray[0] + alarmTime[2]) > dayInMonth[dateArray[1] - 1]){
  1250.           setAlarm(alarmToggle, alarmTime[0], alarmTime[1], ((dateArray[0] + alarmTime[2]) - dayInMonth[dateArray[1] - 1]),dateArray[1]); // (dateArray[0] + alarmTime[2]) == current date plus the days in advance we want to set the
  1251.           /*Serial.print("Alarm set for the : ");
  1252.           Serial.println(((dateArray[0] + alarmTime[2]) - dayInMonth[dateArray[1] - 1]));*/
  1253.         } else {
  1254.           setAlarm(alarmToggle, alarmTime[0], alarmTime[1], (dateArray[0] + alarmTime[2]),dateArray[1]);
  1255.           /*Serial.print("Alarm set for the : ");
  1256.           Serial.println((dateArray[0] + alarmTime[2]));*/
  1257.         }
  1258.  
  1259.       }
  1260.  
  1261.    } else if(alarmIndex == 4){
  1262.      if(alarmToggle == 0){
  1263.        alarmToggle = 1;
  1264.      } else {
  1265.        alarmToggle = 0;
  1266.      }
  1267.    } else {
  1268.      locked = !locked;
  1269.    }
  1270.   } else if(pageIndex == SHUTDOWN){
  1271.     shutDownCounter = -1;
  1272.     pageIndex = HOME_PAGE;
  1273.   } else {
  1274.     Serial.println(F("Unknown Page."));
  1275.   }
  1276. }
  1277.  
  1278. short getConfirmedInputVector()
  1279. {
  1280.   static short lastConfirmedVector = 0;
  1281.   static short lastVector = -1;
  1282.   static long unsigned int heldVector = 0L;
  1283.  
  1284.   // Combine the inputs.
  1285.   short rawVector =
  1286.     isButtonPressed(OK_BUTTON) << 2 |
  1287.     isButtonPressed(DOWN_BUTTON) << 1 |
  1288.     isButtonPressed(UP_BUTTON) << 0;
  1289.  
  1290.   /*Serial.print("Okay Button: ");
  1291.   Serial.println(touchRead(OK_BUTTON));
  1292.   Serial.print("Down Button: ");
  1293.   Serial.println(touchRead(DOWN_BUTTON));
  1294.   Serial.print("Up Button: ");
  1295.   Serial.println(touchRead(UP_BUTTON));*/
  1296.  
  1297.   // On a change in vector, don't return the new one!
  1298.   if (rawVector != lastVector)
  1299.   {
  1300.     heldVector = millis();
  1301.     lastVector = rawVector;
  1302.     return lastConfirmedVector;
  1303.   }
  1304.  
  1305.   // We only update the confirmed vector after it has
  1306.   // been held steady for long enough to rule out any
  1307.   // accidental/sloppy half-presses or electric bounces.
  1308.   //
  1309.   long unsigned heldTime = (millis() - heldVector);
  1310.   if (heldTime >= CONFIRMATION_TIME)
  1311.   {
  1312.     lastConfirmedVector = rawVector;
  1313.   }
  1314.  
  1315.   return lastConfirmedVector;
  1316. }
  1317.  
  1318. /*
  1319. * Data Proccessing methods.
  1320. */
  1321.  
  1322. void getWeatherData(char weatherItem[],short len){
  1323.   char *weaPtr = weatherItem;
  1324.   weaPtr+=3; //remove the tag
  1325.   short charIndex = 0;
  1326.   short index = 0;
  1327.   for(short i=0; i < len;i++){
  1328.     char c = *weaPtr; //derefence pointer to get value in char[]
  1329.     if(c=='<'){
  1330.       //split the t and more the next item
  1331.       weaPtr+=2;
  1332.       index++;
  1333.       charIndex = 0;
  1334.     } else {
  1335.       if(index==0){
  1336.         weatherDay[charIndex] = c;
  1337.         charIndex++;
  1338.       } else if(index==1){
  1339.         weatherTemperature[charIndex] = c;
  1340.         charIndex++;
  1341.       } else if(index==2){
  1342.         weatherForecast[charIndex] = c;
  1343.         charIndex++;
  1344.       }
  1345.     }
  1346.     weaPtr++; //move pointer along
  1347.   }
  1348.   /*Serial.print(F("Day: "));
  1349.   Serial.println(weatherDay);
  1350.   Serial.print(F("Temperature: "));
  1351.   Serial.println(weatherTemperature);
  1352.   Serial.print(F("Forecast: "));
  1353.   Serial.println(weatherForecast);*/
  1354.   for(short l=0; l < 2; l++){
  1355.     timeWeGotWeather[l] = clockArray[l];
  1356.   }
  1357.   weatherData = true;
  1358. }
  1359.  
  1360. void getNotification(char notificationItem[],short len){
  1361.   //split the <n>
  1362.   char *notPtr = notificationItem;
  1363.   notPtr+=3; //'removes' the first 3 characters
  1364.   short index = 0;
  1365.   short charIndex = 0;
  1366.   for(short i=0; i < len;i++){
  1367.     char c = *notPtr; //dereferences point to find value
  1368.     if(c=='<'){
  1369.       //split the i and more the next item
  1370.       notPtr+=2; // on two becuase this char is one
  1371.       index++;
  1372.       charIndex = 0;
  1373.     } else {
  1374.       if(index==0){
  1375.         notifications[notificationIndex].packageName[charIndex] = c;
  1376.         charIndex++;
  1377.       }else if(index==1){
  1378.         notifications[notificationIndex].title[charIndex] = c;
  1379.         charIndex++;
  1380.       } else if(index==2){
  1381.         notifications[notificationIndex].text[charIndex] = c;
  1382.         charIndex++;
  1383.       }
  1384.     }
  1385.     notPtr++; //move along
  1386.   }
  1387.   //finally get the timestamp of whenwe recieved the notification
  1388.   notifications[notificationIndex].dateReceived[0] = clockArray[0];
  1389.   notifications[notificationIndex].dateReceived[1] = clockArray[1];
  1390.  
  1391.   notifications[notificationIndex].textLength = charIndex;
  1392.  
  1393.   /*Serial.print(F("Notification title: "));
  1394.   Serial.println(notifications[notificationIndex].title);
  1395.   Serial.print(F("Notification text: "));
  1396.   Serial.println(notifications[notificationIndex].text);
  1397.   Serial.print("Text length: ");
  1398.   Serial.println(notifications[notificationIndex].textLength); */
  1399.   notificationIndex++;
  1400. }
  1401.  
  1402.  
  1403.  
  1404. void getTimeFromDevice(char message[], short len){
  1405.   //sample data
  1406.   //<d>24 04 2016 17:44:46
  1407.   Serial.print(F("Date data: "));
  1408.   Serial.println(message);
  1409.   char buf[4];//max 2 chars
  1410.   short charIndex = 0;
  1411.   short dateIndex = 0;
  1412.   short clockLoopIndex = 0;
  1413.      bool gotDate = false;
  1414.      for(short i = 3; i< len;i++){ // i = 3 skips first 3 chars
  1415.       if(!gotDate){
  1416.        if(message[i]==' '){
  1417.           dateArray[dateIndex] = atoi(buf);
  1418.           charIndex = 0;
  1419.           dateIndex++;
  1420.           if(dateIndex >= 3){
  1421.             gotDate = true;
  1422.             charIndex = 0;
  1423.             memset(buf, 0, sizeof(buf));
  1424.           }
  1425.        } else {
  1426.         buf[charIndex] = message[i];
  1427.         charIndex++;
  1428.  
  1429.        }
  1430.       } else {
  1431.         if(message[i]==':'){
  1432.             clockArray[clockLoopIndex] = atoi(buf); //ascii to short
  1433.             charIndex = 0;
  1434.             clockLoopIndex++;
  1435.         } else {
  1436.           buf[charIndex] = message[i];
  1437.           charIndex++;
  1438.         }
  1439.       }
  1440.      }
  1441.      //Read from the RTC
  1442.      RTC.read(tm);
  1443.      //Compare to time from Device(only minutes and hours doesn't have to be perfect)
  1444.      if(!((tm.Hour == clockArray[0] && tm.Minute == clockArray[1] && dateArray[0] == tm.Day && dateArray[1] == tm.Month && dateArray[2] == tm.Year))){
  1445.         setClockTime(clockArray[0],clockArray[1],clockArray[2],dateArray[0],dateArray[1],dateArray[2]);
  1446.         Serial.println(F("Setting the clock!"));
  1447.      } else {
  1448.         //if it's correct we do not have to set the RTC and we just keep using the RTC's time
  1449.         Serial.println(F("Clock is correct already!"));
  1450.         gotUpdatedTime = true;
  1451.      }
  1452.  
  1453. }
  1454.  
  1455. /*
  1456. * System methods
  1457. */
  1458.  
  1459. void shutDown(){
  1460.   HWSERIAL.print("AT"); // disconnect
  1461.   digitalWrite(BT_POWER,LOW); // turn off BT module
  1462.   int whatPin = Snooze.sleep(config); //SLEEP, DEEPSLEEP MAKE CURRENT GO THROUGH THE ROOF, HIBERNATE WORRKS BUT WONT wAKEUP WITH TSI, low storage problem?
  1463.   if(whatPin == 37){ // 37 is the TSI detected number
  1464.     SCB_AIRCR = 0x05FA0004; //reset chip
  1465.   }
  1466. }
  1467. void setAlarm(short alarmType, short hours, short minutes, short date,short month){
  1468.   short start = 0;
  1469.   if(alarmType == 0){
  1470.     RTC.setAlarm(ALM1_MATCH_DATE, minutes, hours, date); // minutes // hours // date (28th of the month)
  1471.     Serial.println("ALARM1 Set!");
  1472.     start = ALARM_ADDRESS;
  1473.   } else {
  1474.     RTC.setAlarm(ALM2_MATCH_DATE, minutes, hours, date); // minutes // hours // date (28th of the month)
  1475.     Serial.println("ALARM2 Set!");
  1476.     start = ALARM_ADDRESS + 4;
  1477.   }
  1478.   Serial.print("Starting write at address: ");
  1479.   Serial.println(start);
  1480.   saveToEEPROM(start,true); //set alarm active
  1481.   start++;
  1482.   saveToEEPROM(start,hours);
  1483.   start++;
  1484.   saveToEEPROM(start,minutes);
  1485.   start++;
  1486.   saveToEEPROM(start,date);
  1487.   start++;
  1488.   saveToEEPROM(start,month);
  1489. }
  1490.  
  1491. void createAlert(char text[],short len, short vibrationTime){
  1492.   if(len < 20){
  1493.     lastPage = pageIndex;
  1494.     alertTextLen = len;
  1495.     for(short i =0; i < len; i++){
  1496.       alertText[i] = text[i];
  1497.     }
  1498.     vibrate(vibrationTime);
  1499.     pageIndex = ALERT;
  1500.   } else {
  1501.     Serial.println(F("Not Creating Alert, text to big!"));
  1502.   }
  1503. }
  1504.  
  1505. void vibrate(short vibrationTime){
  1506.   alertVibrationCount = (vibrationTime) * 2;// double it as we toggle vibrate twice a second
  1507. }
  1508.  
  1509. void saveToEEPROM(short address,short value){
  1510.   if(address < EEPROM.length()){
  1511.     EEPROM.write(address,value);
  1512.   }
  1513. }
  1514.  
  1515. short readFromEEPROM(short address){
  1516.     return EEPROM.read(address);
  1517. }
  1518.  
  1519. void drawTriangle(short x, short y, short size, short direction){
  1520.   // some triangle are miss-shapen need to fix
  1521.   switch (direction) {
  1522.     case 1: u8g_DrawTriangle(&u8g,x,y,x+size,y, x+(size/2), y+(size/2)); break; //down
  1523.     case 2: u8g_DrawTriangle(&u8g,x,y,x+size,y, x+(size/2), y-(size/2)); break; //up
  1524.     case 3: u8g_DrawTriangle(&u8g,x+size,y,x,y-(size/2),x+size,y-size); break; // left
  1525.     case 4: u8g_DrawTriangle(&u8g,x + size,y-(size/2),x,y,x,y-size); break; // right
  1526.   }
  1527. }
  1528.  
  1529. void setClockTime(short hours,short minutes,short seconds, short days, short months, short years){
  1530.   tm.Hour = hours;
  1531.   tm.Minute = minutes;
  1532.   tm.Second = seconds;
  1533.   tm.Day = days;
  1534.   tm.Month = months;
  1535.   tm.Year = CalendarYrToTm(years);
  1536.   t = makeTime(tm);
  1537.  
  1538.   if(RTC.set(t) == 1) { // Success
  1539.     setTime(t);
  1540.     Serial.println(F("Writing time to RTC was successfull!"));
  1541.     gotUpdatedTime= true;
  1542.   } else {
  1543.     Serial.println(F("Writing to clock failed!"));
  1544.   }
  1545.  
  1546.  
  1547. }
  1548.  
  1549. void resetBTModule(){
  1550.   HWSERIAL.print("AT"); //disconnect
  1551.   delay(100); //need else the module won't see the commands as two separate ones
  1552.   HWSERIAL.print("AT+RESET"); //then reset
  1553.   createAlert("BT Module Reset.",16,0);
  1554. }
  1555.  
  1556. void resetTransmissionVariables(){
  1557.   finalDataIndex = 0; //reset final data
  1558.   memset(finalData, 0, sizeof(finalData)); // clears array - (When add this code to the OS we need to add the memsets to the resetTransmission() func)
  1559.   readyToProcess = false;
  1560. }
  1561.  
  1562. void removeNotification(short pos){
  1563.   if ( pos >= notificationIndex + 1 ){
  1564.     Serial.println(F("Can't delete notification."));
  1565.   } else {
  1566.     //need to zero out the array or stray chars will overlap with notifications
  1567.     memset(notifications[pos].text,0,sizeof(notifications[pos].text));
  1568.     memset(notifications[pos].title,0,sizeof(notifications[pos].title));
  1569.     memset(notifications[pos].packageName,0,sizeof(notifications[pos].packageName));
  1570.     for ( short c = pos ; c < (notificationIndex - 1) ; c++ ){
  1571.        notifications[c] = notifications[c+1];
  1572.     }
  1573.     //lower the index
  1574.     notificationIndex--;
  1575.   }
  1576. }
  1577.  
  1578. float getBatteryVoltage(){
  1579.   /*
  1580.    * WARNING: Add voltage divider to bring batt voltage below 3.3v at all times! Do this before pluggin in the Batt or will destroy the Pin in a best case scenario
  1581.    * and will destroy the teensy in a worst case.
  1582.    */
  1583.    float reads = 0;
  1584.    for(short i=0; i<100; i++){
  1585.     reads+= analogRead(BATT_READ);
  1586.    }
  1587.    // R1 = 2000, R2 = 3300
  1588.    // Vin = (Vout * (R1 + R2)) / R2
  1589.   return ((reads/100) * (3.3 / 1024) * (3300 + 2000))/(3300);
  1590. }
  1591.  
  1592. /*
  1593. * Utility methods
  1594. */
  1595.  
  1596. void intTo2Chars(short number){
  1597.   memset(numberBuffer,0,sizeof(numberBuffer));
  1598.   if(number < 10){
  1599.     numberBuffer[0] = '0';
  1600.     numberBuffer[1] = (number + 48);
  1601.  
  1602.   } else {
  1603.     itoa(number,numberBuffer,10);
  1604.   }
  1605. }
  1606.  
  1607. bool startsWith(char data[], char charSeq[], short len){
  1608.     for(short i=0; i < len; i++){
  1609.       if(!(data[i]==charSeq[i])){
  1610.         return false;
  1611.       }
  1612.     }
  1613.     return true;
  1614. }
  1615.  
  1616. bool contains(char data[], char character, short lenOfData){
  1617.   for(short i = 0; i < lenOfData; i++){
  1618.     if(data[i] == character){
  1619.       return true;
  1620.     }
  1621.   }
  1622.   return false;
  1623. }
  1624.  
  1625. short FreeRam() {
  1626.   char top;
  1627.   #ifdef __arm__
  1628.     return &top - reinterpret_cast<char*>(sbrk(0));
  1629.   #else  // __arm__
  1630.     return __brkval ? &top - __brkval : &top - &__bss_end;
  1631.   #endif  // __arm__
  1632. }
  1633.  
  1634. /*#ifdef __cplusplus
  1635. extern "C" {
  1636. #endif
  1637. void startup_early_hook() {
  1638.   // empty
  1639. }
  1640. #ifdef __cplusplus
  1641. }
  1642. #endif */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement