Remote_Wifi_Switch/main/comms.c
2025-02-21 15:26:53 +05:30

2126 lines
65 KiB
C

/*
* comms.c
*
* Created on: Jan 16, 2023
* Author: Sword
*/
#include "rtc.h"
#include "nvm.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <string.h>
#include "esp_timer.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#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 "<unknown>";
}
}
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) { }