Trevor Hackett / Mbed OS get_time_EQ

Dependencies:   Hexi_KW40Z Hexi_OLED_SSD1351

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 #include "mbed.h"
00002 #include "Hexi_KW40Z.h"
00003 #include "Hexi_OLED_SSD1351.h"
00004 #include "Ticker.h"
00005 #include "timeHelp.h"
00006 
00007 void AlertReceived(uint8_t *data, uint8_t length);
00008 void displayTimeToScreen();
00009 void clearScreen();
00010 void updateError();
00011 void updateDisplayString();
00012 void txTask();
00013 
00014 KW40Z kw40z_device(PTE24, PTE25);
00015 
00016 // oled driver and its text buffer
00017 SSD1351 oled(PTB22,PTB21,PTC13,PTB20,PTE6, PTD15);
00018 char text[20];
00019 
00020 const float interval = 0.1;
00021 int numTicks = 0;
00022 int prevNumTicks = 0;
00023 float intervalError = 0.0;
00024 
00025 char prevTime[11] = "00:00:00.0";
00026 char displayTime[11] = "00:00:00.0";
00027 
00028 // important to know whether or not we've synced at least once with pi
00029 // because we don't have an initial time until we hear from pi
00030 bool firstSync = true;
00031 bool syncedTwice = false;
00032 
00033 DigitalOut pwm(PTA10);
00034 
00035 
00036 // bluetooth thread
00037 Thread txThread;
00038 
00039 // event queue for displaying the time
00040 EventQueue displayQueue;
00041 // event queue for receiving the time
00042 EventQueue receiveTimeQueue;
00043 
00044 int main() {    
00045     
00046     kw40z_device.attach_alert(&AlertReceived);
00047     
00048     // thread that displays the time for us
00049     Thread displayThread;
00050     displayThread.start(callback(&displayQueue, &EventQueue::dispatch_forever));
00051     
00052     // thread that responds to pi's time updates
00053     Thread receiveTimeThread;
00054     receiveTimeThread.start(callback(&receiveTimeQueue, &EventQueue::dispatch_forever));
00055     
00056     // initialize the screen to blank
00057     displayQueue.call(&clearScreen);
00058     displayQueue.call(&displayTimeToScreen);
00059     
00060     // ticker that increments the time
00061     Ticker updateTimeTicker;
00062     updateTimeTicker.attach(receiveTimeQueue.event(&updateDisplayString), interval);
00063     
00064     // start toggling bluetooth so you can connect
00065     txThread.start(txTask);
00066     
00067     wait(osWaitForever);   
00068 }
00069 
00070 /******************************End of Main*************************************/
00071 
00072 // initialize the screen to black
00073 void clearScreen() {    
00074     oled.FillScreen(COLOR_BLACK);
00075 }
00076 
00077 void displayTimeToScreen() {
00078     /* Get OLED Class Default Text Properties */
00079     oled_text_properties_t textProperties = {0};
00080     oled.GetTextProperties(&textProperties);
00081     
00082     /* Change font color to Blue */ 
00083     textProperties.fontColor   = COLOR_BLUE;
00084     oled.SetTextProperties(&textProperties);
00085 
00086     if (secondsAreEven(displayTime)) {
00087         pwm = 0 ;
00088     } else {
00089         pwm = 1;
00090     }
00091     
00092     /* Display time Label at x=20,y=40 */ 
00093     strcpy((char *) text, displayTime);
00094     oled.Label((uint8_t *)text,20,40);   
00095 }
00096 
00097 // the alert that we've received is always the updated time from raspberry pi
00098 // so we should put that in display time, calculate the new interval, and 
00099 // display the new time
00100 void AlertReceived(uint8_t *data, uint8_t length) {
00101     
00102     char buf[10];
00103     for (int i = 0; i < 10; ++i) {
00104         buf[i] = data[i];
00105     }
00106     
00107     // copy in the new data, storing the old only if there is old to store
00108     for (int i = 0; i < 10; i++) {
00109         if (!firstSync) {
00110             prevTime[i] = displayTime[i];
00111         }
00112         
00113         else {
00114             prevTime[i] = buf[i];
00115             
00116             // if you get here, then you've synced once
00117             if (!syncedTwice) {
00118                 syncedTwice = true;
00119             }
00120         }
00121         displayTime[i] = buf[i];
00122     }
00123     
00124     // reset numTicks
00125     prevNumTicks = numTicks;
00126     numTicks = 0;
00127     
00128     // update the error as long as it isn't your first sync ... need two times
00129     if (!firstSync && syncedTwice) {
00130         receiveTimeQueue.call(&updateError);
00131     }
00132     
00133     firstSync = false;
00134 }
00135 
00136 // error is the total amount that hexiwear was off by
00137 // averaged over all of the ticks ... moving forward we
00138 // can add the error into out calculation of the current
00139 // time and hopefully it will be more accurate.
00140 void updateError() {
00141     
00142     // 
00143     float secsToAdd = prevNumTicks * (interval + intervalError);
00144     
00145     float T1 = currTimeSecs(displayTime);
00146     float T0 = currTimeSecs(prevTime);
00147     
00148     intervalError = (T1 - (T0+secsToAdd)) / prevNumTicks;
00149 }
00150 
00151 int numPrints = 20;
00152 
00153 // you update the display string every 0.1 seconds, to add to the
00154 // number of ticks, calculate the offset from the previous time,
00155 // and display it
00156 void updateDisplayString() {
00157     numTicks++;
00158     
00159     float offset = numTicks * (interval + intervalError);
00160     
00161     addSecondsToCurrentTime(prevTime, displayTime, offset);
00162     
00163     displayQueue.call(&displayTimeToScreen);
00164 }
00165 
00166 // take care of the bluetooth toggling so that it can conect
00167 void txTask(){
00168    
00169    while (true) 
00170    {
00171         // there is about a half second delay before the hexiwear
00172         // realizes that the link state is down, so if you ever
00173         // do realize that, you should toggle the advertisement
00174         // state right away, I think. NO what you should do it, if
00175         // you ever realize that the link is down, wait a half a second
00176         // and then toggle advertisement mode to let it refresh
00177 
00178         // it seems like this doesn't perform quite as well, but I think
00179         // it is more robust...
00180         if (kw40z_device.GetLinkState() == 0) {
00181             Thread::wait(2500);
00182             if (kw40z_device.GetLinkState() == 0) {
00183                 kw40z_device.ToggleAdvertisementMode();
00184             }
00185         }
00186 
00187         Thread::wait(5000);                 
00188     }
00189 }