run this here

Dependencies:   Hexi_KW40Z Hexi_OLED_SSD1351

Revision:
3:f34bbdea0786
Parent:
2:75253a344332
Child:
4:1ae9f76749b9
--- a/main.cpp	Fri Apr 27 06:16:33 2018 +0000
+++ b/main.cpp	Tue Jun 12 00:27:26 2018 +0000
@@ -1,188 +1,189 @@
 #include "mbed.h"
+#include "Hexi_KW40Z.h"
+#include "Hexi_OLED_SSD1351.h"
 #include "Ticker.h"
-#include <stdlib.h>
+#include "timeHelp.h"
 
-InterruptIn catchChange(PTD2);
-Serial pc(USBTX, USBRX);
+void AlertReceived(uint8_t *data, uint8_t length);
+void displayTimeToScreen();
+void clearScreen();
+void updateError();
+void updateDisplayString();
+void txTask();
 
-// software PWM using DigitalOut
-DigitalOut pulse(PTA10);
+KW40Z kw40z_device(PTE24, PTE25);
 
-float PERIOD = 0.06f;
-float DUTYCYCLE = 0.50f;
+// oled driver and its text buffer
+SSD1351 oled(PTB22,PTB21,PTC13,PTB20,PTE6, PTD15);
+char text[20];
+
+const float interval = 0.1;
+int numTicks = 0;
+int prevNumTicks = 0;
+float timingError = 0.0;
 
-// period and duty cycle that we'll be changing
-float currentPeriod = PERIOD;
-float currentDutyCycle = DUTYCYCLE;
+char prevTime[11] = "00:00:00.0";
+char displayTime[11] = "00:00:00.0";
 
-// period is the time between the previous rising edge
-// and the current one, so recompute each time you
-// encounter a rising edge
-float period;
-Timer t;
+// important to know whether or not we've synced at least once with pi
+// because we don't have an initial time until we hear from pi
+bool firstSync = true;
+bool syncedTwice = false;
+
+DigitalOut pwm(PTA10);
 
-// D is fraction of time that was high during the preceding interval
-float D;
-Timer highTime;
-Timer lowTime;
+
+// bluetooth thread
+Thread txThread;
 
-// every 10 rising edges, print T and D
-int risingEdges = 0;
+// event queue for displaying the time
+EventQueue displayQueue;
+// event queue for receiving the time
+EventQueue receiveTimeQueue;
 
-// add in a thread that will do printing so it 
-// doesn't interfere with my measurements
-EventQueue q1;
-Thread t1;
-
-// ticker to change from low to high and one to change from high to low
-Ticker lowToHigh; // low to high every period seconds
-Ticker highToLow; // high to low every period + period * duty_cycle seconds
-
-// switch the digital signal whenever the ticker goes off
-void tickerHandle() {
-    if (pulse.read() == 1) {
-        pulse.write(0);   
-    } else {
-        pulse.write(1);
-    }
+int main() {    
+//    pc.printf("main started!!\r\n");
+    
+    kw40z_device.attach_alert(&AlertReceived);
+    
+    // thread that displays the time for us
+    Thread displayThread;
+    displayThread.start(callback(&displayQueue, &EventQueue::dispatch_forever));
+    
+    // thread that responds to pi's time updates
+    Thread receiveTimeThread;
+    receiveTimeThread.start(callback(&receiveTimeQueue, &EventQueue::dispatch_forever));
+    
+    // initialize the screen to blank
+    displayQueue.call(&clearScreen);
+    displayQueue.call(&displayTimeToScreen);
+    
+    // ticker that increments the time
+    Ticker updateTimeTicker;
+    updateTimeTicker.attach(receiveTimeQueue.event(&updateDisplayString), interval);
+    
+    // start toggling bluetooth so you can connect
+    txThread.start(txTask);
+    
+    wait(osWaitForever);   
 }
 
-void printData() {
-    // this does not run in the ISR
-    pc.printf("mbed> %i, %.3f\n\r",(int)(period*1000000.0f),D);
+/******************************End of Main*************************************/
+
+// initialize the screen to black
+void clearScreen() {    
+    oled.FillScreen(COLOR_BLACK);
 }
 
-void riseHandle() {
-    // recompute the period
-    period = t.read();
-    t.reset();
-    t.start();
+void displayTimeToScreen() {
+    /* Get OLED Class Default Text Properties */
+    oled_text_properties_t textProperties = {0};
+    oled.GetTextProperties(&textProperties);
     
-    // if it's the first rising edge of a 10 edge interval,
-    // then reset both timers
-    if (risingEdges == 0) {
-        lowTime.reset();
-        highTime.reset();
-        lowTime.stop();
-        highTime.start();
-        
-        // and you're in high time on the first rising edge
-        risingEdges++;
-    }
-    
-    // if it's the tenth, then store D so that someone else can
-    // print it out. reset the timers and rising edge count
-    else if (risingEdges >= 9) {
-        float h = highTime.read();
-        float l = lowTime.read();
-        D = h / (h + l);
-        
-        lowTime.reset();
-        highTime.reset();
-        lowTime.stop();
-        highTime.start();
-        
-        risingEdges++;
+    /* Change font color to Blue */ 
+    textProperties.fontColor   = COLOR_BLUE;
+    oled.SetTextProperties(&textProperties);
+
+    if (secondsAreEven(displayTime)) {
+        pwm = 0 ;
+    } else {
+        pwm = 1;
     }
     
-    // if it's rising edge 2 ... 9, then just increment and start
-    // the high timer and stop the low timer
-    else {
-        risingEdges++;
-        lowTime.stop();
-        highTime.start(); 
-    }
-    
-    // then defer the possible printf call to the other thread
-    if (risingEdges == 10) {
-        q1.call(&printData);
-        risingEdges = 0;
-    }
+    /* Display time Label at x=20,y=40 */ 
+    strcpy((char *) text, displayTime);
+    oled.Label((uint8_t *)text,20,40);   
 }
 
-// when you come to a falling edge, you should stop the high timer and
-// start the low timer
-void fallHandle() {
-    lowTime.start();
-    highTime.stop();   
-}
-
-void inputHandle() {
-    char buff[256];
-    gets(buff);
+// the alert that we've received is always the updated time from raspberry pi
+// so we should put that in display time, calculate the new interval, and 
+// display the new time
+void AlertReceived(uint8_t *data, uint8_t length) {
+    
+    char buf[10];
+    for (int i = 0; i < 10; ++i) {
+        buf[i] = data[i];
+    }
     
-    // extract out the values from the character array
-    int i = 0;
-    char p[20];
-    while (buff[i] != ',') {
-        p[i] = buff[i];
-        ++i;
+    // copy in the new data, storing the old only if there is old to store
+    for (int i = 0; i < 10; i++) {
+        if (!firstSync) {
+            prevTime[i] = displayTime[i];
+        }
+        
+        else {
+            prevTime[i] = buf[i];
+            
+            // if you get here, then you've synced once
+            if (!syncedTwice) {
+                syncedTwice = true;
+            }
+        }
+        displayTime[i] = buf[i];
     }
-    p[i] = '\0';
     
-    i += 2;
-    int j = 0;
-    char dc[20];
-    while (buff[i] != '\0') {
-        dc[j] = buff[i];
-        ++i;
-        ++j;
+    // reset numTicks
+    prevNumTicks = numTicks;
+    numTicks = 0;
+    
+    // update the error as long as it isn't your first sync ... need two times
+    if (!firstSync && syncedTwice) {
+        receiveTimeQueue.call(&updateError);
     }
     
-    int T_temp = atoi(p);
-    float D_temp = atof(dc);
-   
-    // make the changes to the period and duty cycle as long
-    // as they are within range
-    if ((T_temp >= 1000.0f && T_temp <= 60000.0f) &&
-        (D_temp >= 0.0f && D_temp <= 1.0f))
-    {
-        currentPeriod = ((float)T_temp) / 1000000.0f;
-        currentDutyCycle = D_temp;
-        
-        // set to low
-        pulse.write(0);
-        
-        // reset the low to high ticker
-        lowToHigh.detach();
-        lowToHigh.attach(&tickerHandle, currentPeriod);
-        
-        highToLow.detach();
-        
-        // wait period * duty cycle
-        wait(currentPeriod * currentDutyCycle);
-        // reset the high to low ticker
-        highToLow.attach(&tickerHandle, currentPeriod);
-    }
+    firstSync = false;
+}
+
+// error is the total amount that hexiwear was off by
+// averaged over all of the ticks ... moving forward we
+// can add the error into out calculation of the current
+// time and hopefully it will be more accurate.
+void updateError() {
     
-    // print an error, non-blocking, if they input bad values
-    else {
-        q1.call(printf,"mbed> ERROR\r\n");   
-    }
+    float secsToAdd = interval * prevNumTicks + timingError;
+    
+    float T1 = currTimeSecs(displayTime);
+    float T0 = currTimeSecs(prevTime);
+    
+    timingError += (T1 - (T0+secsToAdd)) / prevNumTicks;
 }
 
-// main() runs in its own thread in the OS
-int main() {
+int numPrints = 20;
+
+// you update the display string every 0.1 seconds, to add to the
+// number of ticks, calculate the offset from the previous time,
+// and display it
+void updateDisplayString() {
+    numTicks++;
     
-    // each time you see a rising edge, recompute the period
-    // and stop timing the low signal
-    catchChange.rise(&riseHandle);
-    catchChange.fall(&fallHandle);
+    float offset = interval * numTicks + timingError;
     
-    // when the user inputs something
-    pc.attach(&inputHandle);
+    addSecondsToCurrentTime(prevTime, displayTime, offset);
     
-    // start low
-    pulse.write(0);
-    
-    // 1) ticker that goes from low to high every period seconds
-    lowToHigh.attach(&tickerHandle, currentPeriod);
-    // 2) wait period * duty cycle
-    wait(currentPeriod * currentDutyCycle);
-    // 3) ticker that goes from high to low every period seconds
-    highToLow.attach(&tickerHandle, currentPeriod);
-    
-    t1.start(callback(&q1, &EventQueue::dispatch_forever));
-    
-    wait(osWaitForever);
+    displayQueue.call(&displayTimeToScreen);
+}
+
+// take care of the bluetooth toggling so that it can conect
+void txTask(){
+   
+   while (true) 
+   {
+        // there is about a half second delay before the hexiwear
+        // realizes that the link state is down, so if you ever
+        // do realize that, you should toggle the advertisement
+        // state right away, I think. NO what you should do it, if
+        // you ever realize that the link is down, wait a half a second
+        // and then toggle advertisement mode to let it refresh
+
+        // it seems like this doesn't perform quite as well, but I think
+        // it is more robust...
+        if (kw40z_device.GetLinkState() == 0) {
+            Thread::wait(2500);
+            if (kw40z_device.GetLinkState() == 0) {
+                kw40z_device.ToggleAdvertisementMode();
+            }
+        }
+
+        Thread::wait(5000);                 
+    }
 }
\ No newline at end of file