Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: MAX30101 MAX32620FTHR
Revision 16:07842c9f55cc, committed 2020-10-31
- 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) {