run this here
Dependencies: Hexi_KW40Z Hexi_OLED_SSD1351
Diff: main.cpp
- 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