JNP3 SmartAlarm / Mbed 2 deprecated budzik

Dependencies:   TextLCD nRF24L01P mbed

Revision:
10:3417715786be
Parent:
9:53da36425601
Child:
11:c94b9db597e9
--- a/main.cpp	Tue Jan 17 21:42:42 2017 +0000
+++ b/main.cpp	Sun Jan 22 20:03:32 2017 +0000
@@ -1,10 +1,13 @@
 #include "mbed.h"
-#include "rtos.h"
+//#include "rtos.h"
 #include "TextLCD.h"
 #include "custom-chars.h"
 #include "melodies.h"
 #include "nRF24L01P.h"
 #include <string>
+#include <vector>
+
+time_t next_alarm = 0;
 
 // Host PC Communication channels
 Serial pc(USBTX, USBRX); // tx, rx
@@ -13,7 +16,18 @@
 TextLCD_I2C lcd(&i2c_lcd, 0x4E, TextLCD::LCD16x2); // I2C exp: I2C bus, PCF8574 Slaveaddress, LCD Type
 
 //Light sensor
+#define LIGHT_INTERVAL 2
 AnalogIn light_sensor(A1);
+double light_sum;
+int light_samples;
+time_t next_light = 0;
+//Mutex light_mutex;
+
+void lightSensor(){
+    light_sum += light_sensor;
+    light_samples++;
+    next_light = time(NULL) + LIGHT_INTERVAL;
+}
 
 //2.4 GHz radio
 #define RX_ADDRESS      ((unsigned long long) 0xABCDEF00)
@@ -56,25 +70,55 @@
     radio.enable();
 };
 
-//TODO: I don't think it needs to be in a separate thread,
-//we probably can just put it into the main loop.
-void radio_recv(void const* args){
-    char rxData[TRANSFER_SIZE+1];
-    while (1) {
-        int rx_bytes=0;
+bool movement_detected = false;
+
+std::vector<std::string> last_wireless_data;
+time_t last_wireless_time;
 
-        if(radio.readable(NRF24L01P_PIPE_P1)){
-            rx_bytes = radio.read(NRF24L01P_PIPE_P1, rxData, TRANSFER_SIZE);
-            rxData[TRANSFER_SIZE] = '\0';
-            pc.printf("Received %d >>%s<<\r\n",rx_bytes, rxData);
-        }
+void processWirelessData(char* data_string){
+    std::string s = data_string;
+    std::vector<std::string> data;
+    size_t pos = 0;
+    std::string token;
+    std::string delimiter = "&";
+    
+    while ((pos = s.find(delimiter)) != std::string::npos) {
+        token = s.substr(0, pos);
+        data.push_back(token);
+        s.erase(0, pos + delimiter.length());
+    }
+    
+    last_wireless_data = data;
+    last_wireless_time = time(NULL);
+    
+    if (data.size() >= 3){
+        double min = atof(data[0].c_str());
+        double max = atof(data[1].c_str());
+        double avg = atof(data[2].c_str());
         
+        if (max > 0.3 && avg > 0.1)
+            movement_detected = true;
+        else
+            movement_detected = false;
     }
 }
 
-//Display
-void backlightTimeout(void const *arg);
-RtosTimer backlightTimer(&backlightTimeout, osTimerPeriodic, (void*)0);
+void radio_recv(){
+    char rxData[TRANSFER_SIZE+1];
+    int rx_bytes=0;
+
+    if(radio.readable(NRF24L01P_PIPE_P1)){
+        rx_bytes = radio.read(NRF24L01P_PIPE_P1, rxData, TRANSFER_SIZE);
+        rxData[TRANSFER_SIZE] = '\0';
+        pc.printf("Received %d >>%s<<\r\n",rx_bytes, rxData);
+        processWirelessData(rxData);
+    }
+}
+
+//Handling display
+void backlightTimeout();
+//RtosTimer backlightTimer(&backlightTimeout, osTimerPeriodic, (void*)0);
+Timeout backlightTimer;
 
 class Display{
 public:
@@ -88,7 +132,7 @@
     char time_str[9];
     char date_str[9];
     
-    static const int backlightTime = 5000;
+    static const float backlightTime = 5.000;
     int backlightState;
     Display()
     {
@@ -113,15 +157,23 @@
     void backlightOn(){
         lcd.setBacklight(TextLCD::LightOn); 
         backlightState = 1;
-        backlightTimer.start(backlightTime);
+        backlightTimer.attach(&backlightTimeout, backlightTime);
+        
     }
     
     void update(){
         //Top row of display
         char ico1 = ' ';
-        char ico2 = wireless_in_progress ? (frame % 2 ? C_WLC : ' ' ) : ' ';
-        char ico3 = C_ALRM;
-        int ah=85, am=84;
+        char ico2 = sync_in_progress ? (frame % 2 ? C_WIFI : ' ' ) : ' ';
+        char ico3 = ' ';
+        char alarm_time[6];
+        if (next_alarm != 0){
+            ico3 = C_ALRM;
+            strftime(alarm_time, 6, "%H:%M", localtime(&next_alarm));
+        }
+        else {
+            strcpy(alarm_time, "     ");
+        }
         
         time_t seconds_now = time(NULL);
         if (seconds_now != seconds) {
@@ -131,12 +183,15 @@
         }
         
         lcd.locate(0,0); //Put in top row
-        lcd.printf("%s%c%c%c%02d:%02d",time_str,ico1,ico2,ico3,ah,am);
+        lcd.printf("%s%c%c%c%s",time_str,ico1,ico2,ico3,alarm_time);
         
         lcd.locate(0,1); //Put in bottom row
         if (sync_in_progress) {
             lcd.printf("Synchronizacja..");
         }
+        if (alarm_on){
+            lcd.printf("Wstawaj!        ");
+        }
         else {
             if (frame % 60 < 30) {
                 lcd.printf("SmartAlarm+ Pro ");
@@ -166,7 +221,7 @@
     userButtonReleased = 1; 
 }
 
-void backlightTimeout(void const *arg){
+void backlightTimeout(){
     backlightTimedOut = 1;
 }
 
@@ -178,13 +233,15 @@
 bool readInProgress = false;
 int currentReadIndex = 0;
 
-void wifiCallback() {    
+void wifiCallback() {
     char c = wifi.getc();
+    
     if (c == '*') {
         readInProgress = !readInProgress;
         wifiData[currentReadIndex] = '\0';
         currentReadIndex = 0;
-        wifiDataReady = true;
+        if (readInProgress == false)
+            wifiDataReady = true;
     } else if (readInProgress) {
         wifiData[currentReadIndex++] = c;
     }
@@ -208,6 +265,7 @@
         while (!wifiDataReady && t <= timeout){
             wait(0.01f);
         }
+        
         pc.printf("http GET trying #%d\r\n", retry);
         if (wifiDataReady)
             break;
@@ -217,108 +275,141 @@
 
 //Synchronization
 time_t next_sync = 0;
+time_t last_sync = 0;
 bool sync_in_progress = false;
-time_t next_alarm = (time_t)-1; //TODO: bardzo brzydki hack
 
 time_t getNextSync(){
     //TODO: zmiennej czasu nie powinno sie chyba tak modyfikowac
-    return time (NULL) + 123;
+    return time (NULL) + 23;
 }
 
-//Reads are blocking now, so we need to put it into a different thread
-void syncThreadFunction(void const* args){
+int syncFunction(){
+    disp.sync_in_progress = 1;
+    last_sync = time(NULL);
     std::string time_string = httpGETWithRetry("GET " 
                 "/time/current/ "
                 "HTTP/1.1\r\n"
-                "Host: 10.1.8.202:8080\r\n\r\n", 5.0, 5);
+                "Host: 10.1.8.202:8080\r\n\r\n", 2.0, 5);
     if (time_string == ""){
-        lcd.locate(0,1);
-        lcd.printf("Blad synchroniz."); //TODO: to nie bedzie dzialac, trzeba przekazac te dane do obiektu disp
+        //TODO: błąd synchronizacji
     }
     else {
         set_time(atoi(time_string.c_str()));
     }
     
     time_string = httpGETWithRetry("GET " 
-                "/alarm/latest/ "
+                "/alarm/get/nearest/id/5881e409e93a2218d42fe888 "
                 "HTTP/1.1\r\n"
-                "Host: 10.1.8.202:8080\r\n\r\n", 5.0, 5); //TODO: Jaki endpoint do alarmow?
+                "Host: 10.1.8.202:8080\r\n\r\n", 2.0, 5);
     if (time_string == ""){
-        lcd.locate(0,1);
-        lcd.printf("Blad synchroniz.");
     }
     else {
         next_alarm = atoi(time_string.c_str());
     }
     
+    time_t now;
+    time(&now);
+    char time_str[50];
+    strftime(time_str, 50, "%FT%TZ", gmtime(&now));
+    
+    //Get light sensor data
+    double light_sensor_avg;
+    light_sensor_avg = light_samples == 0 ? 0 : light_sum / light_samples ;
+    light_sum = 0;
+    light_samples = 0;
+    
+    wifi.printf("POST " 
+                "/alarm/get/nearest/id/5881e409e93a2218d42fe888 "
+                "HTTP/1.1\r\n"
+                "Host: 10.1.8.202:8080\r\n\r\n"
+                "{"
+                "\"date\":\"%s\""
+                "\"value\":%f"
+                "\"device_id\":\"5881e409e93a2218d42fe888\""
+                "\"type\":\"light\""
+                "}\r\n\r\n", time_str, light_sensor_avg);
     next_sync = getNextSync();
-    sync_in_progress = false;
+    return 0;
 }
 
 //Alarm
-PwmOut sound(D2);
+PwmOut sound(D13);
 bool alarm_playing = false;
 bool alarm_stopped = false;
 
-//We probably could do sound playback with timers and whatnot
-//but why when we have THREADS!
-void alarmThreadFunction(void const* args){
-    //TODO: opcja wyboru dzwonka? whatever, i tak tego nie dokonczymy
-    const int* freq = axelf_freq;
-    const int* per = axelf_per;
-    float bpm = 100.0f; //tempo
-    alarm_stopped = false;
-    while (!alarm_stopped){
-        float base_period = 0.5f;
-        float base_time = bpm / 60.0f;
-        for (int i = 0; i < 100; i++){ //TODO: no bounds checking, -1 sentinel at the end required
-            if (per[i] == -1)
-                break;
-            if (freq[i] != 0) {
-                sound.period(base_period/freq[i]);
-                sound = 0.5f;
-            }
-            else {
-                sound = 0.0f;
-            }
-            wait(base_time/per[i]);
-        }
+const int* freq = axelf_freq;
+const int* per = axelf_per;
+int next_note = 0;
+
+void play_next_note();
+Timeout next_note_timeout;
+
+void start_alarm(){
+    disp.alarm_on = 1;
+    alarm_playing = true;
+    next_note = 0;
+    next_note_timeout.attach(&play_next_note, 0.01);
+}
+
+void stop_alarm(){
+    next_alarm = 0;
+    alarm_playing = false;
+    disp.alarm_on = 0;
+    sound = 0.0f;
+}
+
+//TODO: won't work if melody contains -1 per at the beginning, has to have at least one note
+void play_next_note(){
+    if (!alarm_playing)
+        return;
+    
+    const float bpm = 100.0f; //tempo
+    const float base_period = 0.5f;
+    const float base_time = bpm / 60.0f;
+
+    if (per[next_note] <= 0)
+        next_note = 0;
+
+    if (freq[next_note] != 0) {
+        sound.period(base_period/freq[next_note]);
+        sound = 0.5f;
+    }
+    else {
         sound = 0.0f;
     }
-    alarm_playing = false;
+    
+    next_note++;
+    next_note_timeout.attach(&play_next_note, base_time/per[next_note]);    
 }
 
-Ticker display_update_ticker;
 int main() {
-    set_time(1256729737);  //DEBUG: Set RTC time to Wed, 28 Oct 2009 11:35:37
+    wifi.baud(115200); 
+    wifi.attach(&wifiCallback);
     //Initialization
     disp.backlightOn();
     button.rise(&userButtonPress);
     button.fall(&userButtonRelease);
     
-    wifi.baud(115200); 
-    wifi.attach(&wifiCallback);
-    
     pc.printf("Waiting for time\r\n");
     
     std::string time_string = httpGETWithRetry("GET " 
                 "/time/current/ "
                 "HTTP/1.1\r\n"
-                "Host: 10.1.8.202:8080\r\n\r\n", 5.0, 5);
+                "Host: 10.4.8.136:8080\r\n\r\n", 5.0, 5);
     
-    pc.printf("Get time returned >>%s<<", time_string.c_str());
+    pc.printf("Get time returned >>%s<< %d\r\n", time_string.c_str());
     
     if (time_string == ""){
         lcd.locate(0,1); //Put in top row
         lcd.printf("Blad synchroniz.");
         wait(1);
+        set_time(1256729737);  //DEBUG: Set RTC time to Wed, 28 Oct 2009 11:35:37
     }
     else {
         set_time(atoi(time_string.c_str()));
     }
     
     initRadio(6, NRF24L01P_TX_PWR_ZERO_DB, NRF24L01P_DATARATE_250_KBPS);
-    Thread radio_thread(radio_recv);
     
     while (1){
         pc.printf("ok\r\n");
@@ -335,9 +426,13 @@
             userButtonTimer.stop();
             if (userButtonTimer.read_ms() > userButtonLongPress){
                 pc.printf("User button long pressed");
-                //disp.backlightOff(); //that was just debug code anyway
+                disp.backlightOff(); //that was just debug code anyway
                 if (alarm_playing){
-                    alarm_stopped = true;
+                    stop_alarm();
+                }
+                else {
+                    //Force synchronization
+                    next_sync = time(NULL);
                 }
             }
             else {
@@ -352,22 +447,35 @@
             disp.backlightOff();
         }
         
+        if (time(NULL) >= next_light){
+            lightSensor();
+        }
+        
         //Synchronize with server
-        if (time(NULL) >= next_sync && !sync_in_progress){
-            sync_in_progress = true;
-            Thread sync_thread(syncThreadFunction);
+        if (time(NULL) >= next_sync){
+            disp.sync_in_progress = 1;
+            disp.update();
+            syncFunction();
+            disp.sync_in_progress = 0;
+            disp.update();
         }
         
         //Check if alarm should be played
-        if (time(NULL) >= next_alarm && !alarm_playing){
-            alarm_playing = true;
-            Thread alarm_thread(alarmThreadFunction);
+        if (next_alarm != 0 && !alarm_playing){
+            if (time(NULL) >= next_alarm-(15*60) ){ //Hardcoded to 15 minutes before set time
+                if (movement_detected || time(NULL) >= next_alarm){
+                    start_alarm();
+                }
+            }
         }
         
+        //Try to receive from radio
+        radio_recv();
+        
         //Updating display
         disp.update();
         
-        Thread::wait(100);
+        wait_ms(100);
     };
 }