Greg Toth / Mbed OS MAX30101WING_HR_SPO2

Dependencies:   MAX30101 MAX32620FTHR

Files at this revision

API Documentation at this revision

Comitter:
gregtoth
Date:
Sat Oct 31 15:45:51 2020 +0000
Parent:
15:d9f7d0d5fc4e
Commit message:
add MediumOne support

Changed in this revision

main.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/main.cpp	Wed Oct 21 18:07:10 2020 +0000
+++ b/main.cpp	Sat Oct 31 15:45:51 2020 +0000
@@ -40,6 +40,51 @@
 #include <math.h>
 #include <string.h>
 
+#define WIFI_SSID       "YOUR_INFO"
+#define WIFI_PASSWORD   "YOUR_INFO"
+
+#define MQTT_BROKER     "mqtt.mediumone.com"
+#define MQTT_PORT       61618           /* encrypted port */
+#define MQTT_USERNAME   "xxxxxxxxxxx/xxxxxxxxxxx"
+#define MQTT_PASSWORD   "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/xxxxxxxxxxxxxxxxx"
+#define MQTT_PUB_TOPIC  "0/xxxxxxxxxxx/xxxxxxxxxxx/mydevice"
+
+#define PUB_INTERVAL_MS 3000
+#define ENABLE_PUBLISH  1
+
+typedef enum {
+    APP_STATE_INIT = 0,
+    APP_STATE_RESET_BRIDGE,
+    APP_STATE_INIT_BRIDGE,
+    APP_STATE_INIT_BRIDGE_CONFIRM,
+    APP_STATE_CONNECT_WIFI,
+    APP_STATE_CONNECT_WIFI_CONFIRM,
+    APP_STATE_CONNECT_MQTT,
+    APP_STATE_CONNECT_MQTT_CONFIRM,
+    APP_STATE_PUBLISH_SENSOR_DATA,
+    APP_STATE_PUBLISH_SENSOR_DATA_CONFIRM,
+    APP_STATE_DISCONNECT_MQTT,
+    APP_STATE_DISCONNECT_WIFI,
+    APP_STATE_DISCONNECT_WIFI_CONFIRM,
+    APP_STATE_TIMED_DELAY,
+    APP_STATE_NONE
+} APP_STATE_T;
+
+APP_STATE_T app_state = APP_STATE_INIT;
+APP_STATE_T next_app_state = APP_STATE_NONE;
+uint32_t timed_delay_start = 0;
+uint32_t timed_delay_duration = 0;
+
+typedef struct {
+    uint32_t iteration;     // iteration counter
+    uint32_t timestamp;     // millisecond timestamp
+    uint16_t hrbpm;         // heart rate, beats per minute
+    uint16_t spo2;          // oxygen saturation, percent
+    int      valid;         // 1=hrbpm and spo2 are valid, 0=not valid
+} SENSOR_DATA_T;
+
+SENSOR_DATA_T sensorData;
+    
 //variable for the algorithm
 uint16_t sampleRate =100;
 uint16_t compSpO2=1;
@@ -82,17 +127,158 @@
 uint32_t irData[500];//set array to max fifo size
 uint32_t greenData[500];//set array to max fifo size
 
+Serial *ppc = NULL;
+
+// UART2 serial
+RawSerial *puart2 = NULL;
+#define UART2_GETC() puart2->getc()
+#define UART2_PUTC(ch) puart2->putc(ch)
+#define UART2_PUTS(str) puart2->puts(str)
+#define UART2_READABLE() puart2->readable()
+
+#define SERIAL_BUF_SIZE 80
+char read_buffer[SERIAL_BUF_SIZE] = {0};
+char current_response[SERIAL_BUF_SIZE] = {0};
+char last_response[SERIAL_BUF_SIZE] = {0};
+int read_pos = 0;
+int write_pos = 0;
+int new_response_available = 0;
+uint32_t cmd_send_time;
+int fail_count = 0;
+char command[256];
+
+Timer timer;
+#define GET_TIME_MS()   (uint32_t)timer.read_ms()
+//#define GET_TIME_MS()   0
+
+// LEDs on MAX32620FTHR
+DigitalOut redLed(LED1 /*RED*/, LED_OFF);
+DigitalOut grnLed(LED2 /*GREEN*/, LED_OFF);
+DigitalOut bluLed(LED3 /*BLUE*/, LED_OFF);
+
+// Prototypes
+void Clear_Rx(void);
+void Send_Command(const char *cmd);
+uint32_t Response_Elapsed_Time(void);
+bool isOKResponse(char *p);
+void Delay_Ms(uint32_t ms);
+void LED_On(void);
+void LED_Off(void);
+APP_STATE_T new_app_state(APP_STATE_T app_state);
+void set_timed_delay(uint32_t delay_ms, APP_STATE_T next_state);
+void reset_bridge(void);
+void State_Machine(void);
+
+void uart2_rx()
+{
+    char ch = UART2_GETC();
+    if (ch == '\n') {  // end of response
+        current_response[write_pos] = 0;
+        strcpy(last_response, current_response);
+        read_pos = 0;
+        write_pos = 0;
+        current_response[write_pos] = 0;
+        new_response_available = 1;
+    } else if (ch != 0 && ch != '\r' && write_pos < sizeof(current_response) - 1) {  // ignore NUL & CR, keep rest
+        current_response[write_pos++] = ch;
+        current_response[write_pos] = 0;
+    }
+}
+
+void Clear_Rx(void)
+{
+    while (UART2_READABLE()) {
+        UART2_GETC();
+    }
+}
+
+void Send_Command(const char *cmd)
+{
+    if (cmd != NULL) {
+        read_pos = 0;
+        write_pos = 0;
+        current_response[write_pos] = 0;
+        new_response_available = 0;
+        Clear_Rx();
+        UART2_PUTS(cmd);
+        cmd_send_time = GET_TIME_MS();
+    }
+}
+
+uint32_t Response_Elapsed_Time(void)
+{
+    return GET_TIME_MS() - cmd_send_time;
+}
+
+bool isOKResponse(char *p)
+{
+    if (strncmp(p, "OK", 2) == 0) {
+        return true;
+        } else {
+        return false;
+    }
+}
+
+void Delay_Ms(uint32_t ms)
+{
+    uint32_t start = GET_TIME_MS();
+    while ((GET_TIME_MS() - start) < ms) {
+    }
+}
+
+void LED_On(void)
+{
+    grnLed = LED_ON;
+}
+
+void LED_Off(void)
+{
+    grnLed = LED_OFF;
+}
+
+APP_STATE_T new_app_state(APP_STATE_T app_state)
+{   
+    // Return next_app_state if it's not APP_STATE_NONE,
+    // otherwise return app_state
+    APP_STATE_T state = app_state;
+    if (next_app_state != APP_STATE_NONE) {
+        state = next_app_state;
+        next_app_state = APP_STATE_NONE;
+    }
+    return state;
+}
+
+void set_timed_delay(uint32_t delay_ms, APP_STATE_T next_state)
+{   
+    timed_delay_start = GET_TIME_MS();
+    timed_delay_duration = delay_ms;
+    next_app_state = next_state;
+    app_state = APP_STATE_TIMED_DELAY;
+}
+
+void reset_bridge(void)
+{   
+    // Not used due to MAX32620FTHR RST wiring
+}
 
 int main()
 {
+    // Create serial objects after main() has started
+    
     Serial pc(USBTX, USBRX);            // Use USB debug probe for serial link
+    ppc = &pc;
     pc.baud(115200);                    // Baud rate = 115200
     
-    //Serial uart2(P3_1, P3_0);
+    pc.printf("Starting main program\r\n");
+    
     RawSerial uart2(P3_1, P3_0);
+    puart2 = &uart2;
     uart2.baud(115200);
-
-    DigitalOut rLed(LED1, LED_OFF);     // Debug LED
+    uart2.attach(uart2_rx);
+        
+    timer.start();
+    
+    //DigitalOut redLed(LED1, LED_OFF);     // Debug LED
 
     InterruptIn op_sensor_int(P3_2);            // Config P3_2 as int. in for
     op_sensor_int.fall(&op_sensor_callback);    // FIFO ready interrupt
@@ -121,7 +307,11 @@
     int c=0; //counter to print values
 
     pc.printf("Starting Program...Please wait a few seconds while data is being collected.\r\n");
+    
     while(1) {
+        
+        State_Machine();
+   
         if( rc == 0 ) {
 
             // Check if op_sensor interrupt asserted
@@ -176,18 +366,32 @@
                             if(DRdy==1) {
                                 pc.printf("Heart Rate = %i\r\n",HRbpm2);
                                 pc.printf("SPO2 = %i\r\n",SpO2B);
-                                uart2.printf("SPO2 = %i (SpO2B)\r\n", SpO2B);
+                                sensorData.hrbpm = HRbpm2;
+                                sensorData.spo2 = SpO2B;
+                                sensorData.valid = 1;
+                                sensorData.timestamp = GET_TIME_MS();
+                                //uart2.printf("SPO2 = %i (SpO2B)\r\n", SpO2B);
+                                //UART2_PUTS("Got SPO2 reading (Sp02B)\r\n");
                             }
                             else if (HRTemp!=0)//if a valid heart was calculated at all, it is printed
                             {
                                 pc.printf("Heart Rate = %i\r\n",HRTemp);
                                 pc.printf("SPO2 = %i\r\n",spo2Temp);
-                                uart2.printf("SPO2 = %i (spo2Temp)\r\n", spo2Temp);
+                                sensorData.hrbpm = HRTemp;
+                                sensorData.spo2 = spo2Temp;
+                                sensorData.valid = 1;
+                                sensorData.timestamp = GET_TIME_MS();
+                                //uart2.printf("SPO2 = %i (spo2Temp)\r\n", spo2Temp);
+                                //UART2_PUTS("Got SPO2 reading (spo2Temp)\r\n");
                             }
                             else
                             {
                                 pc.printf("Calculation failed...waiting for more samples...\r\n");
-                                pc.printf("Please keep your finger on the MAX30101 sensor with minimal movement.\r\n"); 
+                                pc.printf("Please keep your finger on the MAX30101 sensor with minimal movement.\r\n");
+                                sensorData.hrbpm = 0;
+                                sensorData.spo2 = 0;
+                                sensorData.valid = 0;
+                                sensorData.timestamp = GET_TIME_MS();
                             }
 
                             //dump the first hundred samples after caluclaiton
@@ -217,14 +421,158 @@
             //gLed = LED_OFF;
 
             while(1) {
-                rLed = !rLed;
-                wait(0.5);
+                redLed = !redLed;
+                //wait(0.5);
+                //wait_ms(500);
+                wait_us(500000);
+                //ThisThread::sleep_for(500);
             }
         }
 
     }
 }
 
+void State_Machine(void)
+{
+    switch (app_state) {
+        case APP_STATE_INIT:
+            app_state = APP_STATE_RESET_BRIDGE;
+            break;
+        case APP_STATE_RESET_BRIDGE:
+            ppc->printf("Resetting bridge hardware...");
+            reset_bridge();
+            ppc->printf("complete\r\n");
+            app_state = APP_STATE_INIT_BRIDGE;
+            break;
+        case APP_STATE_INIT_BRIDGE:
+            ppc->printf("Initializing bridge\r\n");
+            Send_Command("AT\n");
+            app_state = APP_STATE_INIT_BRIDGE_CONFIRM;
+            break;
+        case APP_STATE_INIT_BRIDGE_CONFIRM:
+            if (new_response_available && isOKResponse(last_response)) {
+                ppc->printf("Bridge initialization complete\r\n");
+                app_state = APP_STATE_CONNECT_WIFI;
+                } else if (Response_Elapsed_Time() > 1000) {
+                ppc->printf("ERROR: Bridge not responding\r\n");
+                app_state = APP_STATE_RESET_BRIDGE;
+            }
+            break;
+        case APP_STATE_CONNECT_WIFI:
+            ppc->printf("Connecting to Wi-Fi\r\n");
+            sprintf(command, "AT+CWIFI={\"ssid\":\"%s\",\"password\":\"%s\"}\n",
+            WIFI_SSID, WIFI_PASSWORD);
+            Send_Command(command);
+            app_state = APP_STATE_CONNECT_WIFI_CONFIRM;
+            break;
+        case APP_STATE_CONNECT_WIFI_CONFIRM:
+            if (new_response_available) {
+                if (isOKResponse(last_response)) {
+                    ppc->printf("Wi-Fi connect successful\r\n");
+                    app_state = APP_STATE_CONNECT_MQTT;
+                    } else {
+                    ppc->printf("ERROR: Wi-Fi connect failed, will retry\r\n");
+                    set_timed_delay(5000, APP_STATE_CONNECT_WIFI);
+                }
+                } else if (Response_Elapsed_Time() > 20000) {
+                ppc->printf("ERROR: Wi-Fi connect timed out, will retry\r\n");
+                set_timed_delay(5000, APP_STATE_CONNECT_WIFI);
+            }
+            break;
+        case APP_STATE_CONNECT_MQTT:
+            ppc->printf("Connecting to MQTT broker\r\n");
+            sprintf(command, "AT+CMQTT={\"host\":\"%s\",\"port\":%d,\"username\":\"%s\",\"password\":\"%s\"}\n",
+            MQTT_BROKER, MQTT_PORT, MQTT_USERNAME, MQTT_PASSWORD);
+            Send_Command(command);
+            app_state = APP_STATE_CONNECT_MQTT_CONFIRM;
+            break;
+        case APP_STATE_CONNECT_MQTT_CONFIRM:
+            if (new_response_available) {
+                if (isOKResponse(last_response)) {
+                    ppc->printf("MQTT connect successful\r\n");
+                    app_state = APP_STATE_PUBLISH_SENSOR_DATA;
+                    } else {
+                    ppc->printf("ERROR: MQTT connect failed, will retry\r\n");
+                    set_timed_delay(5000, APP_STATE_CONNECT_MQTT);
+                }
+                } else if (Response_Elapsed_Time() > 10000) {
+                ppc->printf("ERROR: MQTT connect timed out, will retry\r\n");
+                set_timed_delay(5000, APP_STATE_CONNECT_MQTT);
+            }
+            break;
+        case APP_STATE_PUBLISH_SENSOR_DATA:
+            ppc->printf("Building publish message\r\n");
+            sprintf(command,
+            "AT+PUBLISH={\"topic\":\"%s\",\"msg\":\"{\\\"event_data\\\":{\\\"iteration\\\":%u,\\\"timestamp\\\":%u,\\\"valid\\\":%d,\\\"hrbpm\\\":%u,\\\"spo2\\\":%u}}\"}\n",
+            MQTT_PUB_TOPIC,
+            (unsigned)sensorData.iteration, (unsigned)sensorData.timestamp, sensorData.valid, sensorData.hrbpm, sensorData.spo2
+            );
+            ppc->printf("%s\r", command);  // command already has \n at end
+            sensorData.iteration++;
+#if ENABLE_PUBLISH == 1
+            Send_Command(command);
+            LED_On();
+            app_state = APP_STATE_PUBLISH_SENSOR_DATA_CONFIRM;
+#else
+            set_timed_delay(PUB_INTERVAL_MS, APP_STATE_PUBLISH_SENSOR_DATA);
+#endif
+            break;
+        case APP_STATE_PUBLISH_SENSOR_DATA_CONFIRM:
+            if (new_response_available) {
+                LED_Off();
+                if (isOKResponse(last_response)) {
+                    ppc->printf("MQTT publish successful\r\n");
+                    fail_count = 0;
+                    set_timed_delay(PUB_INTERVAL_MS, APP_STATE_PUBLISH_SENSOR_DATA);
+                    } else {
+                    ppc->printf("ERROR: MQTT publish failed\r\n");
+                    if (++fail_count >= 3) {
+                        app_state = APP_STATE_DISCONNECT_WIFI;
+                        } else {
+                        set_timed_delay(PUB_INTERVAL_MS, APP_STATE_PUBLISH_SENSOR_DATA);
+                    }
+                }
+                } else if (Response_Elapsed_Time() > 10000) {
+                LED_Off();
+                ppc->printf("ERROR: MQTT publish timed out\r\n");
+                if (++fail_count >= 3) {
+                    app_state = APP_STATE_DISCONNECT_WIFI;
+                    } else {
+                    // try again with no additional delay
+                }
+            }
+            break;
+        case APP_STATE_DISCONNECT_MQTT:
+            /* not currently used */
+            break;
+        case APP_STATE_DISCONNECT_WIFI:
+            ppc->printf("Disconnecting Wi-Fi\r\n");
+            Send_Command("AT+DWIFI\n");
+            app_state = APP_STATE_DISCONNECT_WIFI_CONFIRM;
+            break;
+        case APP_STATE_DISCONNECT_WIFI_CONFIRM:
+            if (new_response_available) {
+                if (isOKResponse(last_response)) {
+                    ppc->printf("Wi-Fi disconnect successful\r\n");
+                    app_state = new_app_state(APP_STATE_INIT);
+                    } else {
+                    ppc->printf("ERROR: Wi-Fi disconnect failed\r\n");
+                    app_state = new_app_state(APP_STATE_INIT);
+                }
+                } else if (Response_Elapsed_Time() > 10000) {
+                ppc->printf("ERROR: Wi-Fi disconnect timed out\r\n");
+                app_state = new_app_state(APP_STATE_INIT);
+            }
+            break;
+        case APP_STATE_TIMED_DELAY:
+            if ((GET_TIME_MS() - timed_delay_start) >= timed_delay_duration) {
+                app_state = new_app_state(APP_STATE_INIT);
+            }
+        case APP_STATE_NONE:
+            default:
+            break;
+        }   
+}
 
 bool op_sensor_config(MAX30101 &op_sensor)
 {