/* * comms.c * * Created on: Jan 16, 2023 * Author: Sword */ #include "rtc.h" #include "nvm.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include #include "esp_timer.h" #include #include #include #include "modem.h" #include "wifi_Client.h" #include "main.h" #include "comms.h" #include "port.h" #include "data_processing.h" #include "ota.h" #include "hmi.h" #define LOG_LOCAL_LEVEL ESP_LOG_INFO #include "esp_log.h" // Development support: force the operation of the following configuration functions #ifdef SET_CFG_BITS // set 1 to force the appropriate functions #define FORCE_MCU_CONFIG_DOWNLOAD 1 #define FORCE_MCU_PROG_DOWNLOAD 1 #define FORCE_MODEM_PROG_DOWNLOAD 1 #else #define FORCE_MCU_CONFIG_DOWNLOAD 0 #define FORCE_MCU_PROG_DOWNLOAD 0 #define FORCE_MODEM_PROG_DOWNLOAD 0 #endif /* Set 1 to use "unwired/[IMEI]", e.g. "unwired/862061049756488" * Set 0 to use "unwiredct" */ #define COMMS_PUBLISH_WITH_IMEI 0 #define JWT_LEN 1024 //#define MCU_SP4_URL "https://parthasarathimishra.com/hae/tempstick/%s/mcu_config_download/" /* Name of file to create in modem file system for the downloaded image. * This is arbitrary, but we name the upper and lower version differently * to avoid possible mixing up at the firmware level (the server can * still mix them up if a lower app was put at the /higher URL) */ #if ST_OTA_HIGHER_APPLICATION /* A running "higher" app must download and install a "lower" app and vice versa. */ #define MCU_FW_UPDATE_FILE "lrsm0005_fw_ota_image_lower.bin" #else #define MCU_FW_UPDATE_FILE "lrsm0005_fw_ota_image_higher.bin" #endif //#define MCU_FW_BIN_FILE_URL1_HIGHER "https://parthasarathimishra.com/hae/azuma/%s/mcu_pgm_download/lrsm0005_fw_ota_image_higher.bin" //#define MCU_FW_BIN_FILE_URL1_LOWER "https://parthasarathimishra.com/hae/azuma/%s/mcu_pgm_download/lrsm0005_fw_ota_image_lower.bin" #define MCU_PROG_VER_URL SERVER_URL_BASE "mcu_pgm_download/version" //#define MODEM_FW_BIN_FILE_URL1 SERVER_URL_BASE "modem_pgm_download" #define MODEM_PROG_VER_URL SERVER_URL_BASE "modem_pgm_download/version" #define WHITELIST_URL SERVER_URL_BASE "whitelist" //#define MCU_FW_BIN_FILE_URL1 "https://parthasarathimishra.com/hae/azuma/%s/mcu_pgm_download/" MCU_FW_UPDATE_FILE //#define MCU_FW_BIN_FILE_URL1 "https://www.parthasarathimishra.com/hae/tempstick/%s/mcu_pgm_download/OTA.bin" //#define MODEM_FW_BIN_FILE_URL1 "https://www.parthasarathimishra.com/hae/tempstick/%s/modem_pgm_download/MOTA.bin"/*upgrade*/ //#define MODEM_FW_BIN_FILE_URL1 "https://www.parthasarathimishra.com/hae/tempstick/%s/modem_pgm_download/Update_BG77LAR02A04_01.009.01.009-R02A04_01.006.01.006.bin"/*downgrade*/ #define MQTT_PUB_TOPIC_LEN 48 #define MCU_CONFIG_FLAG_WHITELIST_UPDATE 0x1 #define MCU_CONFIG_FLAG_MCU_UPDATE 0x2 #define MCU_CONFIG_FLAG_MODEM_UPDATE 0x4 #define HTTP_RETRY_COUNT_MAX 5 #define HTTP_POST_RETRY_MAX 2 #define HTTP_RETRY_WAIT 20000 static const char *TAG = "COMMS"; extern uint32_t g_ConfigUpdate; extern uint32_t g_McuUpdate; extern uint32_t g_ModemUpdate; extern uint32_t g_version; typedef enum { COMMS_EVENT_START, COMMS_EVENT_TIMER, COMMS_EVENT_STOP, COMMS_EVENT_CONNECT, } comms_event_t; /* State of the comms process */ typedef enum { COMMS_STATE_INIT, COMMS_STATE_WAIT_MODEM, COMMS_STATE_WAIT_NET_CONNECT, COMMS_STATE_WIFI_CONNECT, COMMS_STATE_WIFI_POST_REQ, COMMS_STATE_WIFI_GET_REQ, COMMS_STATE_WAIT_HTTP_SEND_CONFIG_FLAGS, COMMS_STATE_WAIT_HTTP_GET_CONFIG_FLAGS, COMMS_STATE_WAIT_HTTP_POST_REQ, COMMS_STATE_WAIT_HTTP_POST_RES, COMMS_STATE_WAIT_HTTP_SEND_SP5, COMMS_STATE_WAIT_HTTP_GET_SP5, COMMS_STATE_WAIT_HTTP_SEND_SP6, COMMS_STATE_WAIT_HTTP_GET_SP6, COMMS_STATE_WAIT_HTTP_GET_MODEM_UPDATE, /* Get modem update version */ COMMS_STATE_WAIT_MODEM_UPDATE, /* Wait for modem to do its thing */ COMMS_STATE_WAIT_HTTP_GET_MCU_UPDATE, /* Get version */ COMMS_STATE_WAIT_HTTP_GET_MCU_FILE, /* Download file */ COMMS_STATE_WAIT_MCU_UPDATE, /* Install update */ COMMS_STATE_GOING_IDLE, COMMS_STATE_IDLE, COMMS_STATE_WAIT, COMMS_STATE_WAIT_MODEM_OFF, } comms_state_t; typedef int (*comms_switch_cb)(comms_state_t init_state, const char* url,const char* msg, comms_state_t success_state); typedef struct { comms_state_t state; /* Timer */ bool poll_timer; /* User start callback */ comms_op_cb_t start_cb; bool is_starting; /* User connect callback */ comms_op_cb_t connect_cb; char mqtt_pub_topic[MQTT_PUB_TOPIC_LEN]; /* Printing an SP2 message: * Header: 3 + 1 + [IMEI-15] +1 + 10 + 1+ 10 + 1 = 42 * [32],[4],[4],[3] = 46 * 20 = 920 * Footer: 3 * 42 + 920 + 3 = 965 * Add buffer overflow protection in writing routines. */ char mqtt_buf[1024]; /* Also general buffer */ //char jwt[JWT_LEN]; uint8_t overflow_check; int mqtt_pub_counter; /* flagged actions to take */ bool get_whitelist; bool get_mcu_update; bool get_modem_update; /* Status of the last communication cycle * OK or ERROR */ int last_cycle_status; /* Status of last pending operation */ bool last_op_success; bool wf1_msg; int httpRetryCnt; comms_state_t http_init_state; } comms_t; /* Unique timer ID for this process for use with timer module */ //#define COMMS_TIMER_ID 1 esp_timer_handle_t comms_timer; /* Local process state */ static comms_t comms; //nvs_handle_t my_handle; extern uint8_t onBoarded; extern uint8_t comms_mode; comms_medium_t comms_medium; static bool comms_do_wifi_backup; static bool comms_do_cell_backup; static bool comms_posting_failed; uint8_t checkin_cycle_counter; uint8_t number_of_check_in_to_do; char jsonMessage[2560]; char http_post_header[250]; #if (FAKE_NETWORK == 1) char server_resp[] = "{\"request\":\"settings\",\"id\":10608508,\"minTemp\":-1.11,\"maxTemp\":26.67,\"minHum\":10,\"maxHum\":80,\"voltageQuit\":2.3,\"alertInterval\":900,\"sendInterval\":60,\"sendDetails\":1,\"postURLNumber\":2,\"postURLMax\":3,\"tmpThA_GP\":71.11,\"tmpThA_GN\":70,\"tmpThB_GP\":71.11,\"tmpThB_GN\":70,\"tmpThC_GP\":71.11,\"tmpThC_GN\":70,\"tmpThD_GP\":-44.44,\"tmpThD_GN\":-45.56,\"tmpThE_GP\":-44.44,\"tmpThE_GN\":-45.56,\"tmpThF_GP\":-44.44,\"tmpThF_GN\":-45.56,\"T_TKN\":5,\"humThA_GP\":103,\"humThA_GN\":101,\"humThB_GP\":103,\"humThB_GN\":101,\"humThC_GP\":103,\"humThC_GN\":101,\"humThD_GP\":-1,\"humThD_GN\":-3,\"humThE_GP\":-1,\"humThE_GN\":-3,\"humThF_GP\":-1,\"humThF_GN\":-3,\"H_TKN\":5,\"TC_M\":1,\"TC_TYPE\":\"K\",\"tcThA_GP\":71.11,\"tcThA_GN\":70,\"tcThB_GP\":71.11,\"tcThB_GN\":70,\"tcThC_GP\":71.11,\"tcThC_GN\":70,\"tcThD_GP\":-168.33,\"tcThD_GN\":-169.44,\"tcThE_GP\":-168.33,\"tcThE_GN\":-169.44,\"tcThF_GP\":-168.33,\"tcThF_GN\":-169.44,\"TC_TKN\":5,\"LT_M\":3,\"LT_LVLGP\":200,\"LT_LVLGN\":50,\"LT_LOCK\":900,\"LT_TKN\":5,\"AC_M\":1,\"AC_LVL\":15000,\"AC_INT\":60,\"AC_LOCK\":60,\"AC_TKN\":5,\"PWR_M\":3,\"PWR_DBNC\":60,\"PWR_TKN\":5,\"PUSH_TKN\":5,\"TKN_RLD\":300}"; #endif /* ------------------------------------------------------------------------- */ static const char* state_str(comms_state_t s) { switch (s) { case COMMS_STATE_INIT:return "INIT"; case COMMS_STATE_WAIT_MODEM:return "WAIT_MODEM"; case COMMS_STATE_WAIT_NET_CONNECT:return "WAIT_NET_CONNECT"; case COMMS_STATE_WIFI_CONNECT:return "WIFI_CONNECT"; case COMMS_STATE_WIFI_POST_REQ:return "WIFI_POST_REQ"; case COMMS_STATE_WIFI_GET_REQ:return "WIFI_GET_REQ"; case COMMS_STATE_WAIT_HTTP_SEND_CONFIG_FLAGS:return "WAIT_HTTP_SEND_CONFIG_FLAGS"; case COMMS_STATE_WAIT_HTTP_GET_CONFIG_FLAGS:return "WAIT_HTTP_GET_CONFIG_FLAGS"; case COMMS_STATE_WAIT_HTTP_POST_REQ:return "WAIT_HTTP_POST_REQ"; case COMMS_STATE_WAIT_HTTP_POST_RES:return "WAIT_HTTP_POST_RES"; case COMMS_STATE_WAIT_HTTP_SEND_SP5:return "WAIT_HTTP_SEND_SP5"; case COMMS_STATE_WAIT_HTTP_GET_SP5:return "HTTP_GET_SP5"; case COMMS_STATE_WAIT_HTTP_SEND_SP6:return "HTTP_SEND_SP6"; case COMMS_STATE_WAIT_HTTP_GET_SP6:return "HTTP_GET_SP6"; case COMMS_STATE_WAIT_HTTP_GET_MODEM_UPDATE:return "WAIT_HTTP_GET_MODEM_UPDATE"; case COMMS_STATE_WAIT_HTTP_GET_MCU_UPDATE:return "WAIT_HTTP_GET_MCU_UPDATE"; case COMMS_STATE_WAIT_HTTP_GET_MCU_FILE:return "WAIT_HTTP_GET_MCU_FILE"; case COMMS_STATE_WAIT_MODEM_UPDATE:return "WAIT_MODEM_UPDATE"; case COMMS_STATE_WAIT_MCU_UPDATE:return "WAIT_MCU_UPDATE"; case COMMS_STATE_GOING_IDLE: return "COMMS_STATE_GOING_IDLE"; case COMMS_STATE_IDLE:return "IDLE"; case COMMS_STATE_WAIT:return "STATE_WAIT"; case COMMS_STATE_WAIT_MODEM_OFF:return "WAIT_MODEM_OFF"; default: return ""; } } static esp_err_t build_http_headerBodyMsg(uint32_t len) { /* jsonMessage address is the same address as msg*/ uint32_t header_len = 0; int index = 0; /* Setup the HTTP header*/ sprintf(http_post_header, HTTP_POST_HEADER,(unsigned int)len); /* Calculate http-header length*/ header_len = strlen(http_post_header); /* Shift jsonMessage right by length of http-header*/ if( (len+header_len)>= 2560) { ESP_LOGI(TAG,"Shifting exceeded the maximum size of jsonMessage buffer"); return ESP_FAIL; } /* Shift the message in jsonMessage buffer to right by length of http-header*/ for(index = len-1; index >= 0; index--) { jsonMessage[index+header_len] = jsonMessage[index]; /* Copy http-header at the beginning of jsonMessage*/ if(index < header_len) jsonMessage[index] = http_post_header[index]; } return ESP_OK; } static void transition(comms_state_t state_to) { ESP_LOGD(TAG,"%s->%s\n", state_str(comms.state), state_str(state_to)); comms.state = state_to; } /* These handlers handle completion events for commands issued by the BG96 modem driver. * If success, the comms process continues by way of a "timer" event. * If fail, the comms process stops what it was doing and goes back to "idle" state. * The comms process is started once at startup and does not stop thereafter. */ static void modem_start_cb(int status) { comms.poll_timer = true; if (MODEM_STATUS_OK == status) { /* started */ transition(COMMS_STATE_WAIT_MODEM); } else { /* Nope - back to init */ ESP_LOGW(TAG,"BG96 startup failed.\r\n"); if(comms_mode == COMMS_OVER_CELL) { hmi_stop_continued_led_state(BLUE_LED_FLASHING); //stop BLUE_LED_FLASHING event if(!onBoarded) //Unable to connect to LTE network { hmi_set_leds_state(RED_LED_FLASHING); } //Unable to connect to LTE network } /* Set the posting_failed to be true */ comms_posting_failed = true; if(COMMS_OVER_CELL_WIFI_BACKUP == comms_mode) { comms_do_wifi_backup = true; } transition(COMMS_STATE_GOING_IDLE); } } //bool net_connected = false; static void net_connect_cb(int status) { //net_connected = true; comms.poll_timer = true; if (MODEM_STATUS_OK == status) { /* connected */ ESP_LOGI(TAG,"Network connection Successful.\r\n"); } else { /* Nope - back to init */ ESP_LOGW(TAG,"Network connection failed.\r\n"); /* Set the posting_failed to be true */ comms_posting_failed = true; if(COMMS_OVER_CELL_WIFI_BACKUP == comms_mode) { comms_do_wifi_backup = true; } if(comms_mode == COMMS_OVER_CELL) { hmi_stop_continued_led_state(BLUE_LED_FLASHING); //stop BLUE_LED_FLASHING event if(!onBoarded) //Unable to connect to LTE network { hmi_set_leds_state(RED_LED_FLASHING); } //Unable to connect to LTE network } transition(COMMS_STATE_GOING_IDLE); } } static void http_op_cb(int status) { if (MODEM_STATUS_OK == status) { /*Connected. Set the poll_timer to be true*/ comms.poll_timer = true; } else { /*If not connected then check the number of http retries if it's greater than zero*/ if(comms.httpRetryCnt) { /*decrement the number of retries by 1*/ comms.httpRetryCnt--; /*start a timer for 20sec*/ esp_timer_start_once(comms_timer, 1000*HTTP_RETRY_WAIT); /*Logging waiting message*/ ESP_LOGI(TAG,"Waiting for another HTTP Retry.\r\n"); /*transition to COMMS_STATE_WAIT state*/ transition(COMMS_STATE_WAIT); } else { /*Reinitialize the counter of http retries with 3*/ comms.httpRetryCnt = HTTP_RETRY_COUNT_MAX; /*Set the poll_timer to be true*/ comms.poll_timer = true; /* Nope - back to idle */ ESP_LOGW(TAG,"HTTP operation failed.\r\n"); //SP1_Mqtt_Tx(heartbeat_time); //creating sp1 message //int retval = start_mqtt_publish_sequence(); /* Run the MQTT publish sequence if nothing else pending */ int retval = MODEM_STATUS_ERROR; if(MODEM_STATUS_OK==retval) { ESP_LOGI(TAG,"MQTT Publish SP1 message success"); } else { ESP_LOGI(TAG,"MQTT Publish SP1 message failed"); } /*transition to COMMS_STATE_GOING_IDLE state*/ transition(COMMS_STATE_GOING_IDLE); } } } static void http_post_op_cb(int status) { if (MODEM_STATUS_OK == status) { comms.poll_timer = true; /* Update the number of already done check-ins */ checkin_cycle_counter++; /* Clear history array (So that its current readings don't affect the readings of the next sector) * Just clear the array (don't clear anything from NVS) */ data_clear_history(); /* Check if this was the last check-in to do (in other words, check if there are no more previous readings to send to server) */ if(checkin_cycle_counter == number_of_check_in_to_do) { /* Reset the last post sector in the NVS partition to 0*/ nvm_set_last_posted_history_sector(0); /* successfully posted. */ ESP_LOGI(TAG,"HTTP post message SUCCESS.\r\n"); /* Clear History sectors * Clear from NVS Partition */ nvm_clear_history_sector(NVM_HISTORY_ALL_SECTORS); /* Reset the posting_failed to be false */ comms_posting_failed = false; comms_do_wifi_backup = false; /*Set the last operation to be completed successfully*/ comms.last_op_success = true; comms.httpRetryCnt = HTTP_RETRY_COUNT_MAX; } else { /* Coming here means that there were some previous readings that are stored in NVS and need to posted in multiple check-in cycles * and we already posted the readings in history_sector x ----> so we need to update the last_posted_sector flag */ /* Update the last post sector in the NVS partition */ uint8_t x = nvm_get_last_posted_history_sector()+1; nvm_set_last_posted_history_sector(x); /* Wait some time before doing the next check-in of the remaining previous readings */ vTaskDelay(2000/portTICK_PERIOD_MS); /* Do a transition to "COMMS_STATE_WAIT_HTTP_POST_REQ" state */ transition(COMMS_STATE_WAIT_HTTP_POST_REQ); } } else { if(comms.httpRetryCnt) { /*decrement the number of retries by 1*/ comms.httpRetryCnt--; /*start a timer for 20sec*/ esp_timer_start_once(comms_timer, 1000*HTTP_RETRY_WAIT); /*Logging waiting message*/ ESP_LOGI(TAG,"Waiting for another HTTP Retry.\r\n"); /*Set the poll_timer to be true*/ comms.poll_timer = true; /*transition to COMMS_STATE_WAIT state*/ transition(COMMS_STATE_WAIT); } else { /*Reinitialize the counter of http_post retries with 3*/ comms.httpRetryCnt = HTTP_POST_RETRY_MAX; /*Set the poll_timer to be true*/ comms.poll_timer = true; /* Nope - back to idle */ /* failed. */ ESP_LOGW(TAG,"HTTP post message FAILED.\r\n"); comms.last_op_success = false; /* Give Red-led indication*/ if(comms_mode == COMMS_OVER_CELL) { hmi_stop_continued_led_state(BLUE_LED_FLASHING); //stop BLUE_LED_FLASHING event if(!onBoarded) //Unable to connect to LTE network { hmi_set_leds_state(RED_LED_FLASHING); } //Unable to connect to LTE network } /* alternating between three servers * * transition to COMMS_STATE_GOING_IDLE state if the connection to the servers failed*/ switch(data_get_postToServer()){ case TEMPSTICK_SERVER1: if( 1 == data_get_postUrlMax()) { ESP_LOGI(TAG,"Just one server available"); /* Set the posting_failed to be true */ comms_posting_failed = true; /* Do wifi backup for the check-in process */ if(COMMS_OVER_CELL_WIFI_BACKUP == comms_mode) { comms_do_wifi_backup = true; } transition(COMMS_STATE_GOING_IDLE); } else { data_set_postToServer(TEMPSTICK_SERVER2); ESP_LOGI(TAG,"Transition to the next server --> %d",TEMPSTICK_SERVER2); transition(COMMS_STATE_WAIT_HTTP_POST_REQ); } break; case TEMPSTICK_SERVER2: if( 2 == data_get_postUrlMax()) { ESP_LOGI(TAG,"Just two servers available"); /* Set the posting_failed to be true */ comms_posting_failed = true; /* Do wifi backup for the check-in process */ if(COMMS_OVER_CELL_WIFI_BACKUP == comms_mode) { comms_do_wifi_backup = true; } transition(COMMS_STATE_GOING_IDLE); } else { data_set_postToServer(TEMPSTICK_SERVER3); ESP_LOGI(TAG,"Transition to the next server --> %d",TEMPSTICK_SERVER3); transition(COMMS_STATE_WAIT_HTTP_POST_REQ); } break; case TEMPSTICK_SERVER3: data_set_postToServer(TEMPSTICK_SERVER1); ESP_LOGI(TAG,"Transition to default server --> %d then going to IDLE",TEMPSTICK_SERVER1); /* Set the posting_failed to be true */ comms_posting_failed = true; /* Do wifi backup for the check-in process */ if(COMMS_OVER_CELL_WIFI_BACKUP == comms_mode) { comms_do_wifi_backup = true; } transition(COMMS_STATE_GOING_IDLE); break; default: data_set_postToServer(TEMPSTICK_SERVER1); ESP_LOGI(TAG,"connection to servers Failed"); ESP_LOGI(TAG,"Transition to default server --> %d then going to IDLE",TEMPSTICK_SERVER1); /* Set the posting_failed to be true */ comms_posting_failed = true; /* Do wifi backup for the check-in process */ if(COMMS_OVER_CELL_WIFI_BACKUP == comms_mode) { comms_do_wifi_backup = true; } transition(COMMS_STATE_GOING_IDLE); break; } } } } static void fotadl_op_cb(int status) { comms.poll_timer = true; if (MODEM_STATUS_OK == status) { /* completed. */ ESP_LOGI(TAG,"Modem upgrade SUCCESS.\r\n"); } else { if(comms.httpRetryCnt) { /*decrement the number of retries by 1*/ comms.httpRetryCnt--; /*start a timer for 20sec*/ esp_timer_start_once(comms_timer, 1000*HTTP_RETRY_WAIT); /*Logging waiting message*/ ESP_LOGI(TAG,"Waiting for another HTTP Retry.\r\n"); /*Set the poll_timer to be true*/ comms.poll_timer = true; /*transition to COMMS_STATE_WAIT state*/ transition(COMMS_STATE_WAIT); } else { /*Reinitialize the counter of http retries with 3*/ comms.httpRetryCnt = HTTP_RETRY_COUNT_MAX; /*Set the poll_timer to be true*/ comms.poll_timer = true; /* Nope - back to idle */ /* failed. */ /* failed. */ /* failed. */ ESP_LOGW(TAG,"Modem upgrade FAILED.\r\n"); /* Give Red-led indication*/ if(comms_mode == COMMS_OVER_CELL) { hmi_stop_continued_led_state(BLUE_LED_FLASHING); //stop BLUE_LED_FLASHING event if(!onBoarded) //Unable to connect to LTE network { hmi_set_leds_state(RED_LED_FLASHING); } //Unable to connect to LTE network } transition(COMMS_STATE_GOING_IDLE); } /* Let state handle it */ } } static int start_http_get_request(comms_state_t init_state,const char* url, const char* log_msg, comms_state_t success_state) { /* Reset the operation status flag */ comms.last_op_success = false; /* Initialize the comms.http_init_state to init_state */ comms.http_init_state = init_state; /* Now make the GET request. */ /* Setup URL */ memset(comms.mqtt_buf, 0, sizeof(comms.mqtt_buf)); snprintf(comms.mqtt_buf, sizeof(comms.mqtt_buf), url, modem_get_imei()); /* Download the GET data to modem */ int retval = modem_http_get_to_buf(http_op_cb, comms.mqtt_buf); if (retval == MODEM_STATUS_OK) { ESP_LOGI(TAG,"GET %s\r\n", log_msg); transition(success_state); } else { ESP_LOGE(TAG,"GET %s failed.\r\n", log_msg); comms.poll_timer = true; /* Give Red-led indication*/ if(comms_mode == COMMS_OVER_CELL) { hmi_stop_continued_led_state(BLUE_LED_FLASHING); //stop BLUE_LED_FLASHING event if(!onBoarded) //Unable to connect to LTE network { hmi_set_leds_state(RED_LED_FLASHING); } //Unable to connect to LTE network } transition(COMMS_STATE_GOING_IDLE); } return retval; } static int start_http_post_request(comms_state_t init_state,const char* url, const char* message, comms_state_t success_state) { esp_err_t ret; /* Reset the operation status flag */ comms.last_op_success = false; /* Initialize the comms.http_init_state to init_state */ comms.http_init_state = init_state; /* Setup URL */ memset(comms.mqtt_buf, 0, sizeof(comms.mqtt_buf)); snprintf(comms.mqtt_buf, sizeof(comms.mqtt_buf), url, modem_get_imei()); //sprintf(http_post_header,HTTP_POST_HEADER,(uint32_t)strlen(message)); /*concatenate http-header with http-body*/ //strcat(http_post_header,message); /* Build the headerBody of the http-post message*/ ret = build_http_headerBodyMsg((uint32_t)strlen(jsonMessage)); //ret = ESP_OK; if(ESP_OK == ret) { /* Send HTTP POST data to modem to upload it to server*/ int retval = modem_http_post_message(http_post_op_cb, comms.mqtt_buf, message); if (retval == MODEM_STATUS_OK) { ESP_LOGI(TAG,"HTTP-POST Started\r\n"); transition(success_state); } else { ESP_LOGE(TAG,"HTTP-POST failed to proceed\r\n"); } return retval; } else { ESP_LOGI(TAG,"Failed to build header-body of http-post message"); return MODEM_STATUS_ERROR; } } static void fwdl_op_cb(int status) { if (MODEM_STATUS_OK == status) { /* Firmware file was downloaded to the modem. */ ESP_LOGI(TAG,"MCU FW download SUCCESS.\r\n"); comms.last_op_success = true; /* Continue in the current state */ comms.poll_timer = true; } else { if(comms.httpRetryCnt) { /*decrement the number of retries by 1*/ comms.httpRetryCnt--; /*start a timer for 20sec*/ esp_timer_start_once(comms_timer, 1000*HTTP_RETRY_WAIT); /*Logging waiting message*/ ESP_LOGI(TAG,"Waiting for another HTTP Retry.\r\n"); /*transition to COMMS_STATE_WAIT state*/ transition(COMMS_STATE_WAIT); } else { /*Reinitialize the counter of http retries with 3*/ comms.httpRetryCnt = HTTP_RETRY_COUNT_MAX; /*Set the poll_timer to be true*/ comms.poll_timer = true; /* Nope - back to idle */ /* Firmware file not downloaded. */ ESP_LOGW(TAG,"MCU FW download operation failed.\r\n"); //SP1_Mqtt_Tx(heartbeat_time); //creating sp1 message // int retval = start_mqtt_publish_sequence(); /* Run the MQTT publish sequence if nothing else pending */ int retval = MODEM_STATUS_ERROR; if(MODEM_STATUS_OK==retval) { ESP_LOGI(TAG,"MQTT Publish SP1 message success"); } else { ESP_LOGI(TAG,"MQTT Publish SP1 message failed"); } comms.last_op_success = false; /*transition to COMMS_STATE_GOING_IDLE state*/ transition(COMMS_STATE_GOING_IDLE); } } } static void fwupd_op_cb(int status) { comms.poll_timer = true; if (MODEM_STATUS_OK == status) { /* Firmware file was installed into device. */ ESP_LOGI(TAG,"MCU FW update SUCCESS.\r\n"); comms.last_op_success = true; } else { /* Firmware file not installed. */ ESP_LOGW(TAG,"MCU FW installation failed.\r\n"); transition(COMMS_STATE_GOING_IDLE); comms.poll_timer = true; comms.last_op_success = false; } } /* ------------------------------------------------------------------------- */ /* OTA firmware update. * These callbacks handle the file transfer from the modem and interface with * the OTA_btl firmware update system. * * The main interface is the OTA_Offline_Init and OTA_Offline_Data functions. * These are added to interface with the stock OTA_btl update engine. * * To initialize, we use OTA_Offline_Init(file_size) API. * This will either accept or reject the firmware image based on * available space. * * To feed update data, call OTA_Offline_Data with a chunk of data. * * Be mindful of the return values and feed them back to the updater engine. * */ static int ota_file_open_cb(uint32_t fileSize) { int retval = MODEM_STATUS_OK; esp_err_t res = ota_init(fileSize); if (ESP_OK == res) { ESP_LOGI(TAG,"OTA file opened\r\n"); } else { ESP_LOGI(TAG,"OTA file open error: %d\r\n", res); /* This will abort the entire update process. */ retval = MODEM_STATUS_ERROR; } return retval; } static int ota_file_data_cb(const char* buf, int buf_len) { int retval = MODEM_STATUS_OK; /* Data callback: we can receive a buffer up to MODEM_FREAD_SIZE bytes */ esp_err_t res = ota_get_data_to_buffer(buf, buf_len); if (ESP_OK == res) { ESP_LOGI(TAG,"%d bytes OTA data processed\r\n", buf_len); } else { ESP_LOGI(TAG,"%d bytes OTA data error: %d\r\n", buf_len, res); /* This will abort the entire update process. */ retval = MODEM_STATUS_ERROR; } return retval; } static int sum_digits(int digit) { int sum = 0; while (digit > 0) { sum = sum + digit % 10; digit = digit / 10; } return sum; } /** This function is used to check if IMEI has correct length (15) to check if IMEI has numerical values (0-9) to check if the parsed IMEI is same as hardware IMEI to check if IMEI is valid by help of luhn algorithm https://www.geeksforgeeks.org/luhn-algorithm/ */ static bool imei_check_valid(char *message_imei) { //find the length of message imei int len = strlen(message_imei); int sum = 0; ESP_LOGI(TAG,"IMEI : %s",message_imei); //check length of imei field if (len != 15){ //invalid IMEI ESP_LOGW(TAG,"Invalid IMEI length"); return false; } if(!strcmp(message_imei,modem_get_imei())){ for(int i = len-1 ; i >= 0; i--) { //check if message imei fields contain numbers (0-9) if((message_imei[i] > 47) && (message_imei[i] < 58)){ int digit = (message_imei[i] - 48); // Doubling every alternate beginning at [13] digit //ignore last number [14] and first number [0] as well if (i % 2 != 0) digit = 2 * digit; // Finding sum of the digits // if digit*2 is a two digit number add the two digits sum += sum_digits(digit); } else{ ESP_LOGW(TAG,"Invalid IMEI (not numerical values)"); return false; } } } else{ ESP_LOGI(TAG,"Message IMEI doesn't match board IMEI"); return false; } return (sum % 10 == 0); } void check_for_update(){ if(g_ConfigUpdate==true){ // get the data from server //transition(); comms.poll_timer=true; /* just for a test*/ transition(COMMS_STATE_GOING_IDLE); /* just for a test*/ } else if(g_McuUpdate==true){ // that mean we should check for program update //transition(); comms.poll_timer=true; /* just for a test*/ transition(COMMS_STATE_WAIT_HTTP_SEND_SP5); /* just for a test*/ } else if(g_ModemUpdate==true){ // that mean we need to update the modem software. comms.poll_timer=true; transition(COMMS_STATE_WAIT_HTTP_SEND_SP6); } else { comms.poll_timer=true; transition(COMMS_STATE_GOING_IDLE); } } /* function for parsing SP5 message */ // format example /*SP5 IMEI epoch T FW_V EP */ /* | | | | | */ /* | | | | | */ /*SP5 866349048889004 1676395843 FW_2002 EP */ static void Comms_Parse_SP5(char *buf, int len) { char messageheader[4] = {0}; /*ex: SPx*/ char messageIMEI[15] = {0}; // char messageIMEI[] = "866349048890473";/*//hard coded IMEI*/ char epochTime[30] = {0}; char firmware_version[10] = {0}; char *strret = NULL; uint32_t new_fw_version = 0; char epcheck[2] = {0}; int ret_sp5 = COMMS_STATUS_ERROR; /**********************************************************************************************************/ /*SP5*/ strret = strtok(buf, " "); strcpy(messageheader, strret); ESP_LOGI(TAG,"%s message is received",messageheader); /**********************************************************************************************************/ /*IMEI*/ strret = strtok (NULL," "); strcpy(messageIMEI, strret); ret_sp5 = imei_check_valid(messageIMEI); if(ret_sp5 != false){ //ok IMEI ESP_LOGI(TAG,"Fetched IMEI matches board"); } else{ ESP_LOGW(TAG,"INVALID IMEI"); comms.poll_timer = true; transition(COMMS_STATE_GOING_IDLE); return; //return ret_sp5; } /**********************************************************************************************************/ /*epoch time*/ strret = strtok (NULL," "); strcpy(epochTime, strret); ESP_LOGI(TAG,"epoch Time : %s",epochTime); /**********************************************************************************************************/ /*new FW version*/ strret = strtok(NULL, "FW_"); strcpy(firmware_version,strret); new_fw_version = (uint32_t)atoi(firmware_version); ESP_LOGI(TAG,"Firmware version from SP5: %ld",new_fw_version); //logging/printing FR_version message for tracing ESP_LOGI(TAG,"Board Firmware version: %ld",g_version); /**********************************************************************************************************/ /*EP*/ /* strret = strtok (NULL," "); strcpy(epcheck, strret); if(!strcmp(epcheck,"EP\"") || !strcmp(epcheck,"EP")){ ESP_LOGI(TAG,"(%s) %s message is terminated", epcheck,messageheader); } else{ ESP_LOGI(TAG,"(%s) %s message is not terminated!!", epcheck,messageheader); }*/ /**********************************************************************************************************/ /*check if the new version is greater than current version*/ if(!(new_fw_version > g_version)) { ESP_LOGI(TAG,"MCU F/W UP TO DATE"); /*if its not check if modem update needed*/ /*read ModemFlag*/ if(g_ModemUpdate == true) { ESP_LOGI(TAG,"Going to state COMMS_STATE_WAIT_HTTP_SEND_SP6"); comms.poll_timer = true; transition(COMMS_STATE_WAIT_HTTP_SEND_SP6); } else { /* */ comms.poll_timer = true; transition(COMMS_STATE_GOING_IDLE); } } else { /*Logging/printing this message*/ ESP_LOGI(TAG,"F/W Update NEEDED"); ESP_LOGI(TAG,"GET MCU UPDATE"); comms.poll_timer = true; transition(COMMS_STATE_WAIT_HTTP_GET_MCU_UPDATE); /*reading OTA files*/ } } /* function for parsing SP6 message */ // format example /*SP6 IMEI epoch T FW_V EP */ /* | | | | | */ /* | | | | | */ /*SP6 866349048889004 1676395909 BG77LAR02A04_01.009.01.009 EP */ static void Comms_Parse_SP6(char *buf, int len) { char messageheader[4] = {'0'}; /*ex: SPx*/ char messageIMEI[15] = {'0'}; // char messageIMEI[] = "866349048890473";/*//hard coded IMEI*/ char epochTime[30] = {'0'}; char modem_sp6_fwv[50] = {'0'}; int ret_sp6 = COMMS_STATUS_ERROR; char* strret = NULL; char epcheck[2] = {0}; /**********************************************************************************************************/ /*SP6*/ strret = strtok(buf, " "); strcpy(messageheader, strret); ESP_LOGI(TAG,"%s message is received",messageheader); /**********************************************************************************************************/ /*IMEI*/ strret = strtok (NULL," "); strcpy(messageIMEI, strret); ret_sp6 = imei_check_valid(messageIMEI); if(ret_sp6 != false){ //ok IMEI ESP_LOGI(TAG,"Fetched IMEI matches board"); } else{ ESP_LOGW(TAG,"INVALID IMEI!!"); comms.poll_timer = true; transition(COMMS_STATE_GOING_IDLE); return; } /**********************************************************************************************************/ /*epoch Time*/ strret = strtok (NULL," "); strcpy(epochTime, strret); ESP_LOGI(TAG,"epoch Time : %s",epochTime); /**********************************************************************************************************/ /*modem version from SP6 */ strret = strtok (NULL," "); strcpy(modem_sp6_fwv, strret); ESP_LOGI(TAG,"Board modem firmware version: %s",modem_get_fw_ver()); ESP_LOGI(TAG,"Modem firmware version from SP6: %s",modem_sp6_fwv); /**********************************************************************************************************/ /*EP*/ strret = strtok (NULL," "); strcpy(epcheck, strret); if(!strcmp(epcheck,"EP\"") || !strcmp(epcheck,"EP")){ ESP_LOGI(TAG,"(%s) %s message is terminated",epcheck,messageheader); } else{ ESP_LOGI(TAG,"(%s) %s message is not terminated!!",epcheck,messageheader); } /**********************************************************************************************************/ /*Case: str1 SP6 fw: BG77LAR02A04_01.009.01.009 str2 fw: BG77LAR02A04_01.008.01.008 9 is the first non-matching character in str1 greater than that of str2. return > 0(update needed) str1 SP6 fw: BG77LAR02A04_01.008.01.008 str2 fw: BG77LAR02A04_01.009.01.009 '9' is the first non-matching character in str1 lower than that of str2. return < 0 */ if(strcmp(modem_sp6_fwv,modem_get_fw_ver()) <= 0) { /*If the existing version is the same go to idle*/ comms.poll_timer = true; ESP_LOGI(TAG,"No update need GOING TO IDLE FROM SP6"); transition(COMMS_STATE_GOING_IDLE); } else { /*Logging/printing this message*/ ESP_LOGI(TAG,"F/W Modem Update NEEDED"); ESP_LOGI(TAG,"GET MODEM UPDATE"); comms.poll_timer = true; transition(COMMS_STATE_WAIT_HTTP_GET_MODEM_UPDATE); } } esp_err_t comms_http_request(comms_switch_cb cb,comms_state_t init_state, const char* msg, comms_state_t success_state,const char* url1,const char* url2,const char* url3){ esp_err_t retval = ESP_FAIL; int32_t val=data_get_postToServer(); switch(val){ case TEMPSTICK_SERVER1: /* make the get/post request to server 1. */ //ESP_LOGI(TAG,"get/post request to server 1........... "); retval = cb(init_state, url1,msg, success_state); break; case TEMPSTICK_SERVER2: /* make the get/post request to server 2. */ //ESP_LOGI(TAG,"get/post request to server 2........... "); retval = cb(init_state, url2, msg, success_state); break; case TEMPSTICK_SERVER3: /* make the get/post request to server 3. */ //ESP_LOGI(TAG,"get/post request to server 3........... "); retval = cb(init_state, url3,msg, success_state); break; default: data_set_postToServer(TEMPSTICK_SERVER1); ESP_LOGI(TAG,"connection to server %ld failed ",data_get_postToServer()); ESP_LOGI(TAG,"connect to the default server "); comms.poll_timer=true; transition(init_state); break; } return retval; } /* ------------------------------------------------------------------------- */ /*Handler for COMMS timer*/ static void timer_handler(void* context) { comms.poll_timer = true; } static int state_machine(comms_event_t evt) { int retval = COMMS_STATUS_OK; switch (comms.state) { case COMMS_STATE_INIT: if (evt == COMMS_EVENT_START) { /* Set the number of check-in cycles to do and reset the checkin_cycle_counter */ number_of_check_in_to_do = nvm_get_last_written_history_sector() - nvm_get_last_posted_history_sector(); checkin_cycle_counter = 0; ESP_LOGI(TAG,"---------> Number of check-in cycles to do is %d",number_of_check_in_to_do); /* Reset the backup flag */ comms_do_wifi_backup = false; comms_do_cell_backup = false; /* Status is ERROR until cleared by successful completion. */ comms.last_cycle_status = COMMS_STATUS_ERROR; /*This must be changed to true inside modem_start_cb to transfer to the next state*/ comms.poll_timer = false; if (modem_is_started()) { modem_start_cb(MODEM_STATUS_OK); } else { /* start the bg96 process */ retval = modem_start(modem_start_cb); if (retval == MODEM_STATUS_OK) { comms.is_starting = true; ESP_LOGI(TAG,"Process starting.\n"); transition(COMMS_STATE_WAIT_MODEM); } } } break; case COMMS_STATE_WAIT_MODEM: /* Wait for BG96 startup event */ if (evt == COMMS_EVENT_TIMER) { #if (FAKE_NETWORK == 1) data_parse_http_response(server_resp); comms.poll_timer = true; comms.last_cycle_status = COMMS_STATUS_OK; transition(COMMS_STATE_GOING_IDLE); #else /* Start the LED-event of connecting to network */ if(!comms_do_cell_backup) { hmi_set_leds_state(BLUE_LED_FLASHING); //connecting to LTE network } /* Check if need to do check-in over WIFI */ if((COMMS_OVER_CELL != comms_mode) && (COMMS_OVER_CELL_WIFI_BACKUP != comms_mode) && (!comms_do_cell_backup)) { comms.poll_timer = true; transition(COMMS_STATE_WIFI_CONNECT); break; } if(comms_do_cell_backup) comms_do_cell_backup = false; /* modem is started. connect to network */ retval = modem_network_connect(net_connect_cb); if (retval == MODEM_STATUS_OK) { /* Set the communication_medium flag to be CELL */ comms_medium = COMMS_MEDIUM_CELL; ESP_LOGI(TAG,"LTE Connecting to Cellular network\r\n"); transition(COMMS_STATE_WAIT_NET_CONNECT); } #endif } break; case COMMS_STATE_WAIT_NET_CONNECT: /* Wait for BG96 network connect event */ if (evt == COMMS_EVENT_TIMER) { ESP_LOGI(TAG,"Network connected\r\n"); comms.httpRetryCnt = HTTP_RETRY_COUNT_MAX; /* Network connected */ comms.poll_timer = true; comms.last_cycle_status = COMMS_STATUS_OK; comms.httpRetryCnt = HTTP_POST_RETRY_MAX; //Setting the number of http_post retries transition(COMMS_STATE_WAIT_HTTP_POST_REQ); } break; case COMMS_STATE_WIFI_CONNECT: if(evt == COMMS_EVENT_TIMER) { /* Set the communication_medium flag to be WIFI */ comms_medium = COMMS_MEDIUM_WIFI; /* Initialize the wifi */ retval = wifi_first_init(); /* If the initialization retval is OK then continue to connect to the registered WIFI access-point */ if(retval == WIFI_OK) { /* Connect to the registered WIFI access-point */ retval = Connect_wifi_sta(WIFI_CLIENT_MODE); /* if the connection retval is OK then jump to the "WIFI_POST_REQ" state */ if(retval == WIFI_OK) { /* Do a transition to "WIFI_POST_REQ" */ transition(COMMS_STATE_WIFI_POST_REQ); } else { /* Print this Log */ ESP_LOGI(TAG,"Failed to connect to the WIFI access-point"); /* Set the posting_failed to be true */ comms_posting_failed = true; /* Do cellular backup for the check-in process */ if(COMMS_OVER_WIFI_CELL_BACKUP) { comms_do_cell_backup = true; } /* Do a transition to "GOING_IDLE" state */ transition(COMMS_STATE_GOING_IDLE); } } else { /* Print this Log */ ESP_LOGI(TAG,"Failed to initialize the WIFI"); /* Set the posting_failed to be true */ comms_posting_failed = true; /* Do cellular backup for the check-in process */ if(COMMS_OVER_WIFI_CELL_BACKUP) { comms_do_cell_backup = true; } /* Do a transition to "GOING_IDLE" state */ transition(COMMS_STATE_GOING_IDLE); } /* Set poll_timer to true to allow executing whatever next state */ comms.poll_timer = true; } break; case COMMS_STATE_WIFI_POST_REQ: if(evt == COMMS_EVENT_TIMER) { /* Get the address of the receiving buffer */ char *buf = modem_get_rxbuf(); /* Do WIFI post-request for the CHECK_IN message * (Creating the check-in string is done internally inside this function) * (Also, Switching between the 3-servers are done inside this function) */ retval = http_client_do_post_request(jsonMessage,buf); /* check whether POST-Req was successful and managed to receive/parse server-response or not*/ if(retval == WIFI_OK) { /* Update the number of already done check-ins */ checkin_cycle_counter++; /* Clear history array (So that its current readings don't affect the readings of the next sector) * Just clear the array (don't clear anything from NVS) */ data_clear_history(); /* Check if this was the last check-in to do (in other words, check if there are no more previous readings to send to server) */ if(checkin_cycle_counter == number_of_check_in_to_do) { /* Close the connection of http-post */ http_client_post_stop(); /* Reset the last post sector in the NVS partition to 0*/ nvm_set_last_posted_history_sector(0); /* Clear History sectors * Clear from NVS Partition */ nvm_clear_history_sector(NVM_HISTORY_ALL_SECTORS); /* Print the POST server response */ ESP_LOGI(TAG,"HTTP-POST response is :\n%s\n",buf); /* Parse the server-response */ data_parse_http_response((const char*)buf); /* Reset the posting_failed to be false */ comms_posting_failed = false; /* Don't do cellular backup */ comms_do_cell_backup = false; /* Do a transition to "WIFI_GET_REQ" state */ transition(COMMS_STATE_WIFI_GET_REQ); } else { /* Coming here means that there were some previous readings that are stored in NVS and need to posted in multiple check-in cycles * and we already posted the readings in history_sector x ----> so we need to update the last_posted_sector flag */ /* Update the last post sector in the NVS partition */ uint8_t x = nvm_get_last_posted_history_sector()+1; nvm_set_last_posted_history_sector(x); /* Wait some time before doing the next check-in of the remaining previous readings */ vTaskDelay(2000/portTICK_PERIOD_MS); } } else { /* Close the connection of http-post */ http_client_post_stop(); /* Print this Log */ ESP_LOGI(TAG,"Failed to do WIFI POST-Request"); /* Set the posting_failed to be true */ comms_posting_failed = true; /* Do cellular backup for the check-in process */ if(COMMS_OVER_WIFI_CELL_BACKUP) { comms_do_cell_backup = true; } /* Do a transition to "GOING_IDLE" state */ transition(COMMS_STATE_GOING_IDLE); } /* Set poll_timer to true to allow executing whatever next state */ comms.poll_timer = true; } break; case COMMS_STATE_WIFI_GET_REQ: if(evt == COMMS_EVENT_TIMER) { /* Get the address of the receiving buffer */ char *buf = modem_get_rxbuf(); /* Do WIFI get-request for the SP messages * Parsing SP5 message and checking the firmware version is done internally inside this function * (Also, Starting WIFI-OTA session is done internally inside this function) * (Also, Switching between the 3-servers are done inside this function) * (Also, Parsing the server-response -if get request succeeded- is done internally inside this function */ retval = http_client_do_get_request(GET_CONFIGURATIONS,(char*)modem_get_imei(),buf); /* check whether GET-Req was successful and managed to receive/parse server-response or not*/ if(retval != WIFI_OK) { /* Print this Log */ ESP_LOGI(TAG,"Failed to do GET-Request"); } /* Set poll_timer to true to allow executing whatever next state */ comms.poll_timer = true; /* Do a transition to "GOING_IDLE" state */ transition(COMMS_STATE_GOING_IDLE); } break; case COMMS_STATE_WAIT_HTTP_SEND_CONFIG_FLAGS: /* Wait for BG96 HTTP setup event */ if (evt == COMMS_EVENT_TIMER) { retval= comms_http_request(start_http_get_request,COMMS_STATE_WAIT_HTTP_SEND_CONFIG_FLAGS,"configuration flags",COMMS_STATE_WAIT_HTTP_GET_CONFIG_FLAGS,MCU_GET_CONFIG_FLAGS_URL1,MCU_GET_CONFIG_FLAGS_URL2,MCU_GET_CONFIG_FLAGS_URL3); } break; case COMMS_STATE_WAIT_HTTP_GET_CONFIG_FLAGS: /* Wait for BG96 HTTP GET config event */ if (evt == COMMS_EVENT_TIMER) { /* Get the buffer and process the configuration. */ int len = 0; char* buf = 0; retval = modem_http_get_buf(&buf, &len); if (retval == MODEM_STATUS_OK) { ESP_LOGI(TAG,"CONFIG BUF :\n%s\n",buf); /// Parsing config ........ retval = data_parsing_config(buf,len); if(!retval){ //if parsing success check update flags g_ConfigUpdate, g_McuUpdate, g_ModemUpdate. ESP_LOGI(TAG,"config Parsing success"); check_for_update(); } else { ESP_LOGI(TAG,"config Parsing Failed"); } } else{ ESP_LOGI(TAG,"Modem get buff Failed (GET_CONFIG_FLAGS state)"); comms.poll_timer= true; transition(COMMS_STATE_GOING_IDLE); } } break; case COMMS_STATE_WAIT_HTTP_POST_REQ: if(evt == COMMS_EVENT_TIMER) { //suceesUrl = 1 data_create_checkin_string(jsonMessage, sizeof(jsonMessage)); retval=comms_http_request(start_http_post_request,COMMS_STATE_WAIT_HTTP_POST_REQ,jsonMessage,COMMS_STATE_WAIT_HTTP_POST_RES,MCU_POST_URL1,MCU_POST_URL2,MCU_POST_URL3); } break; case COMMS_STATE_WAIT_HTTP_POST_RES: /* Wait for BG96 HTTP GET config event */ if (evt == COMMS_EVENT_TIMER) { /* Get the buffer and process the configuration. */ int len = 0; char* buf = 0; retval = modem_http_get_buf(&buf, &len); if (retval == MODEM_STATUS_OK) { ESP_LOGI(TAG,"HTTP-POST response is :\n%s\n",buf); data_parse_http_response((const char *)buf); //comms_update_onboarding_status(); if(NVM_ONBOARDING_NOT_SET_VAL != nvm_read_onboarding_flag(CELL_ONBOARDING_KEY)) { nvm_write_onboarding_flag(CELL_ONBOARDING_KEY,NVM_ONBOARDING_SET_VAL); } comms.poll_timer= true; transition(COMMS_STATE_WAIT_HTTP_SEND_CONFIG_FLAGS); } else{ comms.poll_timer= true; transition(COMMS_STATE_GOING_IDLE); } } break; case COMMS_STATE_WAIT_HTTP_SEND_SP5: /* Wait for comms timer event */ if (evt == COMMS_EVENT_TIMER) { /* Now make the GET request. */ retval = comms_http_request(start_http_get_request,COMMS_STATE_WAIT_HTTP_SEND_SP5,"McuUpdate",COMMS_STATE_WAIT_HTTP_GET_SP5,MCU_FW_VERSION_URL1,MCU_FW_VERSION_URL2,MCU_FW_VERSION_URL3); } break; case COMMS_STATE_WAIT_HTTP_GET_SP5: /* Wait for BG96 HTTP GET config event */ if (evt == COMMS_EVENT_TIMER) { /* Get the buffer and process the configuration. */ int len = 0; char* buf = 0; retval = modem_http_get_buf(&buf, &len); if (retval == MODEM_STATUS_OK) { ESP_LOGI(TAG,"SP5 BUF: %s",buf); //SP5 parsing... Comms_Parse_SP5(buf, len); } else { ESP_LOGI(TAG,"SP5 Parsing Failed"); comms.poll_timer = true; transition(COMMS_STATE_GOING_IDLE); } } break; case COMMS_STATE_WAIT_HTTP_SEND_SP6: /* Wait for comms timer event */ if (evt == COMMS_EVENT_TIMER) { /* Now make the GET request. */ retval = comms_http_request(start_http_get_request,COMMS_STATE_WAIT_HTTP_SEND_SP6,"ModemUpdate",COMMS_STATE_WAIT_HTTP_GET_SP6,MODEM_FW_VERSION_URL1,MODEM_FW_VERSION_URL2,MODEM_FW_VERSION_URL3); } break; case COMMS_STATE_WAIT_HTTP_GET_SP6: /* Wait for BG96 HTTP GET config event */ if (evt == COMMS_EVENT_TIMER) { /* Get the buffer and process the configuration. */ int len = 0; char* buf = 0; retval = modem_http_get_buf(&buf, &len); if (retval == MODEM_STATUS_OK) { ESP_LOGI(TAG,"SP6 BUF: %s",buf); //SP6 parsing... Comms_Parse_SP6(buf, len); } else { ESP_LOGI(TAG,"SP6 Parsing Failed"); comms.poll_timer = true; transition(COMMS_STATE_GOING_IDLE); } } break; case COMMS_STATE_WAIT_HTTP_GET_MODEM_UPDATE: /* Wait for BG96 HTTP GET modem update event */ if (evt == COMMS_EVENT_TIMER) { comms.get_modem_update = false; /* Get the buffer and process the configuration. */ int len = 0; char* buf = 0; retval = modem_http_get_buf(&buf, &len); if (retval == MODEM_STATUS_OK) { // if (COMMS_STATUS_OK == check_modem_update(buf, len)) { /* Different firmware on server. Use it. */ /* Setup URL */ memset(comms.mqtt_buf, 0, sizeof(comms.mqtt_buf)); switch(data_get_postToServer()){ case TEMPSTICK_SERVER1: /* make the POST request to server 1. */ ESP_LOGI(TAG,"Get Modem bin file from server 1"); snprintf(comms.mqtt_buf, sizeof(comms.mqtt_buf), MODEM_FW_BIN_FILE_URL1, modem_get_imei()); break; case TEMPSTICK_SERVER2: /* make the POST request to server 2. */ ESP_LOGI(TAG,"Get Modem bin file from server 2"); snprintf(comms.mqtt_buf, sizeof(comms.mqtt_buf), MODEM_FW_BIN_FILE_URL2, modem_get_imei()); break; case TEMPSTICK_SERVER3: /* make the POST request to server 3. */ ESP_LOGI(TAG,"Get Modem bin file from server 3"); snprintf(comms.mqtt_buf, sizeof(comms.mqtt_buf), MODEM_FW_BIN_FILE_URL3, modem_get_imei()); break; } /* Download the GET data to modem */ int retval = modem_update_modem(fotadl_op_cb, comms.mqtt_buf); if (retval == MODEM_STATUS_OK) { hmi_set_leds_state(BLUE_LED_FLASHING_OTA); ESP_LOGI(TAG,"FOTADL started\r\n"); transition(COMMS_STATE_WAIT_MODEM_UPDATE); break; } else { ESP_LOGE(TAG,"FOTADL failed to start\r\n"); /* Continue with session */ } } } } break; case COMMS_STATE_WAIT_MODEM_UPDATE: /* Wait for modem update callback. */ if (evt == COMMS_EVENT_TIMER) { /* In either case, stop the comm process. We want to connect again to do the uplink, * and we can do that by returning "UPDATED" status, allowing main * to schedule another connection attempt right away - if desired. */ comms.last_cycle_status = COMMS_STATUS_UPDATED; comms.poll_timer = true; /* request state machine to be polled again right away in new state */ hmi_stop_ota_event(); transition(COMMS_STATE_GOING_IDLE); } break; case COMMS_STATE_WAIT_HTTP_GET_MCU_UPDATE: /* Set http_init_state to COMMS_STATE_WAIT_HTTP_GET_MCU_UPDATE */ comms.http_init_state = COMMS_STATE_WAIT_HTTP_GET_MCU_UPDATE; /* Wait for BG96 HTTP GET MCU update event */ //if (evt == COMMS_EVENT_TIMER) { comms.get_mcu_update = false; /* Get the buffer and process the MCU fw version message. */ //int len = 0; //char* buf = 0; //retval = modem_http_get_buf(&buf, &len); //if (retval == MODEM_STATUS_OK) { //if (COMMS_STATUS_OK == check_mcu_update(buf, len)) { /* Different firmware on server. Use it. */ /* Setup URL: * Need to download either upper or lower version of the application, * depending on what we're running now. (i.e. if we are the lower app, need * to get the upper app) */ memset(comms.mqtt_buf, 0, sizeof(comms.mqtt_buf)); #if ST_OTA_HIGHER_APPLICATION //// snprintf(comms.mqtt_buf, sizeof(comms.mqtt_buf), MCU_FW_BIN_FILE_URL1_LOWER, modem_get_imei()); #elif ST_OTA_LOWER_APPLICATION // snprintf(comms.mqtt_buf, sizeof(comms.mqtt_buf), MCU_FW_BIN_FILE_URL1_HIGHER, modem_get_imei()); #else //// snprintf(comms.mqtt_buf, sizeof(comms.mqtt_buf), MCU_FW_BIN_FILE_URL1_LOWER, modem_get_imei()); #endif /*Creating file path and store it in comms.mqtt_buf*/ // snprintf(comms.mqtt_buf, sizeof(comms.mqtt_buf), MCU_FW_BIN_FILE_URL1, modem_get_imei()); switch(data_get_postToServer()){ case TEMPSTICK_SERVER1: /* make the get request to server 1. */ ESP_LOGI(TAG,"Get MCU bin file from server 1"); snprintf(comms.mqtt_buf, sizeof(comms.mqtt_buf), MCU_FW_BIN_FILE_URL1, modem_get_imei()); break; case TEMPSTICK_SERVER2: /* make the get request to server 2. */ ESP_LOGI(TAG,"Get MCU bin file from server 2"); snprintf(comms.mqtt_buf, sizeof(comms.mqtt_buf), MCU_FW_BIN_FILE_URL2, modem_get_imei()); break; case TEMPSTICK_SERVER3: /* make the get request to server 3. */ ESP_LOGI(TAG,"Get MCU bin file from server 3"); snprintf(comms.mqtt_buf, sizeof(comms.mqtt_buf), MCU_FW_BIN_FILE_URL3, modem_get_imei()); break; } /* Download the file data to modem file system */ int retval = modem_http_get_to_file(fwdl_op_cb, comms.mqtt_buf, MCU_OTA_FILE_LOCAL); if (retval == MODEM_STATUS_OK) { ESP_LOGI(TAG,"MCU FW download started\r\n"); ///hmi_set_offload_mode(false); transition(COMMS_STATE_WAIT_HTTP_GET_MCU_FILE); //hmi_set_update_mode(true); break; } else { ESP_LOGE(TAG,"MCU FW download failed to start\r\n"); /* Continue with session */ } } } } break; case COMMS_STATE_WAIT_HTTP_GET_MCU_FILE: /* Wait for download complete callback. */ if (evt == COMMS_EVENT_TIMER) { if (comms.last_op_success) { /* Download is ready. Now we can start the read from file operation on the bg96 driver * and use the callbacks to drive the update. The bg96 process is driving the update. */ retval = modem_read_from_file( fwupd_op_cb, /* called when completed or failed at any point */ MCU_OTA_FILE_LOCAL, ota_file_open_cb, /* Can fail and continue the comms state machine */ ota_file_data_cb); /* Callback for the file data in chunks */ if (retval == MODEM_STATUS_OK) { hmi_set_leds_state(BLUE_LED_FLASHING_OTA); ESP_LOGI(TAG,"MCU FW update started\r\n"); transition(COMMS_STATE_WAIT_MCU_UPDATE); break; } else { ESP_LOGE(TAG,"MCU FW update failed to start\r\n"); /* Continue with session */ //hmi_set_update_mode(false); } } } break; case COMMS_STATE_WAIT_MCU_UPDATE: /* Wait while updating. */ if (evt == COMMS_EVENT_TIMER) { if (comms.last_op_success) { /* If it completes, it will ping this and here and we finish it up. * OTA_terminate_connection sets the flag that is handled in OTA_Tick() * and main to do a reset to start the new application after comm completes. */ ESP_LOGD(TAG,"Ending OTA session, ready for reset\r\n"); ota_finish_processing(); /* Clear this, in case we have just turned on and have updated - * no need to trigger the startup callback in main. */ comms.is_starting = false; } } break; case COMMS_STATE_GOING_IDLE: /* Check if we can use WIFI as backup technique for check-in */ if((COMMS_OVER_CELL_WIFI_BACKUP == comms_mode) && (comms_do_wifi_backup)) { /* Print this log */ ESP_LOGI(TAG,"Doing WIFI-BACKUP for CHECK-IN process."); /* Transfer the control state to "WIFI_CONNECT" */ transition(COMMS_STATE_WIFI_CONNECT); /* Set the comms.poll_timer to be true */ comms.poll_timer = true; /* Reset the wifi-backup flag */ comms_do_wifi_backup = false; /* Break from the state-machine */ break; } else if((COMMS_OVER_WIFI_CELL_BACKUP == comms_mode) && (comms_do_cell_backup)) { /* Print this log */ ESP_LOGI(TAG,"Doing CELL-BACKUP for CHECK-IN process."); /* Transfer the control state to "WAIT_MODEM" */ transition(COMMS_STATE_WAIT_MODEM); /* Set the comms.poll_timer to be true */ comms.poll_timer = true; /* Reset the cell-backup flag */ //comms_do_cell_backup = false; /* Break from the state-machine */ break; } ESP_LOGI(TAG,"Process going idle.\n"); /* Reset the backup flag */ comms_do_wifi_backup = false; comms_do_cell_backup = false; #if (FAKE_NETWORK == 1) comms_update_onboarding_status(); #endif /* Stop BLUE_LED_FLASHING if it's still running*/ hmi_stop_continued_led_state(BLUE_LED_FLASHING); //stop BLUE_LED_FLASHING event /* Check if MCU failed to post the check-in message to the tempstick-server */ if(comms_posting_failed) { /* Print this log */ ESP_LOGI(TAG," -----> Posting the check-in message failed.\n Storing sensor data to NVS to be published in the next successful CHECK-IN process "); /**/ // put your code here to store sensor data to NVS data_save_history(); /* Reset the comms_posting_failed flag */ comms_posting_failed = false; } /*===========================================*/ /* Make sure that wifi is turned-off*/ if(wifi_isStarted()) { retval = wifi_stop(); } /* Make sure that modem is turned-off*/ if(modem_is_started()) { retval = modem_stop(); } /*===========================================*/ transition(COMMS_STATE_WAIT_MODEM_OFF); comms.poll_timer = true; break; case COMMS_STATE_IDLE: if (evt == COMMS_EVENT_CONNECT) { /* Set the number of check-in cycles to do and reset the checkin_cycle_counter */ number_of_check_in_to_do = nvm_get_last_written_history_sector() - nvm_get_last_posted_history_sector(); checkin_cycle_counter = 0; ESP_LOGI(TAG, "Inside comms IDLE state \r\n"); /* Status is ERROR until cleared by successful completion. */ comms.last_cycle_status = COMMS_STATUS_ERROR; if (modem_is_ready()) { modem_start_cb(MODEM_STATUS_OK); } else if(!modem_is_started()) { /* start the bg77 process */ retval = modem_start(modem_start_cb); if (retval == MODEM_STATUS_OK) { ESP_LOGI(TAG,"Waiting for Modem.\n"); transition(COMMS_STATE_WAIT_MODEM); } } else { ESP_LOGI(TAG, "Modem is busy. Comm cycle aborted.\r\n"); } } break; case COMMS_STATE_WAIT: check_in_attempts_count(comms.httpRetryCnt,HTTP_RETRY_COUNT_MAX); esp_timer_stop(comms_timer); comms.poll_timer = true; transition(comms.http_init_state); ESP_LOGI(TAG,"Number of remaining HTTP retry is : %d\n", comms.httpRetryCnt); break; case COMMS_STATE_WAIT_MODEM_OFF: if(!modem_is_started()) { /* transition to INIT state only if not started. */ transition(COMMS_STATE_IDLE); /* Invoke callback if supplied.*/ if(comms.connect_cb) { comms.connect_cb(comms.last_cycle_status); comms.connect_cb = 0; } } else { //ESP_LOGW(TAG,"Modem is busy.\r\n"); comms.poll_timer = true; } break; default: break; } return retval; } /* ------------------------------------------------------------------------- */ /* Initialize. */ int comms_init(void) { int retval = COMMS_STATUS_OK; memset(&comms, 0, sizeof(comms)); comms.overflow_check = 0xFF; /*Initializing the COMMS_TIMER */ const esp_timer_create_args_t comms_timer_args = { .callback = &timer_handler, /* argument specified here will be passed to timer callback function */ .arg = (void*) comms_timer, .name = "comms-timer" }; esp_timer_create(&comms_timer_args, &comms_timer); comms.poll_timer = false; ESP_LOGI(TAG,"Process initialized.\n"); return retval; } /* Start the process */ int comms_start(comms_op_cb_t start_cb, comms_op_cb_t connect_cb) { comms.start_cb = start_cb; comms.connect_cb = connect_cb; int retval = state_machine(COMMS_EVENT_START); return retval; } /* Stop the process */ int comms_stop(void) { int retval = state_machine(COMMS_EVENT_STOP); return retval; } /* Poll the process */ int comms_poll(void) { int retval = COMMS_STATUS_OK; if (comms.poll_timer) { comms.poll_timer = false; retval = state_machine(COMMS_EVENT_TIMER); } else if (0 /* */) { } return retval; } int comms_connect(comms_op_cb_t cb) { comms.connect_cb = cb; int retval = state_machine(COMMS_EVENT_CONNECT); return retval; } /* Check if the process needs to be polled */ bool comms_needs_poll(void) { return comms.poll_timer; } /* Check if the process is started */ bool comms_is_started(void) { return comms.state != COMMS_STATE_INIT; } bool comms_is_idle(void) { return comms.state == COMMS_STATE_IDLE; } int comms_get_status(void) { return comms.last_cycle_status; } /* ------ Process Callbacks ------------------------- */ __attribute__((weak)) void comms_ready_cb(void) { }