3110 lines
96 KiB
C
3110 lines
96 KiB
C
/*
|
||
* bg96.c
|
||
*
|
||
* Created on: Jan 11, 2023
|
||
* Author: Sword
|
||
*/
|
||
|
||
/* Includes -----------------------------------------------------------------*/
|
||
#include "uart_ifx.h"
|
||
#include "port.h"
|
||
#include "esp_system.h"
|
||
#include "freertos/FreeRTOS.h"
|
||
#include "freertos/task.h"
|
||
#include <string.h>
|
||
#include <stdlib.h>
|
||
#include "esp_timer.h"
|
||
#include <stdbool.h>
|
||
#include <stdio.h>
|
||
#include "rtc.h"
|
||
#include "modem.h"
|
||
|
||
static const char* TAG = "BG77";
|
||
|
||
#define LOG_LOCAL_LEVEL ESP_LOG_INFO
|
||
#include "esp_log.h"
|
||
|
||
/* Logging configuration */
|
||
#define LOG_MODULE "BG77"
|
||
#define LOG_LEVEL LOG_LEVEL_INFO
|
||
|
||
/* Local buffer to formulate commands as necessary */
|
||
#define MODEM_TX_BUFFER_LEN 3072
|
||
|
||
/* Modem receiver buffer: expected to hold entire response for any command */
|
||
#define MODEM_RX_BUFFER_LEN 4096
|
||
|
||
/* This drive is expecting this particular device in the ATI response */
|
||
#define MODEM_DEVICE_MATCH_STRING "BG77"
|
||
|
||
/* Match the expected service mode int the QCSQ command for signal strength.
|
||
* For CAT-M1, string differs my modem model, e.g. "CAT-M1" for BG96, "eMTC" for BG77
|
||
*/
|
||
#define MODEM_QCSQ_SERIVCE_MODE_MATCH_1 "eMTC"
|
||
#define MODEM_QCSQ_SERIVCE_MODE_MATCH_2 "NBIoT"
|
||
|
||
/* Modem QFREAD chunk size. This must fit into the RX buffer taking into
|
||
* account possible responses
|
||
*/
|
||
#define MODEM_FREAD_SIZE (MODEM_RX_BUFFER_LEN - 128)
|
||
|
||
/* Maximum number of QFREAD command issuances (retries) we will use to transfer a file.
|
||
* The actual number of QFREAD command issuances is dependent upon the file size determined by QFLST.
|
||
*/
|
||
#define MODEM_FREAD_MAX_PACKET_TRANSFERS 196
|
||
|
||
#define MODEM_IMEI_START 2 /* ignore first 2 characters */
|
||
#define MODEM_IMEI_LEN 16
|
||
|
||
#define BG96_ICCID_START 10 /* ignore first 8 characters */
|
||
#define BG96_ICCID_LEN 20
|
||
|
||
#define JWT_LEN 442
|
||
|
||
/* Max number of bytes that can be sent after QMTPUB command */
|
||
#define MODEM_MQTT_PUB_BYTES_MAX 1548
|
||
|
||
/* Set to 1 to enable the use of BG96 STATUS pin to improve reliability
|
||
* and speed of modem power up and shutdown operations.
|
||
*/
|
||
#define MODEM_USE_STATUS_PIN 1
|
||
|
||
/* Time to wait for modem to turn on */
|
||
#define MODEM_STARTUP_STATUS_TIMEOUT_MS 10000
|
||
|
||
/* Time to wait for modem AT interface to ready */
|
||
#define MODEM_STARTUP_RDY_TIMEOUT_MS 5000
|
||
|
||
/* Granularity of the process timer for polling events */
|
||
#define MODEM_TIMER_GRANULARITY_MS 500
|
||
|
||
/* Maximum number of commands supported in one sequence */
|
||
#define MODEM_MAX_SEQUENCE 17
|
||
|
||
/* Unique timer ID for this process for use with timer module */
|
||
//#define MODEM_TIMER_ID 0
|
||
|
||
/* 500-1000 ms */
|
||
#define MODEM_PWRKEY_ON_DELAY_MS 750
|
||
|
||
/* 650-1500 ms */
|
||
#define MODEM_PWRKEY_OFF_DELAY_MS 1000
|
||
|
||
/* >= 2000 ms */
|
||
#define MODEM_PWRKEY_RESET_DELAY_MS 2500
|
||
|
||
/* Set to enable QHTTP OK parsing, clear to timeout and parse anyways */
|
||
#define USE_QHTTPREAD_OK 1
|
||
|
||
/* Periodic monitoring of STATUS while waiting to confirm shutdown */
|
||
#define MODEM_SHUTDOWN_STATUS_MONITOR_PERIOD_MS 2000
|
||
|
||
#define MODEM_SHUTDOWN_COUNT_WARNING_SEC 10
|
||
|
||
#define MODEM_SHUTDOWN_COUNT_LIMIT_SEC 65
|
||
|
||
/* Indicate modem power as indicated with STATUS line on green LED. */
|
||
#define MODEM_DEBUG_MODEM_POWER_STATE 0
|
||
|
||
/* Enable the "blind modem" option to ignore the STATUS line state
|
||
* and the "APP RDY" indication when turning on and off the modem.
|
||
*/
|
||
#define MODEM_BLIND_MODEM 0
|
||
|
||
#define MODEM_MODEM_FWVER_FROM_QGMR 1
|
||
|
||
/* ------------------------------------------------------------------------- */
|
||
|
||
typedef enum {
|
||
MODEM_EVENT_START,
|
||
MODEM_EVENT_TIMER,
|
||
MODEM_EVENT_UART,
|
||
MODEM_EVENT_STOP,
|
||
MODEM_EVENT_SEND_CMD,
|
||
} modem_event_t;
|
||
|
||
/* State of the bg96 process */
|
||
typedef enum {
|
||
MODEM_STATE_INIT,
|
||
MODEM_STATE_READY,
|
||
MODEM_STATE_WAIT_POWERUP,
|
||
MODEM_STATE_WAIT_STARTUP,
|
||
MODEM_STATE_WAIT_STARTUP_RDY,
|
||
MODEM_STATE_WAIT_POWERDOWN,
|
||
MODEM_STATE_WAIT_POWERKEY,
|
||
MODEM_STATE_CMD,
|
||
|
||
} modem_state_t;
|
||
|
||
/* Status is OK (match response), ERROR (match error) or TIMEOUT (retries and/or wait exhausted).
|
||
* Returns OK or ERROR in processing to help direct which command to call subsequently in
|
||
* the sequence.
|
||
*/
|
||
typedef int (*modem_cmd_handler_t)(int status, const char *buf, int len);
|
||
|
||
/* Command setup function, passed the parameters
|
||
* Intended to write to tx buf and assign that as the command.
|
||
* Return OK to assign buf as cmd_str.
|
||
* Must print a null-terminated string.
|
||
*/
|
||
typedef int (*modem_cmd_setup_t)(const void *params, char *buf, int len);
|
||
|
||
/* Allows command to send custom information */
|
||
typedef int (*modem_send_t)(void);
|
||
|
||
typedef struct {
|
||
const char *host;
|
||
int port;
|
||
const char *client_id;
|
||
//const char* jwt;
|
||
const char *pub_topic;
|
||
const char *pub_data;
|
||
int pub_data_len;
|
||
|
||
} modem_mqtt_setup_params_t;
|
||
|
||
typedef struct {
|
||
/* input params */
|
||
const char *url;
|
||
const char *file; /* for get_to_file */
|
||
const char *post_message;
|
||
|
||
/* output params */
|
||
char *buf;
|
||
int len;
|
||
|
||
} modem_http_setup_params_t;
|
||
|
||
typedef struct {
|
||
const char *file;
|
||
uint32_t file_size;
|
||
uint32_t transferred_bytes;
|
||
uint16_t chunk_size;
|
||
uint16_t expected_bytes;
|
||
uint16_t read_size;
|
||
uint16_t file_handle; /* from +QFOPEN: <filehandle> */
|
||
|
||
modem_read_from_file_open open_cb;
|
||
modem_read_from_file_data data_cb;
|
||
|
||
} modem_file_params_t;
|
||
|
||
typedef struct {
|
||
|
||
const char *cmd_str;
|
||
const char *response_match_str; /* null allowed */
|
||
const char *err_match_str; /* null allowed */
|
||
|
||
const int wait_ms;
|
||
const int retries;
|
||
|
||
/* Called after command is sent */
|
||
const modem_send_t send;
|
||
|
||
/* Called on timeout or match on response or err strings. */
|
||
const modem_cmd_handler_t handler;
|
||
|
||
/* Called on command setup */
|
||
const modem_cmd_setup_t setup;
|
||
|
||
/* Pointer to setup parameters */
|
||
const void *params;
|
||
|
||
} modem_cmd_t;
|
||
|
||
typedef struct {
|
||
modem_state_t state;
|
||
|
||
/* Timer */
|
||
bool poll_timer;
|
||
|
||
/* UART queue flag */
|
||
bool poll_uart;
|
||
|
||
/* Poll periods counter in units of timer granularity */
|
||
int poll_periods;
|
||
|
||
/* User start callback */
|
||
modem_start_cb_t start_cb;
|
||
|
||
/* Command processing state */
|
||
bool is_startup; /* in startup mode */
|
||
|
||
/* Command sequencer */
|
||
const modem_cmd_t *cmd_list[MODEM_MAX_SEQUENCE]; /* list of commands*/
|
||
int cmd_num; /* number in list */
|
||
int cmd_retries; /* count of retries */
|
||
int cmd_sequence; /* current command in list */
|
||
bool cmd_repeat; /* option to repeat a command if set true */
|
||
modem_op_cb_t cmd_complete_cb;
|
||
|
||
/* Device IMEI */
|
||
char imei[MODEM_IMEI_LEN];
|
||
char iccid[BG96_ICCID_LEN];
|
||
|
||
/* Device FW version e.g. BG95M2LAR01A01 or BG77LAR02A02_01.001.01.001 */
|
||
char fw_ver[MODEM_FWVER_LEN];
|
||
|
||
modem_signal_strength_t sig_strength;
|
||
|
||
/* Command parameters */
|
||
modem_mqtt_setup_params_t mqtt_params;
|
||
modem_http_setup_params_t http_params;
|
||
modem_file_params_t file_params;
|
||
|
||
/* Shutdown state monitoring */
|
||
int shutdown_counter;
|
||
bool shutdown_qpowd;
|
||
uint16_t shutdown_qpowd_failures;
|
||
uint16_t shutdown_pwrkey_failures;
|
||
|
||
} modem_t;
|
||
|
||
/* Local process state */
|
||
|
||
static modem_t bg96;
|
||
|
||
esp_timer_handle_t modem_timer;
|
||
/* ------------------------------------------------------------------------- */
|
||
|
||
/* comm buffers */
|
||
static char txBuf[MODEM_TX_BUFFER_LEN];
|
||
static char rxBuf[MODEM_RX_BUFFER_LEN];
|
||
static uint16_t rx_idx = 0;
|
||
|
||
/************** Device-Comms-Data *************/
|
||
extern uint8_t comms_mode;
|
||
|
||
/* Signal strength data stored after GetSignalStrength is called. */
|
||
//static MODEM_SignalStrength_t m_signalStrength;
|
||
/* Wrapping scanner treats RX buffer like a circular buffer and retains state
|
||
* over calls. It allows scanning for strings that might wrap around.
|
||
*/
|
||
typedef struct {
|
||
int RxScannerState;
|
||
int RxScannerIdx;
|
||
} ScanContext_t;
|
||
|
||
static ScanContext_t RxScanContextSuccess; /* scanner for success string */
|
||
static ScanContext_t RxScanContextError; /* scanner for failure string */
|
||
/* AT Commands -------------------------------------------------------------*/
|
||
|
||
// Note: These AT commands end with AT_OK response
|
||
// ATI,
|
||
#define ATI "ATI\r\n"
|
||
#define AT_QPOWD "AT+QPOWD\r\n"
|
||
//#define AT_CGDCONT "AT+CGDCONT=1,\"IPV4V6\",\"\",\"0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0\",0,0,0,0\r\n"
|
||
//#define AT_CGDCONT_ALT "AT+CGDCONT=1,\"IP\",\"\"\r\n"
|
||
#define AT_CGDCONT "AT+CGDCONT=1,\"IPV4V6\",\"hologram\"\r\n"
|
||
#define AT_QICSGP "AT+QICSGP=1,1,\"\",\"\",\"\",0\r\n"
|
||
#define AT_QIACT "AT+QIACT=1\r\n"
|
||
|
||
#define AT_QHTTPPOST "AT+QHTTPPOST=%u,80,60\r\n"
|
||
#define AT_QHTTPCFG_RHD "AT+QHTTPCFG=\"requestheader\",1\r\n"
|
||
#define AT_QHTTPCFG_RHD_0 "AT+QHTTPCFG=\"requestheader\",0\r\n"
|
||
#define AT_QHTTPCFG_CTX "AT+QHTTPCFG=\"contextid\",1\r\n"
|
||
#define AT_QHTTPURL "AT+QHTTPURL=%u,80\r\n" /* host */
|
||
#define AT_QHTTPGET "AT+QHTTPGET=80\r\n"
|
||
#define AT_QHTTPREAD "AT+QHTTPREAD=80\r\n"
|
||
#define AT_QHTTPREADFILE "AT+QHTTPREADFILE=\"%s\",80\r\n" /* file name */
|
||
|
||
#define AT_QFLDS "AT+QFLDS=\"UFS\""
|
||
#define AT_QFLST "AT+QFLST=\"%s\"\r\n" /* file name */
|
||
#define AT_QFOPEN "AT+QFOPEN=\"%s\",2\r\n" /* file name, mode=2 (readonly, fail if not found) */
|
||
#define AT_QFREAD "AT+QFREAD=%d,%u\r\n" /* file handle, chunk size */
|
||
#define AT_QFCLOSE "AT+QFCLOSE=%d\r\n" /* file handle */
|
||
#define AT_QFOTADL "AT+QFOTADL=%s\r\n" /* host */
|
||
#define AT_ECHO_OFF "ATE0\r\n"
|
||
#define AT_CGSN "AT+CGSN\r\n"
|
||
#define AT_QCCID "AT+QCCID\r\n"
|
||
#define AT_CGMR "AT+CGMR\r\n"
|
||
#define AT_QGMR "AT+QGMR\r\n"
|
||
#define AT_CPIN "AT+CPIN?\r\n"
|
||
#define AT_CFUN_OFF "AT+CFUN=0\r\n"
|
||
#define AT_CFUN_FULL "AT+CFUN=1\r\n"
|
||
#define AT_COPS "AT+COPS?\r\n"
|
||
#define AT_QCFG_IOTOPMODE "AT+QCFG=\"iotopmode\",2,1\r\n" /* LTE-M immediately */
|
||
#define AT_QMTCFG_WILL "AT+QMTCFG=\"will\",0\r\n"
|
||
#define AT_QMTCFG_TIMEOUT "AT+QMTCFG=\"timeout\",0,60,3,1\r\n" /* Qianwen, used to be: "AT+QMTCFG=\"timeout\",0,60,3,0\r\n", 1000 */
|
||
#define AT_QMTCFG_KEEPALIVE "AT+QMTCFG=\"keepalive\",0,60\r\n"
|
||
#define AT_QMTOPEN "AT+QMTOPEN=0,\"%s\",%d\r\n" /* host, port */
|
||
#define AT_QMTCLOSE "AT+QMTCLOSE=0\r\n"
|
||
#define AT_QMTDISC "AT+QMTDISC=0\r\n"
|
||
//#define AT_QMTCONN_CID "AT+QMTCONN=0,\"projects/pwc-production/locations/us-central1/registries/unwiredprime/devices/CTD-%s\",\"unused\",\"%s\"\r\n" /* clientID, username,password */
|
||
#define AT_QMTCONN_CID "AT+QMTCONN=0,\"%s\"\r\n" /* clientID*/
|
||
#define AT_QMTPUB "AT+QMTPUB=0,0,0,0,\"/devices/CTD-%s/events\"\r\n" /* topic, note that actual message data follows " and that \r\n is likely sent to the server */
|
||
#define AT_QCSQ "AT+QCSQ\r\n"
|
||
#define AT_CTZU "AT+CTZU=1\r\n"
|
||
#define AT_CCLK "AT+CCLK?\r\n"
|
||
#define AT_IFC "AT+IFC=2,2\r\n"
|
||
#define AT_QFDEL "AT+QFDEL=\"" MCU_OTA_FILE_LOCAL "\"\r\n"
|
||
#define AT_QFUPL "AT+QFUPL=\"cacert.pem\",1244,100\r\n"
|
||
#define AT_QMTCFG_SSL "AT+QMTCFG=\"ssl\",0,1,0\r\n"
|
||
#define AT_QSSLCFG_CACERT "AT+QSSLCFG=\"cacert\",0,\"cacert.pem\"\r\n"
|
||
#define AT_QSSLCFG_SECLEVEL "AT+QSSLCFG=\"seclevel\",0,0\r\n"
|
||
#define AT_QSSLCFG_SSLVER "AT+QSSLCFG=\"sslversion\",0,3\r\n"
|
||
#define AT_QSSLCFG_CIPH "AT+QSSLCFG=\"ciphersuite\",0,0XFFFF\r\n"
|
||
#define AT_QSSLCFG_IGNRTIME "AT+QSSLCFG=\"ignorelocaltime\",0,1\r\n"
|
||
#define AT_QMTCFG_VERSION "AT+QMTCFG=\"version\",0,4\r\n"
|
||
|
||
/* Responses */
|
||
#define AT_OK "\r\nOK\r\n"
|
||
#define AT_ERROR "\r\nERROR\r\n"
|
||
#define AT_CONNECT "CONNECT\r\n"
|
||
#define AT_HTTPPOST_SUCCESS "+QHTTPPOST: 0,200"
|
||
#define AT_QHTTPGET_SUCCESS "\r\n+QHTTPGET: 0,200"
|
||
#define AT_QHTTPREAD_SUCCESS "+QHTTPREAD: 0"
|
||
#define AT_QHTTPREADFILE_SUCCESS "\r\n+QHTTPREADFILE: 0"
|
||
#define AT_QFLST_SUCCESS "\r\n+QFLST: \"%s\""
|
||
#define AT_QFOPEN_SUCCESS "\r\n+QFOPEN:"
|
||
#define AT_CPIN_RESPONSE "\r\n+CPIN: READY" /* every response will be at least this long */
|
||
#define AT_IND_QMTOPEN "\r\n+QMTOPEN: 0,0"
|
||
#define AT_IND_QMTCONN "\r\n+QMTCONN: 0,0,0"
|
||
#define AT_IND_QMTPUB "\r\n+QMTPUB: 0,0,0"
|
||
#define AT_IND_QFUPL "\r\n+QFUPL:"
|
||
#define AT_IND_QMTCLOSE "\r\n+QMTCLOSE: 0,0"
|
||
#define AT_IND_CME_ERROR "\r\n+CME ERROR:"
|
||
#define AT_QENG_RESPONSE "\r\n+QENG:" //Partha = March 11, 2022
|
||
|
||
/* Unsolicited Result Codes */
|
||
#define URC_RDY "\r\nRDY\r\n"
|
||
|
||
#define CTRLZ (0x1A)
|
||
#define ESC (0x1B)
|
||
|
||
/* Notes:
|
||
* Possiblity of getting time from the network.
|
||
* Using NITZ method, BGxx may automatically obtain it and set it in internal RTC.
|
||
* Command sequence:
|
||
* AT+CTZU=1 enable automatic timezone update (in effect automatic time update)
|
||
* optional: AT+CTZR=2 automatic timezone reporting: emit +CTZV indication
|
||
* Get time: AT+CCLK?
|
||
*
|
||
*/
|
||
|
||
/* --------------------------------------------------------------------------*/
|
||
|
||
//definition a new function to return signal strength
|
||
int modem_Rssi() {
|
||
|
||
return bg96.sig_strength.rssi;
|
||
|
||
}
|
||
|
||
char* modem_get_rxbuf(void)
|
||
{
|
||
return (char*)(rxBuf);
|
||
}
|
||
|
||
|
||
/* Transfer bytes from queue to supplied buffer */
|
||
int board_uart_rx_stream_poll(uint8_t* buf, uint16_t* rx_idx, int buf_len)
|
||
{
|
||
int bytesCopied = 0;
|
||
//vTaskDelay(10 / portTICK_PERIOD_MS);
|
||
while(uart_ifx_uart1_ifx_get_rx_data(&buf[(*rx_idx)++]) && (*rx_idx <= buf_len))
|
||
{
|
||
bytesCopied++;
|
||
}
|
||
return bytesCopied;
|
||
}
|
||
|
||
|
||
/* forward decl */
|
||
static int start_cmd_sequence(void);
|
||
|
||
static int handle_imei_cmd(int status, const char *buf, int len) {
|
||
int retval = MODEM_STATUS_ERROR;
|
||
|
||
if (status == MODEM_STATUS_OK) {
|
||
strncpy(bg96.imei, buf + MODEM_IMEI_START, MODEM_IMEI_LEN);
|
||
bg96.imei[MODEM_IMEI_LEN - 1] = 0;
|
||
|
||
ESP_LOGI(TAG,"IMEI No: %s\r\n", bg96.imei);
|
||
|
||
retval = MODEM_STATUS_OK;
|
||
}
|
||
|
||
return retval;
|
||
}
|
||
|
||
#define ATI_REVISION_STR "Revision: "
|
||
|
||
|
||
|
||
static int handle_iccid_cmd(int status, const char* buf, int len){
|
||
|
||
int retval = MODEM_STATUS_ERROR;
|
||
|
||
if (status == MODEM_STATUS_OK)
|
||
{
|
||
strncpy(bg96.iccid, buf + BG96_ICCID_START, BG96_ICCID_LEN);
|
||
bg96.iccid[BG96_ICCID_LEN - 1] = '\0';
|
||
|
||
ESP_LOGI(TAG,"ICCID No: %s", bg96.iccid);
|
||
retval = MODEM_STATUS_OK;
|
||
}
|
||
|
||
return retval;
|
||
}
|
||
|
||
static int handle_ati_cmd(int status, const char *buf, int len) {
|
||
int retval = MODEM_STATUS_ERROR;
|
||
|
||
if (status == MODEM_STATUS_OK) {
|
||
/* Find the expected device type */
|
||
if (strstr(buf, MODEM_DEVICE_MATCH_STRING) != NULL) {
|
||
retval = MODEM_STATUS_OK;
|
||
|
||
ESP_LOGI(TAG,MODEM_DEVICE_MATCH_STRING " detected!\r\n");
|
||
} else {
|
||
ESP_LOGW(TAG,"Device " MODEM_DEVICE_MATCH_STRING "not detected\r\n");
|
||
}
|
||
|
||
#if MODEM_MODEM_FWVER_FROM_QGMR == 0
|
||
/* Find the firmware version */
|
||
char* start_ptr = strstr(buf, ATI_REVISION_STR);
|
||
if (start_ptr) {
|
||
start_ptr += strlen(ATI_REVISION_STR);
|
||
char* end_ptr = strstr(start_ptr, "\r");
|
||
if (end_ptr) {
|
||
int len = end_ptr - start_ptr;
|
||
len = (len > MODEM_FWVER_LEN-1) ? MODEM_FWVER_LEN-1 : len;
|
||
memcpy(bg96.fw_ver, start_ptr, len);
|
||
bg96.fw_ver[MODEM_FWVER_LEN - 1] = 0; /* ensure terminated */
|
||
}
|
||
}
|
||
|
||
if (bg96.fw_ver[0]) {
|
||
ESP_LOGI(TAG,"FW: %s\r\n", bg96.fw_ver);
|
||
}
|
||
else {
|
||
ESP_LOGI(TAG,"Cannot get firmware version\r\n");
|
||
}
|
||
#endif
|
||
|
||
}
|
||
|
||
return retval;
|
||
}
|
||
|
||
#if MODEM_MODEM_FWVER_FROM_QGMR
|
||
static int handle_qgmr_cmd(int status, const char *buf, int len) {
|
||
int retval = MODEM_STATUS_ERROR;
|
||
|
||
if (status == MODEM_STATUS_OK) {
|
||
/* firmware version is modem+application string returned by modem before OK
|
||
e.g. BG77LAR02A02_01.001.01.001
|
||
*/
|
||
const char *start_ptr = buf;
|
||
if (start_ptr) {
|
||
/* If modem starts revision string with \r\n, skip those. */
|
||
if (start_ptr[0] == '\r' && start_ptr[1] == '\n') {
|
||
start_ptr += 2;
|
||
}
|
||
/* look for a trailing \r\n, which may be part of version, or part of \r\nOK\r\n sent after
|
||
*/
|
||
const char *end_ptr = strstr(start_ptr, "\r\n");
|
||
if (end_ptr) {
|
||
int len = end_ptr - start_ptr;
|
||
len = (len > MODEM_FWVER_LEN - 1) ? MODEM_FWVER_LEN - 1 : len;
|
||
memcpy(bg96.fw_ver, start_ptr, len);
|
||
bg96.fw_ver[MODEM_FWVER_LEN - 1] = 0; /* ensure terminated */
|
||
}
|
||
}
|
||
|
||
if (bg96.fw_ver[0]) {
|
||
ESP_LOGI(TAG,"FW: %s\r\n", bg96.fw_ver);
|
||
} else {
|
||
ESP_LOGI(TAG,"Cannot get firmware version\r\n");
|
||
}
|
||
|
||
/* OK regardless; modem can continue to run */
|
||
retval = MODEM_STATUS_OK;
|
||
}
|
||
|
||
return retval;
|
||
}
|
||
#endif
|
||
|
||
/*static int handle_flds_cmd(int status, const char *buf, int len) {
|
||
|
||
ESP_LOGI(TAG,"AT+QFLDS response is: %s",buf);
|
||
return status;
|
||
}*/
|
||
|
||
static int handle_cops_cmd(int status, const char *buf, int len) {
|
||
#if FAKE_NETWORK
|
||
return MODEM_STATUS_OK;
|
||
#else
|
||
/* Return OK to pass this command, or anything else to continue polling. */
|
||
char *token;
|
||
if ((strstr(rxBuf, "\"") != NULL)) {
|
||
token = strtok(rxBuf, "\"");
|
||
token = strtok(NULL, "\"");
|
||
ESP_LOGI(TAG,"The Operator is: %s\r\n", token);
|
||
ESP_LOGI(TAG,"Connected to network.\r\n");
|
||
status = MODEM_STATUS_OK;
|
||
}
|
||
else
|
||
{
|
||
/* If the comms_mode is CELL-ONLY then make at cops command-retries infinite. otherwise make it limited to 120 retries */
|
||
if(comms_mode == 3)
|
||
{
|
||
bg96.cmd_repeat = true;
|
||
}
|
||
else
|
||
{
|
||
status = MODEM_STATUS_TIMEOUT;
|
||
}
|
||
}
|
||
|
||
return status;
|
||
#endif
|
||
}
|
||
|
||
static int handle_qfdel_cmd(int status, const char *buf, int len) {
|
||
status = MODEM_STATUS_OK;
|
||
return status;
|
||
}
|
||
|
||
#define AT_CCLK_IND "+CCLK:"
|
||
|
||
static int handle_cclk_cmd(int status, const char *buf, int len) {
|
||
int retval = MODEM_STATUS_ERROR;
|
||
|
||
/* Working with response like: +CCLK: "20/09/09,16:11:40-16" yy/MM/dd,hh:mm:ss-zz
|
||
* Timezone offset is in quarter-hour units. -16 is -4 hours from GMT/UTC.
|
||
* A negative offset means we need to add those hours to the local epoch to get back
|
||
* to GMT.
|
||
* NOTE!! GMT is reqired to be the system-wide time base:
|
||
* - Each modem provides local time with offset; we convert to GMT
|
||
* - Server time must also be in GMT. Currently, this is correct: SP1 timestamps
|
||
* generated by are in GMT. (https://dev.web.unwiredprime.com/api/v1/trackers/tracker/866349040012464/mcu_config_download)
|
||
*/
|
||
/* The modem under test actually spits out a nonsense time of +CCLK: "80/01/06,00:25:27
|
||
* when not connected to a network. (Year = 2080)
|
||
*/
|
||
if (status == MODEM_STATUS_OK) {
|
||
char *s = strstr(rxBuf, AT_CCLK_IND);
|
||
//char* s = "+CCLK: \"20/09/09,16:11:40-16\"";
|
||
if (s) {
|
||
rtc_timestamp_t ts;
|
||
s += strlen(AT_CCLK_IND) + 2; /* past space and " */
|
||
ts.Year = atoi(s) + 2000;
|
||
s += 3;
|
||
ts.Month = atoi(s);
|
||
s += 3;
|
||
ts.MonthDay = atoi(s);
|
||
s += 3;
|
||
ts.Hour = atoi(s);
|
||
s += 3;
|
||
ts.Minute = atoi(s);
|
||
s += 3;
|
||
ts.Second = atoi(s);
|
||
/* Try to convert the offset, plus or minus. If it can't it is 0 and
|
||
* no harm done.
|
||
*/
|
||
s += 2;
|
||
int tz_offset_sec = atoi(s) * 15 * 60; /* modem provides 1/4 hour increments */
|
||
#if SET_TIME_FROM_SERVER == 0
|
||
|
||
/* Set time just once - here, or from the SP1 record */
|
||
if (!rtc_is_set()) {
|
||
rtc_set_timestamp_tz(&ts, tz_offset_sec);
|
||
}
|
||
|
||
ESP_LOGI(TAG,"Set time: %d/%d/%d,%d:%d:%d %d -> %ld\r\n",
|
||
ts.Year, ts.Month, ts.MonthDay, ts.Hour, ts.Minute, ts.Second, tz_offset_sec,
|
||
rtc_get_epoch());
|
||
#else
|
||
/* Print time modem provides, but do not use it. */
|
||
ESP_LOGI(TAG,"Modem time: %d/%d/%d,%d:%d:%d %d\r\n",
|
||
ts.Year, ts.Month, ts.MonthDay, ts.Hour, ts.Minute, ts.Second, tz_offset_sec);
|
||
#endif
|
||
}
|
||
|
||
retval = MODEM_STATUS_OK;
|
||
}
|
||
return retval;
|
||
}
|
||
|
||
|
||
|
||
static int handle_qcsq_cmd(int status, const char *buf, int len) {
|
||
int retval = MODEM_STATUS_ERROR;
|
||
|
||
/* Working with response like: +QCSQ: "CAT-M1",-52,-81,195,-10 */
|
||
if (status == MODEM_STATUS_OK) {
|
||
char *s = strtok(rxBuf, ",");
|
||
if ((s != NULL) && (strstr(s, MODEM_QCSQ_SERIVCE_MODE_MATCH_1) || strstr(s, MODEM_QCSQ_SERIVCE_MODE_MATCH_2))) {
|
||
/* parse the 4 fields */
|
||
s = strtok(NULL, ",");
|
||
if (s){
|
||
bg96.sig_strength.rssi = atoi(s);
|
||
s = strtok(NULL, ",");
|
||
if (s){
|
||
bg96.sig_strength.rsrp = atoi(s);
|
||
s = strtok(NULL, ",");
|
||
if (s){
|
||
bg96.sig_strength.sinr = atoi(s);
|
||
s = strtok(NULL, ",");
|
||
if (s){
|
||
bg96.sig_strength.rsrq = atoi(s);
|
||
retval = MODEM_STATUS_OK;
|
||
ESP_LOGI(TAG,"Signal strength: %d %d %d %d\r\n",
|
||
bg96.sig_strength.rssi,
|
||
bg96.sig_strength.rsrp,
|
||
bg96.sig_strength.sinr,
|
||
bg96.sig_strength.rsrq);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
retval = MODEM_STATUS_OK;
|
||
} else {
|
||
ESP_LOGW(TAG,"Signal strength : did not find expected service mode\r\n");
|
||
bg96.cmd_repeat = true;
|
||
}
|
||
// to pass the command anyways
|
||
// retval = MODEM_STATUS_ERROR;
|
||
}
|
||
return retval;
|
||
}
|
||
/*
|
||
static int setup_qmtopen_cmd(const void *params, char *buf, int len) {
|
||
snprintf(buf, len, AT_QMTOPEN, bg96.mqtt_params.host,
|
||
bg96.mqtt_params.port);
|
||
|
||
return MODEM_STATUS_OK;
|
||
}
|
||
|
||
static int setup_qmtconn_cmd(const void *params, char *buf, int len) {
|
||
snprintf(buf, len, AT_QMTCONN_CID,bg96.mqtt_params.client_id); //, bg96.imei, bg96.mqtt_params.jwt);//bg96.mqtt_params.client_id,);
|
||
return MODEM_STATUS_OK;
|
||
}
|
||
|
||
static int setup_qmtpub_cmd(const void *params, char *buf, int len) {
|
||
snprintf(buf, len, AT_QMTPUB, bg96.imei); //bg96.mqtt_params.pub_topic);
|
||
|
||
return MODEM_STATUS_OK;
|
||
}
|
||
*/
|
||
|
||
/* Write the length of the URL in the command */
|
||
static int setup_qhttpurl_cmd(const void *params, char *buf, int len) {
|
||
snprintf(buf, len, AT_QHTTPURL, strlen(bg96.http_params.url));
|
||
|
||
return MODEM_STATUS_OK;
|
||
}
|
||
|
||
|
||
/* Write the length of the POST message in the command */
|
||
static int setup_qhttppost_cmd(const void *params, char *buf, int len) {
|
||
snprintf(buf, len, AT_QHTTPPOST, strlen(bg96.http_params.post_message));
|
||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||
return MODEM_STATUS_OK;
|
||
}
|
||
|
||
|
||
/* Write the length of the URL in the command */
|
||
static int setup_qhttpreadfile_cmd(const void *params, char *buf, int len) {
|
||
snprintf(buf, len, AT_QHTTPREADFILE, bg96.http_params.file);
|
||
|
||
return MODEM_STATUS_OK;
|
||
}
|
||
|
||
static int setup_qfotadl_cmd(const void *params, char *buf, int len) {
|
||
/* Send the URL */
|
||
snprintf(buf, len, AT_QFOTADL, bg96.http_params.url);
|
||
ESP_LOGW(TAG,"setup_qfotadl_cmd");
|
||
ESP_LOGI(TAG,"buf: %s",buf);
|
||
return MODEM_STATUS_OK;
|
||
}
|
||
|
||
|
||
static int handle_qhttpread_cmd(int status, const char *buf, int len) {
|
||
bg96.http_params.buf = 0;
|
||
bg96.http_params.len = 0;
|
||
|
||
/* Parse response */
|
||
#if USE_QHTTPREAD_OK
|
||
if (status == MODEM_STATUS_OK)
|
||
#else
|
||
if (status == MODEM_STATUS_TIMEOUT)
|
||
#endif
|
||
{
|
||
/* status is error until we prove correctness of response and
|
||
* user arguments are updated
|
||
*/
|
||
status = MODEM_STATUS_ERROR;
|
||
|
||
/* Ensure null-termination when searching for strings */
|
||
rxBuf[MODEM_RX_BUFFER_LEN - 1] = 0;
|
||
|
||
/* Find the connect response */
|
||
char *start_ptr = strstr(rxBuf, AT_CONNECT);
|
||
if (start_ptr != NULL) {
|
||
start_ptr += strlen(AT_CONNECT); /* point to next */
|
||
|
||
#if USE_QHTTPREAD_OK /* Use OK to frame response. */
|
||
/* Find the trailing OK response */
|
||
char *end_ptr = strstr(start_ptr, AT_OK);
|
||
if (end_ptr != NULL) {
|
||
int rlen = end_ptr - start_ptr;
|
||
|
||
bg96.http_params.buf = start_ptr;
|
||
bg96.http_params.len = rlen;
|
||
/* terminate the buffer at the OK before returning to user */
|
||
*end_ptr = 0;
|
||
/* now we are complete */
|
||
status = MODEM_STATUS_OK;
|
||
}
|
||
#else /* Do NOT use OK to frame response. */
|
||
/* Without OK to frame response, we just gather all bytes received. */
|
||
bg96.http_params.buf = start_ptr;
|
||
bg96.http_params.len = strlen(start_ptr);
|
||
status = MODEM_STATUS_OK;
|
||
#endif
|
||
}
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
/* Send the URL after the CONNECT response or as a send
|
||
* handler for any command.
|
||
*/
|
||
static int send_qhttpurl_cmd(void) {
|
||
ESP_LOGI(TAG,"Send URL: %s\r\n", bg96.http_params.url);
|
||
uart_ifx_uart1_send_bytes((uint8_t *)bg96.http_params.url, strlen(bg96.http_params.url));
|
||
|
||
return MODEM_STATUS_OK;
|
||
}
|
||
|
||
static int send_qhttpost_cmd(void) {
|
||
ESP_LOGI(TAG,"Send post_message: %s\r\n", bg96.http_params.post_message);
|
||
uart_ifx_uart1_send_bytes((uint8_t *)bg96.http_params.post_message, strlen(bg96.http_params.post_message));
|
||
|
||
return MODEM_STATUS_OK;
|
||
}
|
||
|
||
#if 0
|
||
static int handle_qhttppost_cmd(int status, const char *buf, int len)
|
||
{
|
||
|
||
/* Parse the response from the rx buffer */
|
||
char *ptr = strstr((char*) buf, "+QHTTPPOST: 0,200,");
|
||
if (ptr)
|
||
{
|
||
/*if that response exists then returns OK*/
|
||
return MODEM_STATUS_OK;
|
||
}
|
||
else
|
||
{
|
||
/*if that response doesn't exists ----> then search if there's an CME error message*/
|
||
ptr = strstr((char*) buf, "+CME ERROR:");
|
||
if (ptr)
|
||
return MODEM_STATUS_ERROR;
|
||
else
|
||
return MODEM_STATUS_HTTP_POST_WAITRES;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
static int send_qmtpub_cmd(void) {
|
||
if (bg96.mqtt_params.pub_data && bg96.mqtt_params.pub_data_len > 0) {
|
||
ESP_LOGI(TAG,"publishing: [%s]\r\n", bg96.mqtt_params.pub_data);
|
||
uart_ifx_uart1_send_bytes((uint8_t*)bg96.mqtt_params.pub_data, bg96.mqtt_params.pub_data_len);
|
||
} else {
|
||
ESP_LOGW(TAG,"publishing null data\r\n");
|
||
}
|
||
|
||
char buf[1] = {
|
||
/* Send end of message character (ctrl+z) */
|
||
CTRLZ,
|
||
//0 /* null-terminate for nice trace printing */
|
||
};
|
||
uart_ifx_uart1_send_bytes((uint8_t*)buf, sizeof(buf));
|
||
|
||
return MODEM_STATUS_OK;
|
||
}
|
||
|
||
static int send_qfupl_cmd(void) {
|
||
char buf[1244] =
|
||
"-----BEGIN CERTIFICATE----- \
|
||
MIIDazCCAlOgAwIBAgIUHMeQp85hERg7OQNJpIpRenYRRwkwDQYJKoZIhvcNAQEL \
|
||
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM \
|
||
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMTAyMjUxMzUwNDdaFw0yMTAz \
|
||
MjcxMzUwNDdaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw \
|
||
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB \
|
||
AQUAA4IBDwAwggEKAoIBAQDFMVwzDmlbfaZ+oYQwva49wQ5MB2uTLlJ3APHmSOos \
|
||
2bsRXzZf/68rsvZNF/khLoreoW/oi0lJAA/vi7oJuKvdZKovtrwiOk8z4uYEZR8D \
|
||
I3Y7xnIen4jZMjUrGnAUpRd2NQOqt2kScTbSxXvS2GuDxt+nBh2PS34WWBWp1HP0 \
|
||
4zztRYHFUfsnsc21/DMzL86uc2jZQq0fJEWu0qwxTDunIXn6tQYFDFgLasSmZv4d \
|
||
/NSNcbKLYjvUoUnbdqdTEzeshGTBM+zLxakN+Zdxc88Bb83vvNa686lzPZF/LAXT \
|
||
erEr+Yq4SxpQ5Hn9Nj5d5wxRQSDzmtns/jJmk1zhLrIZAgMBAAGjUzBRMB0GA1Ud \
|
||
DgQWBBQrE77qN2Tw7ia5DMHBvgBmwr0zHDAfBgNVHSMEGDAWgBQrE77qN2Tw7ia5 \
|
||
DMHBvgBmwr0zHDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBm \
|
||
eqBPGy1TCNEDa3dMWgO9pK9zsuDGv+J9b2TiqnTvub5uW5z+qV2f7bBsuOZRWzv3 \
|
||
4P9oGjgH+/HFpz+kSvBIRoEjjtX48LyD5H9ah0ALzQt5vXN7Q6QR4bWEtZFYlaOW \
|
||
6Yd4v2DOtyBCa6g33Jf0Hw1OaYPzRmRsbqdB/Izg60ENZFXKCPFvHNIVP7IytEaz \
|
||
gdghpaHdqGSFlbBxtfzk7vNqVoepX9kULaOhNdaDlMZE+nA+unHZc4zd0wDLVB+p \
|
||
8fYZf6JfLRkQoZmdprsa0mtVOXLBwH6C2+lj8mxz6T9Or07LjxpkJB2dxGBiE6b9 \
|
||
zkcHc7vljutOr+sbR1aK \
|
||
-----END CERTIFICATE-----";
|
||
int len = strlen(buf);
|
||
ESP_LOGI(TAG,"Buffer: [%d]\r\n", len);
|
||
uart_ifx_uart1_send_bytes((uint8_t*)buf, len);
|
||
|
||
char cbuf[1] = {
|
||
/* Send end of message character (ctrl+z) */
|
||
CTRLZ,
|
||
//0 /* null-terminate for nice trace printing */
|
||
};
|
||
uart_ifx_uart1_send_bytes((uint8_t*)cbuf, sizeof(cbuf));
|
||
|
||
return MODEM_STATUS_OK;
|
||
}
|
||
|
||
/* --------------------------------------------------------------------------*/
|
||
/* File read command processing.
|
||
*/
|
||
|
||
static int setup_qflst_cmd(const void *params, char *buf, int len) {
|
||
/* Send the file name */
|
||
snprintf(buf, len, AT_QFLST, bg96.file_params.file);
|
||
|
||
return MODEM_STATUS_OK;
|
||
}
|
||
|
||
static int handle_qflst_cmd(int status, const char *buf, int len) {
|
||
int retval = MODEM_STATUS_ERROR;
|
||
|
||
bg96.file_params.file_size = 0;
|
||
|
||
if (status == MODEM_STATUS_OK) {
|
||
/* Parse the file size from the received response */
|
||
char *ptr = strstr((char*) rxBuf, ",");
|
||
if (ptr) {
|
||
ptr++;
|
||
bg96.file_params.file_size = (uint32_t) atoi(ptr);
|
||
ESP_LOGI(TAG,"Found file [%s] on modem. size=%ld\r\n",
|
||
bg96.file_params.file, bg96.file_params.file_size);
|
||
retval = MODEM_STATUS_OK;
|
||
} else {
|
||
ESP_LOGI(TAG,"Cannot find file size for [%s]\r\n",
|
||
bg96.file_params.file);
|
||
}
|
||
} else {
|
||
ESP_LOGI(TAG,"Cannot find downloaded file [%s] on modem\r\n",
|
||
bg96.file_params.file);
|
||
}
|
||
|
||
return retval;
|
||
}
|
||
|
||
static int handle_qfotadl_cmd(int status, const char* buf, int len){
|
||
ESP_LOGI(TAG,"DFOTA handle_qfotadl_cmd ");
|
||
char* s = NULL;
|
||
char errorcode[2] ={0};
|
||
int dfotaerr_idx = -1;
|
||
|
||
s = strstr(rxBuf, "HTTPEND");
|
||
if(s == NULL)
|
||
{
|
||
ESP_LOGI(TAG,"DFOTA package checking\\validation has been failed ");
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
ESP_LOGI(TAG,"DFOTA ERROR %s",s);
|
||
strncpy(errorcode, &s[9], 1 /*only error index*/);
|
||
dfotaerr_idx = atoi(errorcode);
|
||
|
||
ESP_LOGI(TAG,"DFOTA ERROR IDX %d",dfotaerr_idx);
|
||
|
||
if(dfotaerr_idx != 0){
|
||
|
||
status = MODEM_STATUS_ERROR;
|
||
}
|
||
else{
|
||
|
||
status = MODEM_STATUS_OK;
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
static int setup_qfopen_cmd(const void *params, char *buf, int len) {
|
||
/* Send the file name */
|
||
snprintf(buf, len, AT_QFOPEN, bg96.file_params.file);
|
||
|
||
return MODEM_STATUS_OK;
|
||
}
|
||
|
||
static int handle_qfopen_cmd(int status, const char *buf, int len) {
|
||
if (status == MODEM_STATUS_OK) {
|
||
/* Need the file handle */
|
||
char *ptr = strstr((char*) rxBuf, "+QFOPEN:");
|
||
if (ptr) {
|
||
ptr += strlen("+QFOPEN:");
|
||
bg96.file_params.file_handle = atoi(ptr);
|
||
/* Initialize the file state */
|
||
bg96.file_params.transferred_bytes = 0;
|
||
bg96.file_params.chunk_size = MODEM_FREAD_SIZE;
|
||
ESP_LOGI(TAG,"Opened file %s with handle: %d\r\n",
|
||
bg96.file_params.file, bg96.file_params.file_handle);
|
||
} else {
|
||
/* Can't get handle? Uh oh */
|
||
status = MODEM_STATUS_ERROR;
|
||
ESP_LOGI(TAG,"Unable to get handle for %s\r\n", bg96.file_params.file);
|
||
}
|
||
|
||
if (status == MODEM_STATUS_OK) {
|
||
/* Call the user callback */
|
||
if (bg96.file_params.open_cb) {
|
||
/* User callback can return error, which will fail the whole read procedure */
|
||
status = bg96.file_params.open_cb(bg96.file_params.file_size);
|
||
bg96.file_params.open_cb = 0; /* call only once */
|
||
}
|
||
}
|
||
}
|
||
return status;
|
||
}
|
||
|
||
/* BG96 response search strings */
|
||
#define SFU_APP_MODEM_CONNECT_SEARCH "\r\nCONNECT 0\r\n"
|
||
#define SFU_APP_MODEM_CONNECT_PREFIX "\r\nCONNECT "
|
||
|
||
/* Length of the CONNECT response string that we will support, including null-terminator */
|
||
#define SFU_APP_MODEM_CONNECT_BUF_LEN sizeof("\r\nCONNECT 999999\r\n")
|
||
|
||
/* Compute the expected number of bytes in the modem's response to an FREAD */
|
||
static int expectedNumFREADResponseBytes(uint32_t len) {
|
||
int n = strlen(SFU_APP_MODEM_CONNECT_PREFIX);
|
||
|
||
/* digits in CONNECT read_length field */
|
||
n += (len < 10) ? 1 : (len < 100) ? 2 : (len < 1000) ? 3 : 4;
|
||
|
||
n += 2; /* trailing \r\n */
|
||
|
||
n += len;
|
||
|
||
n += strlen(AT_OK);
|
||
|
||
ESP_LOGI(TAG,"FREAD expect response len=%d for %ld\r\n", n, len);
|
||
|
||
return n;
|
||
}
|
||
|
||
/*
|
||
* Process the FREAD response from the BG96 modem.
|
||
*
|
||
* The FREAD response must begin at offset 0 in the provided buffer.
|
||
* The potential length of the entire response
|
||
* (e.g. maximum size of provided buffer) must be specified in buf_len parameter.
|
||
* It is not required to know the exact response length as this API will figure it out safely.
|
||
*
|
||
* Return MODEM_STATUS_ERROR if anything fails including buffer not containing a CONNECT response
|
||
* or properly formed CONNECT response.
|
||
*/
|
||
static int ParseFREAD(const char *buf, int buf_len, /* input arguments: pointer to receive buffer and its length */
|
||
const char **data_, int *data_len_) /* output arguments: pointer to recovered data and its length */
|
||
{
|
||
/* Deal with the buffer expecting a response from the BG96 of the form:
|
||
* \r\nCONNECT <read_length>\r\n
|
||
* <data of length read_length>
|
||
* \r\nOK\r\n
|
||
*
|
||
* We cannot assume the caller's buffer is null-terminated anywhere.
|
||
*
|
||
* We must:
|
||
* a) extract the read_length parameter
|
||
* b) find the offset of the data in the buffer
|
||
* c) copy the data to a word-aligned buffer for processing the SFU_APP_Data().
|
||
*
|
||
* The input buffer can be of any length. We will chunk it into our own buffer
|
||
* and call the underlying API as often as needed to consume all bytes in the
|
||
* caller's buffer before returning.
|
||
*/
|
||
|
||
/* Temporary buffer to search for the connect string safely */
|
||
char connect_buf[SFU_APP_MODEM_CONNECT_BUF_LEN];
|
||
|
||
/* Check arguments and basic buffer length sanity check */
|
||
if (buf == NULL || buf_len < strlen(SFU_APP_MODEM_CONNECT_SEARCH)) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
|
||
/* First we need to build a null-terminated string to operate on, so we copy what
|
||
* could be the modem response into our buffer and terminate it.
|
||
* Maximum size will be limited to 6 digits, so that is
|
||
* "\r\nCONNECT 999999\r\n" = 18 characters.
|
||
*/
|
||
const int max_copy = SFU_APP_MODEM_CONNECT_BUF_LEN - 1;
|
||
/* Copy up to BUF LEN characters into temp buffer */
|
||
const int init_copy = buf_len > max_copy ? max_copy : buf_len;
|
||
memcpy(connect_buf, buf, init_copy);
|
||
connect_buf[init_copy] = 0; /* null terminate for safe string operations on it */
|
||
ESP_LOGI(TAG,"Copied %d bytes\r\n", init_copy);
|
||
|
||
/* Find the length */
|
||
const char *start_ptr = strstr(connect_buf, SFU_APP_MODEM_CONNECT_PREFIX);
|
||
if (start_ptr == NULL) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
int offset = start_ptr - connect_buf; /* should be 0 but support other cases too */
|
||
ESP_LOGI(TAG,"Offset=%d\r\n", offset);
|
||
const char *ptr = start_ptr + strlen(SFU_APP_MODEM_CONNECT_PREFIX);
|
||
int data_len = atoi(ptr);
|
||
if (data_len <= 0) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
ESP_LOGI(TAG,"data_len=%d\r\n", data_len);
|
||
/* Offset of actual data immediately follows the \r\n */
|
||
ptr = strstr(ptr, "\r\n");
|
||
if (ptr == NULL) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
ptr += 2;
|
||
|
||
/* data offset into user buffer is specified finally here. */
|
||
offset += (ptr - start_ptr);
|
||
ESP_LOGI(TAG,"Offset=%d\n", offset);
|
||
|
||
/* check that the data length reported by CONNECT response is actually
|
||
* present in the buffer supplied.
|
||
*/
|
||
if (data_len > (buf_len - offset)) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
|
||
/* Return the actual data length and a pointer to it */
|
||
*data_ = buf + offset;
|
||
*data_len_ = data_len;
|
||
|
||
return MODEM_STATUS_OK;
|
||
}
|
||
|
||
static int setup_qfread_cmd(const void *params, char *buf, int len) {
|
||
/* Send the number of bytes we read this call */
|
||
bg96.file_params.read_size = bg96.file_params.chunk_size;
|
||
|
||
/* Adjust to the actual number of bytes remaining */
|
||
if ((bg96.file_params.file_size - bg96.file_params.transferred_bytes)
|
||
< bg96.file_params.chunk_size) {
|
||
bg96.file_params.read_size = bg96.file_params.file_size
|
||
- bg96.file_params.transferred_bytes;
|
||
}
|
||
|
||
/* This is used in the handler to mark when we have received the response */
|
||
bg96.file_params.expected_bytes = expectedNumFREADResponseBytes(
|
||
bg96.file_params.read_size);
|
||
|
||
ESP_LOGI(TAG,
|
||
"setup qfread: handle:%d read_size:%d file_size:%ld chunk_size:%d xfered:%ld expect:%d\r\n",
|
||
bg96.file_params.file_handle, bg96.file_params.read_size,
|
||
bg96.file_params.file_size, bg96.file_params.chunk_size,
|
||
bg96.file_params.transferred_bytes,
|
||
bg96.file_params.expected_bytes);
|
||
|
||
snprintf(buf, len, AT_QFREAD, bg96.file_params.file_handle,
|
||
bg96.file_params.read_size);
|
||
|
||
return MODEM_STATUS_OK;
|
||
}
|
||
|
||
/* This is how we are handling the QFREAD command response.
|
||
* We need to frame it somehow, and we do that by waiting for the expected number of
|
||
* bytes to arrive. But to have this handler called, we need to kick it with something,
|
||
* and we use the "\r\nOK\r\n" string expected at the end. We will, however, see this
|
||
* string embedded within the firmware image, so we must be careful not to end prematurely.
|
||
*
|
||
* Coming into this function, we will expect status = MODEM_STATUS_OK to indicate match for the \r\nOK\r\n string.
|
||
* then, we look for the number of bytes recevied and compare. If these match, we return STATUS_OK.
|
||
* If they do not, we must return TIMEOUT to keep looking. If the error condition was found, we have a
|
||
* similar problem with finding it in the stream, so we don't look for it and instead rely on the
|
||
* command timeout to abort.
|
||
*
|
||
* Also, we need to retry the FREAD command until the transfer is done,
|
||
* to do that we must return TIMEOUT always until it is done, then OK, or ERROR in any error state.
|
||
*/
|
||
static int handle_qfread_cmd(int status, const char *buf, int len) {
|
||
/* Pass ERROR and TIMEOUT through, only handle OK */
|
||
if (status == MODEM_STATUS_OK) {
|
||
/* Found \r\nOK\r\n in the stream. Do we have the expected number of bytes? */
|
||
if (rx_idx < bg96.file_params.expected_bytes) {
|
||
/* No, this was an embedded \r\nOK\r\n so continue scanning */
|
||
status = MODEM_STATUS_TIMEOUT;
|
||
|
||
/* Required to reset the scanner state (and update the index) for next OK */
|
||
RxScanContextSuccess.RxScannerState = 0;
|
||
RxScanContextSuccess.RxScannerIdx = rx_idx;
|
||
|
||
/* In the last UART event we got a numnber of bytes to bring it to rx_idx,
|
||
* and in that chunk we found OK but NOT expected number of bytes. This means
|
||
* we expect at least another UART event to kick the next scan.
|
||
*/
|
||
ESP_LOGI(TAG,"Found embedded OK, rx_idx=%d scanidx=%d\r\n", rx_idx,
|
||
RxScanContextSuccess.RxScannerIdx);
|
||
} else {
|
||
const char *data;
|
||
int data_len;
|
||
status = ParseFREAD(rxBuf, MODEM_RX_BUFFER_LEN, &data, &data_len);
|
||
if (status == MODEM_STATUS_OK) {
|
||
ESP_LOGI(TAG,"%d bytes file data read successfully\r\n", data_len);
|
||
/* Invoke user callback, which can also fail the transfer */
|
||
if (bg96.file_params.data_cb) {
|
||
status = bg96.file_params.data_cb(data, data_len);
|
||
if (status == MODEM_STATUS_OK) {
|
||
/* Increment the number of bytes transfered only after success on user callback */
|
||
bg96.file_params.transferred_bytes +=
|
||
bg96.file_params.read_size;
|
||
ESP_LOGI(TAG,"%d bytes processed\r\n", data_len);
|
||
} else {
|
||
ESP_LOGI(TAG,"%d bytes failed to process.\r\n", data_len);
|
||
}
|
||
}
|
||
} else {
|
||
ESP_LOGI(TAG,"Failed to parse FREAD response\r\n");
|
||
}
|
||
|
||
ESP_LOGI(TAG,"Transfer %ld/%ld %ld%% complete\r\n",
|
||
bg96.file_params.transferred_bytes,
|
||
bg96.file_params.file_size,
|
||
(bg96.file_params.transferred_bytes * 100)
|
||
/ bg96.file_params.file_size);
|
||
|
||
/* If status is OK at this point, we must set it to TIMEOUT to continue reading the file */
|
||
if (status == MODEM_STATUS_OK) {
|
||
/* If we have received all bytes, we can terminate the transfer */
|
||
if (bg96.file_params.transferred_bytes
|
||
< bg96.file_params.file_size) {
|
||
bg96.cmd_repeat = true;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
/* Must return TIMEOUT until all bytes have been tranferred, unless ERROR to signal
|
||
* transfer failed and abort the command sequence and OK to signal all done.
|
||
*/
|
||
return status;
|
||
}
|
||
|
||
static int setup_qfclose_cmd(const void *params, char *buf, int len) {
|
||
/* Send the file handle */
|
||
snprintf(buf, len, AT_QFCLOSE, bg96.file_params.file_handle);
|
||
|
||
return MODEM_STATUS_OK;
|
||
}
|
||
|
||
/* Command table
|
||
* Allows command chaining
|
||
* Each entry has a response process function
|
||
*/
|
||
|
||
#define MODEM_DEFAULT_CMD_TIMEOUT_MS 5000
|
||
#define MODEM_DEFAULT_CMD_RETRIES 5
|
||
|
||
/* Align with timeout given to modem in AT_QMTCFG_TIMEOUT */
|
||
#define MODEM_MQTT_CONN_CMD_TIMEOUT_MS 60000
|
||
|
||
typedef enum {
|
||
AT_CMD_IDX_ECHO_OFF = 0,
|
||
AT_CMD_IDX_IFC,
|
||
AT_CMD_IDX_IDENT,
|
||
#if MODEM_MODEM_FWVER_FROM_QGMR
|
||
AT_CMD_IDX_QGMR,
|
||
#endif
|
||
AT_CMD_IDX_IMEI,
|
||
AT_CMD_IDX_ICCID, //AT_QCCID to get ICCID
|
||
#if FAKE_NETWORK
|
||
AT_CMD_IDX_SETCCLK,
|
||
#endif
|
||
AT_CMD_IDX_CTZU,
|
||
AT_CMD_IDX_CPIN,
|
||
AT_CMD_IDX_CGDCONT_ALT,
|
||
AT_CMD_IDX_CFUN_OFF,
|
||
AT_CMD_IDX_CFUN,
|
||
AT_CMD_IDX_COPS,
|
||
AT_CMD_IDX_QCSQ,
|
||
AT_CMD_IDX_QCFG_IOTMODE,
|
||
AT_CMD_IDX_CCLK,
|
||
AT_CMD_IDX_QICSGP,
|
||
AT_CMD_IDX_QIACT,
|
||
|
||
//AT_CMD_IDX_QMTCFG_SSL,
|
||
AT_CMD_IDX_QFDEL,
|
||
//AT_CMD_IDX_QFUPL,
|
||
/*AT_CMD_IDX_QFUPL_SEND,
|
||
AT_CMD_IDX_QSSLCFG_CACERT,
|
||
AT_CMD_IDX_QSSLCFG_SECLEVEL,
|
||
AT_CMD_IDX_QSSLCFG_SSLVER,
|
||
AT_CMD_IDX_QSSLCFG_CIPH,
|
||
AT_CMD_IDX_QSSLCFG_IGNRTIME,
|
||
AT_CMD_IDX_QMTCFG_WILL,
|
||
AT_CMD_IDX_QMTCFG_TIMEOUT,
|
||
AT_CMD_IDX_QMTCFG_KEEPALIVE,
|
||
AT_CMD_IDX_QMTCFG_VERSION,
|
||
AT_CMD_IDX_QMTOPEN,
|
||
AT_CMD_IDX_QMTCONN_CID,*/
|
||
|
||
//AT_CMD_IDX_QMTPUB,
|
||
//AT_CMD_IDX_QMTPUB_SEND, /* not an actual command, part 2 of the QMTPUB operation */
|
||
//AT_CMD_IDX_QMTCLOSE,
|
||
|
||
AT_CMD_IDX_QHTTPCFG_CTX,
|
||
AT_CMD_IDX_QHTTPCFG_RHD,
|
||
AT_CMD_IDX_QHTTPCFG_RHD_0,
|
||
AT_CMD_IDX_QHTTPURL,
|
||
AT_CMD_IDX_QHTTPURL_SET,
|
||
AT_CMD_IDX_QHTTPPOST,
|
||
AT_CMD_IDX_QHTTPPOST_SET,
|
||
AT_CMD_IDX_QHTTPGET,
|
||
AT_CMD_IDX_QHTTPREAD,
|
||
AT_CMD_IDX_QHTTPREADFILE,
|
||
|
||
AT_CMD_IDX_QPOWD,
|
||
|
||
AT_CMD_IDX_QFOTADL,
|
||
AT_CMD_IDX_QFOTADL_WAIT_HTTPEND,
|
||
AT_CMD_IDX_QFOTADL_WAIT_END,
|
||
|
||
//AT_CMD_IDX_QFLDS,
|
||
AT_CMD_IDX_QFLST,
|
||
AT_CMD_IDX_QFOPEN,
|
||
AT_CMD_IDX_QFREAD,
|
||
AT_CMD_IDX_QFCLOSE,
|
||
|
||
// AT_CMD_IDX_QENG_SVCELL, //Partha - March 11, 2022
|
||
// AT_CMD_IDX_QENG_NBCELL //Partha - March 11, 2022
|
||
} modem_at_cmd_idx_t;
|
||
|
||
static const modem_cmd_t cmd_table[] =
|
||
{
|
||
|
||
/* ATE0 */
|
||
{ AT_ECHO_OFF, AT_OK, 0, MODEM_DEFAULT_CMD_TIMEOUT_MS,
|
||
MODEM_DEFAULT_CMD_RETRIES, 0, 0, 0, 0 },
|
||
|
||
/* IFC */
|
||
{ AT_IFC, AT_OK, 0, MODEM_DEFAULT_CMD_TIMEOUT_MS,
|
||
MODEM_DEFAULT_CMD_RETRIES, 0, 0, 0, 0 },
|
||
|
||
/* ATI */
|
||
{ ATI, AT_OK, 0, MODEM_DEFAULT_CMD_TIMEOUT_MS, MODEM_DEFAULT_CMD_RETRIES,
|
||
0, handle_ati_cmd, 0, 0 },
|
||
|
||
#if MODEM_MODEM_FWVER_FROM_QGMR
|
||
/* QGMR */
|
||
{ AT_QGMR, AT_OK, 0, MODEM_DEFAULT_CMD_TIMEOUT_MS,
|
||
MODEM_DEFAULT_CMD_RETRIES, 0, handle_qgmr_cmd, 0, 0 },
|
||
#endif
|
||
|
||
/* CGSN */
|
||
{ AT_CGSN, AT_OK, 0, MODEM_DEFAULT_CMD_TIMEOUT_MS,
|
||
MODEM_DEFAULT_CMD_RETRIES, 0, handle_imei_cmd, 0, 0 },
|
||
/* QCCID */
|
||
{ AT_QCCID, AT_OK, 0, MODEM_DEFAULT_CMD_TIMEOUT_MS, MODEM_DEFAULT_CMD_RETRIES, 0, handle_iccid_cmd, 0, 0 },
|
||
|
||
#if FAKE_NETWORK
|
||
/* SETCCLK */
|
||
/* Set the modem's RTC for testing without network
|
||
* Note: timezone offset is in units of 1/4 hour, so -20 is -5 hours (EST timezone)
|
||
* Below time is local to EST. It should be converted to GMT epoch and that is used
|
||
* as the system-wide time base for SP1/2 publish messages.
|
||
*/
|
||
{ "AT+CCLK=\"20/10/04,15:43:10-20\"\r\n", AT_OK, 0, MODEM_DEFAULT_CMD_TIMEOUT_MS, MODEM_DEFAULT_CMD_RETRIES, 0, 0, 0, 0 },
|
||
#endif
|
||
|
||
/* Network connection */
|
||
|
||
/* CTZU */
|
||
{ AT_CTZU, AT_OK, 0, MODEM_DEFAULT_CMD_TIMEOUT_MS,
|
||
MODEM_DEFAULT_CMD_RETRIES, 0, 0, 0, 0 },
|
||
|
||
/* CPIN */
|
||
{ AT_CPIN, AT_OK, 0, 5000, MODEM_DEFAULT_CMD_RETRIES, 0, 0, 0, 0 },
|
||
|
||
/* CGDCONT_ALT */
|
||
{ AT_CGDCONT, AT_OK, 0, MODEM_DEFAULT_CMD_TIMEOUT_MS,
|
||
MODEM_DEFAULT_CMD_RETRIES, 0, 0, 0, 0 },
|
||
|
||
/* CFUN_OFF */
|
||
{ AT_CFUN_OFF, AT_OK, AT_IND_CME_ERROR, 15000,
|
||
MODEM_DEFAULT_CMD_RETRIES, 0, 0, 0, 0 },
|
||
|
||
/* CFUN */
|
||
{ AT_CFUN_FULL, AT_OK, AT_IND_CME_ERROR, 15000,
|
||
MODEM_DEFAULT_CMD_RETRIES, 0, 0, 0, 0 },
|
||
|
||
/* COPS
|
||
* Wait for timeout and use handler function to look for the operators we want to connect with.
|
||
* Retry for up to 2 minutes.
|
||
*/
|
||
// { AT_COPS, 0, 0, 1000, 120, 0, handle_cops_cmd, 0, 0 },
|
||
{ AT_COPS, AT_OK, 0, 2000, 60, 0, handle_cops_cmd, 0, 0 },
|
||
/* QCSQ */
|
||
{ AT_QCSQ, AT_OK, 0, MODEM_DEFAULT_CMD_TIMEOUT_MS,
|
||
20, 0, handle_qcsq_cmd, 0, 0 },
|
||
|
||
/* QCFG_IOTMODE */
|
||
{ AT_QCFG_IOTOPMODE, AT_OK, 0, MODEM_DEFAULT_CMD_TIMEOUT_MS,
|
||
MODEM_DEFAULT_CMD_RETRIES, 0, 0, 0, 0 },
|
||
|
||
/* CCLK */
|
||
{ AT_CCLK, AT_OK, 0, MODEM_DEFAULT_CMD_TIMEOUT_MS,
|
||
MODEM_DEFAULT_CMD_RETRIES, 0, handle_cclk_cmd, 0, 0 },
|
||
|
||
/* PDP context commands:
|
||
* CGDCONT sets it up
|
||
* CGACT activates it
|
||
* OR
|
||
* QICSGP sets it up
|
||
* QIACT activates it
|
||
* QI commands are in the TCP(IP) AT command manual, while CG are standard AT commands.
|
||
* https://forums.quectel.com/t/what-is-the-difference-between-cgdcont-and-qicsgp/152
|
||
* "When using module’s embedded stacks like TCP and UDP protocol, you need to use AT+QICSGP to configure the APN.
|
||
* While using PPP, you need to use AT+CGDCONT to configure the APN."
|
||
* I also suspect that these commands need to be run before MQTT communications. We are not using PPP.
|
||
* They are included in the network connection sequence.
|
||
*/
|
||
|
||
/* QICSGP */
|
||
{ AT_QICSGP, AT_OK, AT_ERROR, MODEM_DEFAULT_CMD_TIMEOUT_MS,
|
||
MODEM_DEFAULT_CMD_RETRIES, 0, 0, 0, 0 },
|
||
|
||
/* QIACT
|
||
* Maximum response time 150 seconds.
|
||
*/
|
||
{ AT_QIACT, 0, 0, 5000, MODEM_DEFAULT_CMD_RETRIES, 0, 0, 0, 0 },
|
||
|
||
/* QSSLCFG_CACERT */
|
||
/*{ AT_QMTCFG_SSL, AT_OK, 0, MODEM_DEFAULT_CMD_TIMEOUT_MS,
|
||
MODEM_DEFAULT_CMD_RETRIES, 0, 0, 0, 0 },*/
|
||
/* MQTT connection */
|
||
{ AT_QFDEL, 0, 0, 5000, MODEM_DEFAULT_CMD_RETRIES, 0,
|
||
handle_qfdel_cmd, 0, 0 },
|
||
|
||
/* MQTT connection */
|
||
/*{ AT_QFUPL, "CONNECT", AT_IND_CME_ERROR, 5000,
|
||
MODEM_DEFAULT_CMD_RETRIES, 0, 0, 0, 0 },*/
|
||
/* Send data then wait for indication. */
|
||
//{ 0 /* no command */, AT_OK, AT_IND_CME_ERROR, 180 * 1000,
|
||
// 0 /* no retries */, send_qfupl_cmd, 0, 0, 0 },
|
||
|
||
/* QSSLCFG_CACERT */
|
||
/*{ AT_QSSLCFG_CACERT, AT_OK, 0, MODEM_DEFAULT_CMD_TIMEOUT_MS,
|
||
MODEM_DEFAULT_CMD_RETRIES, 0, 0, 0, 0 },*/
|
||
|
||
/* QMTCFG_WILL */
|
||
/*{ AT_QSSLCFG_SECLEVEL, AT_OK, 0, MODEM_DEFAULT_CMD_TIMEOUT_MS,
|
||
MODEM_DEFAULT_CMD_RETRIES, 0, 0, 0, 0 },*/
|
||
|
||
/* QMTCFG_WILL */
|
||
/*{ AT_QSSLCFG_SSLVER, AT_OK, 0, MODEM_DEFAULT_CMD_TIMEOUT_MS,
|
||
MODEM_DEFAULT_CMD_RETRIES, 0, 0, 0, 0 },*/
|
||
|
||
/* QMTCFG_WILL */
|
||
/*{ AT_QSSLCFG_CIPH, AT_OK, 0, MODEM_DEFAULT_CMD_TIMEOUT_MS,
|
||
MODEM_DEFAULT_CMD_RETRIES, 0, 0, 0, 0 },*/
|
||
|
||
/* QMTCFG_WILL */
|
||
/*{ AT_QSSLCFG_IGNRTIME, AT_OK, 0, MODEM_DEFAULT_CMD_TIMEOUT_MS,
|
||
MODEM_DEFAULT_CMD_RETRIES, 0, 0, 0, 0 },*/
|
||
|
||
/* QMTCFG_WILL */
|
||
/*{ AT_QMTCFG_WILL, AT_OK, 0, MODEM_DEFAULT_CMD_TIMEOUT_MS,
|
||
MODEM_DEFAULT_CMD_RETRIES, 0, 0, 0, 0 },*/
|
||
/* AT_QMTCFG_TIMEOUT */
|
||
/*{ AT_QMTCFG_TIMEOUT, AT_OK, 0, MODEM_DEFAULT_CMD_TIMEOUT_MS,
|
||
MODEM_DEFAULT_CMD_RETRIES, 0, 0, 0, 0 },*/
|
||
|
||
/* AT_QMTCFG_KEEPALIVE */
|
||
/*{ AT_QMTCFG_KEEPALIVE, AT_OK, 0, MODEM_DEFAULT_CMD_TIMEOUT_MS,
|
||
MODEM_DEFAULT_CMD_RETRIES, 0, 0, 0, 0 },*/
|
||
|
||
/* AT_QMTCFG_VERSION */
|
||
/*{ AT_QMTCFG_VERSION, AT_OK, 0, MODEM_DEFAULT_CMD_TIMEOUT_MS,
|
||
MODEM_DEFAULT_CMD_RETRIES, 0, 0, 0, 0 },*/
|
||
|
||
/* QMTOPEN */
|
||
/*{ AT_QMTOPEN, AT_IND_QMTOPEN, 0, MODEM_MQTT_CONN_CMD_TIMEOUT_MS,
|
||
MODEM_DEFAULT_CMD_RETRIES, 0, 0, setup_qmtopen_cmd, 0 },*/
|
||
|
||
/* QMTCONN_CID */
|
||
/*{ AT_QMTCONN_CID, AT_IND_QMTCONN, 0,
|
||
MODEM_MQTT_CONN_CMD_TIMEOUT_MS, MODEM_DEFAULT_CMD_RETRIES,
|
||
0, 0, setup_qmtconn_cmd, 0 },*/
|
||
|
||
/* MQTT publish */
|
||
|
||
/* QMTPUB
|
||
* Publish messages.
|
||
* AT+QMTPUB=0,0,0,0,"topic/pub"
|
||
* >This is test data, hello MQTT. //After receiving >, input data "This is test data, hello MQTT." and
|
||
* then send it. The maximum length of the data is 1548 bytes and the
|
||
* data that beyond 1548 bytes will be omitted. After inputting data,
|
||
* tap Ctrl+Z to send.
|
||
* OK
|
||
* +QMTPUB: 0,0,0
|
||
*
|
||
* Note: need to wait for ">" from modem after command is sent before sending our data.
|
||
* Publish is then split into two operations: AT_QMTPUB command which waits for ">",
|
||
* then send the data and waits for the indication.
|
||
*/
|
||
/*{ AT_QMTPUB, ">", AT_IND_CME_ERROR, 5000,
|
||
MODEM_DEFAULT_CMD_RETRIES, 0, 0, setup_qmtpub_cmd, 0 },*/
|
||
/* Send data then wait for indication. */
|
||
//{ 0 /* no command */, AT_IND_QMTPUB, AT_IND_CME_ERROR, 180
|
||
// * 1000, 0 /* no retries */, send_qmtpub_cmd, 0, 0, 0 },
|
||
|
||
/* QMTCLOSE
|
||
* Note:
|
||
* The QMTCLOSE: indication does not appear within a 10s timeout. The manual has no specification on how long
|
||
* this might take. Instead, we wait for the command's OK response and continue as if the connection
|
||
* had closed.
|
||
*/
|
||
//{ AT_QMTCLOSE, AT_OK /* AT_IND_QMTCLOSE */, 0,
|
||
// MODEM_DEFAULT_CMD_TIMEOUT_MS, MODEM_DEFAULT_CMD_RETRIES,
|
||
// 0, 0, 0, 0 },
|
||
|
||
/* HTTP */
|
||
|
||
/* QHTTPCFG_CTX */
|
||
{ AT_QHTTPCFG_CTX, AT_OK, AT_IND_CME_ERROR,
|
||
MODEM_DEFAULT_CMD_TIMEOUT_MS, MODEM_DEFAULT_CMD_RETRIES,
|
||
0, 0, 0, 0 },
|
||
|
||
/* QHTTPCFG_RHD */
|
||
{ AT_QHTTPCFG_RHD, AT_OK, AT_IND_CME_ERROR,
|
||
MODEM_DEFAULT_CMD_TIMEOUT_MS, MODEM_DEFAULT_CMD_RETRIES,
|
||
0, 0, 0, 0 },
|
||
|
||
{ AT_QHTTPCFG_RHD_0, AT_OK, AT_IND_CME_ERROR,
|
||
MODEM_DEFAULT_CMD_TIMEOUT_MS, MODEM_DEFAULT_CMD_RETRIES,
|
||
0, 0, 0, 0 },
|
||
|
||
/* QHTTPURL
|
||
* Wait for CONNECT
|
||
*/
|
||
{ AT_QHTTPURL, AT_CONNECT, AT_IND_CME_ERROR,
|
||
MODEM_DEFAULT_CMD_TIMEOUT_MS, MODEM_DEFAULT_CMD_RETRIES,
|
||
0, 0, setup_qhttpurl_cmd, 0 },
|
||
/* then send URL then wait for OK */
|
||
{ 0, AT_OK, AT_IND_CME_ERROR, MODEM_DEFAULT_CMD_TIMEOUT_MS,
|
||
MODEM_DEFAULT_CMD_RETRIES, send_qhttpurl_cmd, 0, 0, 0 },
|
||
|
||
/* QHTTPPOST
|
||
* Wait for CONNECT
|
||
*/
|
||
{ AT_QHTTPPOST, AT_CONNECT, AT_IND_CME_ERROR,
|
||
80000, MODEM_DEFAULT_CMD_RETRIES,
|
||
0, 0, setup_qhttppost_cmd, 0 },
|
||
/* then send POST-Message then wait for OK */
|
||
{ 0, AT_HTTPPOST_SUCCESS, AT_IND_CME_ERROR, 60000,
|
||
MODEM_DEFAULT_CMD_RETRIES, send_qhttpost_cmd, 0, 0, 0 },
|
||
|
||
/* QHTTPGET
|
||
* If <request_header> is 0, then wait for +QHTTPGET indication. Then use QHTTPREAD to get the response.
|
||
* If <request_header> is 1, then wait for CONNECT then OK to frame response from this command
|
||
* Default appears to be 0.
|
||
*/
|
||
{ AT_QHTTPGET, AT_QHTTPGET_SUCCESS, AT_IND_CME_ERROR, 80000,
|
||
0 /* no retries */, 0, 0, 0, 0 },
|
||
|
||
/* QHTTPREAD
|
||
* Look for OK response before +QHTTPREAD indication to frame the GET content. */
|
||
#if USE_QHTTPREAD_OK
|
||
/* OK, +QHTTPREAD response expected. Timeout equal to QHTTPREAD command timeout. */
|
||
{ AT_QHTTPREAD, AT_QHTTPREAD_SUCCESS, /*AT_IND_CME_ERROR*/ 0, 80000,
|
||
3, 0, handle_qhttpread_cmd, 0, 0 },
|
||
#else
|
||
/* No OK Response expected, wait for timeout then parse. */
|
||
{ AT_QHTTPREAD, 0, 0, 3000, MODEM_DEFAULT_CMD_RETRIES, 0, handle_qhttpread_cmd, 0, 0 },
|
||
#endif
|
||
|
||
/* QHTTPREADFILE
|
||
* Look for OK response to frame the GET content. */
|
||
{ AT_QHTTPREADFILE, AT_QHTTPREADFILE_SUCCESS, AT_IND_CME_ERROR,
|
||
5*60*1000, MODEM_DEFAULT_CMD_RETRIES, 0, 0,
|
||
setup_qhttpreadfile_cmd, 0 },
|
||
|
||
/* QPOWD
|
||
* This command default is "1" - normal shutdown.
|
||
It is recommended to execute AT+QPOWD command to power off the module, as it is the safest and best
|
||
way. This procedure is realized by letting the module log off from the network and allowing the software to
|
||
enter a secure and safe data state before disconnecting the power supply.
|
||
After sending AT+QPOWD, do not enter any other AT commands. When the command is executed
|
||
successfully, the module will output POWERED DOWN and set the STATUS pin as low to enter power-off
|
||
state. In order to avoid data loss, it is suggested to wait for 1s at least to disconnect the power supply after
|
||
the STATUS pin is set as low and the URC POWERED DOWN is outputted. If POWERED DOWN cannot
|
||
be received within 65s, the power supply shall be disconnected compulsorily.
|
||
*
|
||
* Our procedure is to enter command and wait for standard OK to complete command sequence,
|
||
* then we monitor STATUS pin for the 65 seconds. If it is still up after that we
|
||
* can try PWRKEY and start waiting again.
|
||
*/
|
||
{ AT_QPOWD, AT_OK, 0, MODEM_DEFAULT_CMD_TIMEOUT_MS,
|
||
MODEM_DEFAULT_CMD_RETRIES, 0, 0, 0, 0 },
|
||
|
||
/* Send QFOTADL with URL, wait for OK */
|
||
{ AT_QFOTADL, AT_OK, AT_IND_CME_ERROR,
|
||
MODEM_DEFAULT_CMD_TIMEOUT_MS, MODEM_DEFAULT_CMD_RETRIES,
|
||
0, 0, setup_qfotadl_cmd, 0 },
|
||
/* then wait 25 mins for process to complete with "END"
|
||
* Need multiple phases: download from server phase: HTTPEND
|
||
* Update phase: END. If server download didn't complete, fail it.
|
||
*/
|
||
{ 0, "\"HTTPEND\",0", "\"HTTPEND\",", 25 * 60 * 1000, 0, 0, handle_qfotadl_cmd,0, 0 },
|
||
{ 0, "\"END\"", AT_IND_CME_ERROR, 25 * 60* 1000, 0, 0, 0, 0, 0 },
|
||
|
||
|
||
//{ AT_QFLDS, AT_OK, AT_IND_CME_ERROR, MODEM_DEFAULT_CMD_TIMEOUT_MS, MODEM_DEFAULT_CMD_RETRIES, 0, handle_flds_cmd, 0, 0 },
|
||
/* File transfer procedure:
|
||
* 1. Look for specific file, get file size from response. setup, handler : set size
|
||
* 2. Open file. handler: success : get file handle, call user open cb, init transfer state.
|
||
* 3 read file repeatedly until bytes consumed. Use handler to control this as a retry.
|
||
*/
|
||
{ AT_QFLST, AT_OK, AT_IND_CME_ERROR,
|
||
MODEM_DEFAULT_CMD_TIMEOUT_MS, MODEM_DEFAULT_CMD_RETRIES,
|
||
0, handle_qflst_cmd, setup_qflst_cmd, 0 }, { AT_QFOPEN,
|
||
AT_OK, AT_IND_CME_ERROR, MODEM_DEFAULT_CMD_TIMEOUT_MS,
|
||
MODEM_DEFAULT_CMD_RETRIES, 0, handle_qfopen_cmd,
|
||
setup_qfopen_cmd, 0 },
|
||
/* Look for OK response to frame FREAD data. This is dangerous by itself because \r\nOK\r\n is likely located within
|
||
* the byte stream. To make this work, we use the handler in combination to check that we have found \r\nOK\r\n AND the
|
||
* expected number of bytes.
|
||
*/
|
||
{ AT_QFREAD, AT_OK /* See note */,
|
||
0 /* do not look for error response */,
|
||
10000 /* timeout */, 0 /* no retries */, 0,
|
||
handle_qfread_cmd, setup_qfread_cmd, 0 }, { AT_QFCLOSE,
|
||
AT_OK, AT_IND_CME_ERROR, MODEM_DEFAULT_CMD_TIMEOUT_MS,
|
||
MODEM_DEFAULT_CMD_RETRIES, 0, 0, setup_qfclose_cmd, 0 }
|
||
|
||
};
|
||
|
||
#define MODEM_NUM_CMDS (sizeof(cmd_table) / sizeof(cmd_table[0]))
|
||
|
||
static int add_cmd(const modem_cmd_t *cmd) {
|
||
int retval = MODEM_STATUS_ERROR;
|
||
if (cmd) {
|
||
if (bg96.cmd_num < MODEM_MAX_SEQUENCE) {
|
||
bg96.cmd_list[bg96.cmd_num++] = cmd;
|
||
retval = MODEM_STATUS_OK;
|
||
}
|
||
}
|
||
return retval;
|
||
}
|
||
|
||
int modem_network_connect(modem_op_cb_t cb) {
|
||
bg96.cmd_num = 0;
|
||
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_CTZU])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_CPIN])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
/*if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_CGDCONT_ALT])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}*/
|
||
/*if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_CFUN_OFF])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}*/
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_CFUN])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_COPS])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QCSQ])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QCFG_IOTMODE])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QFDEL])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QCFG_IOTMODE])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
/*if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QICSGP])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}*/
|
||
#if FAKE_NETWORK
|
||
#else
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QIACT])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
#endif
|
||
|
||
bg96.cmd_complete_cb = cb;
|
||
|
||
int retval = start_cmd_sequence();
|
||
|
||
if (retval == MODEM_STATUS_OK) {
|
||
ESP_LOGI(TAG,"Starting connect network sequence %d\r\n", bg96.cmd_num);
|
||
}
|
||
return retval;
|
||
|
||
}
|
||
|
||
#if 0
|
||
int modem_mqtt_connect(modem_op_cb_t cb, const char *host, int port,
|
||
const char *client_id) //, const char* jwt)
|
||
{
|
||
bg96.cmd_num = 0;
|
||
/*if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QMTCFG_SSL])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QFDEL])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QFUPL])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QFUPL_SEND])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QSSLCFG_CACERT])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QSSLCFG_SECLEVEL])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QSSLCFG_SSLVER])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QSSLCFG_CIPH])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QSSLCFG_IGNRTIME])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}*/
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QMTCFG_WILL])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QMTCFG_TIMEOUT])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QMTCFG_KEEPALIVE])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QMTCFG_VERSION])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
|
||
/* Get signal strength at this location, more reliable than right after COPS. */
|
||
/*if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QCSQ])) { //Not needed - Partha March 14, 2022
|
||
return MODEM_STATUS_ERROR;
|
||
}*/
|
||
|
||
/* Also get time here, may be more reliable. Time is needed before the first publish, below. */
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_CCLK])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
#if FAKE_NETWORK
|
||
/*Don't do the actual MQTT connection */
|
||
//For testing the new WF1 and WF2 messages - Partha - March 16, 2022
|
||
|
||
|
||
#else
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QMTOPEN])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QMTCONN_CID])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
|
||
// //Get Serving cell data - Partha - March 12, 2022
|
||
// if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QENG_SVCELL])) {
|
||
// return MODEM_STATUS_ERROR;
|
||
// }
|
||
//
|
||
// //GEt neighbout cell list - Partha - March 12, 2022
|
||
// if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QENG_NBCELL])) {
|
||
// return MODEM_STATUS_ERROR;
|
||
// }
|
||
|
||
#endif
|
||
|
||
bg96.cmd_complete_cb = cb;
|
||
bg96.mqtt_params.host = host;
|
||
bg96.mqtt_params.port = port;
|
||
//bg96.mqtt_params.jwt = jwt;
|
||
bg96.mqtt_params.client_id = client_id;
|
||
|
||
int retval = start_cmd_sequence();
|
||
|
||
if (retval == MODEM_STATUS_OK) {
|
||
ESP_LOGI(TAG,"Starting connect mqtt sequence %d\r\n", bg96.cmd_num);
|
||
}
|
||
return retval;
|
||
}
|
||
|
||
/* Publish data to the specific topic */
|
||
int modem_mqtt_publish(modem_op_cb_t cb, const char *topic, const char *data,
|
||
int len) {
|
||
bg96.cmd_num = 0;
|
||
|
||
if (!topic || !data) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
#if FAKE_NETWORK
|
||
/*Don't do the actual MQTT connection */
|
||
#else
|
||
/* Two-step operation, see QMTPUB command description. */
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QMTPUB])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QMTPUB_SEND])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
#endif
|
||
bg96.cmd_complete_cb = cb;
|
||
bg96.mqtt_params.pub_topic = topic;
|
||
bg96.mqtt_params.pub_data = data;
|
||
bg96.mqtt_params.pub_data_len = len;
|
||
|
||
int retval = start_cmd_sequence();
|
||
|
||
if (retval == MODEM_STATUS_OK) {
|
||
ESP_LOGI(TAG,"Starting mqtt publish %d bytes to %s\r\n", len, topic);
|
||
}
|
||
return retval;
|
||
}
|
||
|
||
int modem_mqtt_close(modem_op_cb_t cb) {
|
||
bg96.cmd_num = 0;
|
||
|
||
#if FAKE_NETWORK
|
||
/*Don't do the actual MQTT connection */
|
||
#else
|
||
/*
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QMTDISC])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
*/
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QMTCLOSE])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
#endif
|
||
bg96.cmd_complete_cb = cb;
|
||
|
||
int retval = start_cmd_sequence();
|
||
|
||
if (retval == MODEM_STATUS_OK) {
|
||
ESP_LOGI(TAG,"Starting mqtt close\r\n");
|
||
}
|
||
return retval;
|
||
}
|
||
#endif
|
||
/* Setup the HTTP context */
|
||
int modem_http_setup(modem_op_cb_t cb) {
|
||
bg96.cmd_num = 0;
|
||
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QHTTPCFG_CTX])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
|
||
bg96.cmd_complete_cb = cb;
|
||
|
||
int retval = start_cmd_sequence();
|
||
|
||
if (retval == MODEM_STATUS_OK) {
|
||
ESP_LOGI(TAG,"Starting http setup\r\n");
|
||
}
|
||
return retval;
|
||
}
|
||
|
||
/* Make an HTTP GET request and store result in supplied buffer */
|
||
int modem_http_get_to_buf(modem_op_cb_t cb, const char *url) {
|
||
bg96.cmd_num = 0;
|
||
|
||
#if FAKE_NETWORK
|
||
/*Don't do the actual HTTP connection */
|
||
#else
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QHTTPCFG_RHD_0])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QHTTPURL])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QHTTPURL_SET])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QHTTPGET])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QHTTPREAD])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
#endif
|
||
bg96.cmd_complete_cb = cb;
|
||
bg96.http_params.url = url;
|
||
|
||
int retval = start_cmd_sequence();
|
||
|
||
if (retval == MODEM_STATUS_OK) {
|
||
ESP_LOGI(TAG,"Starting http get to buffer from url: %s\r\n", url);
|
||
}
|
||
return retval;
|
||
}
|
||
|
||
/* Make an HTTP GET request and store result to file on modem file system.
|
||
* Use modem_read_from_file to get contents.
|
||
*/
|
||
int modem_http_get_to_file(modem_op_cb_t cb, const char *url, const char *file) {
|
||
bg96.cmd_num = 0;
|
||
#if FAKE_NETWORK
|
||
/*Don't do the actual HTTP connection */
|
||
#else
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QHTTPURL])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QHTTPURL_SET])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QHTTPGET])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QHTTPREADFILE])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
#endif
|
||
bg96.cmd_complete_cb = cb;
|
||
bg96.http_params.url = url;
|
||
bg96.http_params.file = file;
|
||
|
||
int retval = start_cmd_sequence();
|
||
|
||
if (retval == MODEM_STATUS_OK) {
|
||
ESP_LOGI(TAG,"Starting http get to file from url: %s file: %s\r\n",
|
||
bg96.http_params.url, bg96.http_params.file);
|
||
}
|
||
return retval;
|
||
}
|
||
|
||
int modem_http_post_message(modem_op_cb_t cb, const char *url, const char *message) {
|
||
bg96.cmd_num = 0;
|
||
#if FAKE_NETWORK
|
||
/*Don't do the actual HTTP connection */
|
||
#else
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QHTTPCFG_RHD])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QHTTPURL])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QHTTPURL_SET])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QHTTPPOST])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QHTTPPOST_SET])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QHTTPREAD])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
#endif
|
||
bg96.cmd_complete_cb = cb;
|
||
bg96.http_params.url = url;
|
||
bg96.http_params.post_message = message;
|
||
|
||
int retval = start_cmd_sequence();
|
||
|
||
if (retval == MODEM_STATUS_OK) {
|
||
ESP_LOGI(TAG,"Starting http-post to send the json-formatted message");//: %s to url: %s \r\n",
|
||
//bg96.http_params.post_message, bg96.http_params.url);
|
||
}
|
||
return retval;
|
||
}
|
||
|
||
int modem_read_from_file(modem_op_cb_t cb, const char *file,
|
||
modem_read_from_file_open cbOpen, modem_read_from_file_data cbData) {
|
||
bg96.cmd_num = 0;
|
||
#if FAKE_NETWORK
|
||
/*Don't do the actual read from file connection */
|
||
#else
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QFLST])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QFOPEN])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QFREAD])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QFCLOSE])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
#endif
|
||
bg96.cmd_complete_cb = cb;
|
||
/* setup handler for QFLST uses this field for file name */
|
||
bg96.file_params.file = file;
|
||
bg96.file_params.open_cb = cbOpen;
|
||
bg96.file_params.data_cb = cbData;
|
||
|
||
int retval = start_cmd_sequence();
|
||
|
||
if (retval == MODEM_STATUS_OK) {
|
||
ESP_LOGI(TAG,"Starting read from file: %s\r\n", file);
|
||
}
|
||
return retval;
|
||
}
|
||
|
||
/* Update modem command sequence. */
|
||
int modem_update_modem(modem_op_cb_t cb, const char *url) {
|
||
bg96.cmd_num = 0;
|
||
ESP_LOGI(TAG,"cmd-> AT_CMD_IDX_QFOTADL");
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QFOTADL])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
|
||
ESP_LOGI(TAG,"cmd-> AT_CMD_IDX_QFOTADL_WAIT_HTTPEND");
|
||
if (MODEM_STATUS_ERROR
|
||
== add_cmd(&cmd_table[AT_CMD_IDX_QFOTADL_WAIT_HTTPEND])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
ESP_LOGI(TAG,"cmd-> AT_CMD_IDX_QFOTADL_WAIT_END");
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QFOTADL_WAIT_END])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
|
||
bg96.cmd_complete_cb = cb;
|
||
bg96.http_params.url = url;
|
||
|
||
int retval = start_cmd_sequence();
|
||
|
||
if (retval == MODEM_STATUS_OK) {
|
||
ESP_LOGI(TAG,"Started modem update sequence\r\n");
|
||
}
|
||
return retval;
|
||
}
|
||
|
||
/* Internal command sequence */
|
||
static int shutdown_sequence(modem_op_cb_t cb) {
|
||
bg96.cmd_num = 0;
|
||
|
||
#if 1 // Set 0 for testing error handling
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QPOWD])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
#endif
|
||
bg96.cmd_complete_cb = cb;
|
||
|
||
int retval = start_cmd_sequence();
|
||
|
||
if (retval == MODEM_STATUS_OK) {
|
||
ESP_LOGI(TAG,"Starting shutdown sequence\r\n");
|
||
}
|
||
return retval;
|
||
}
|
||
|
||
/* Functions ----------------------------------------------------------------*/
|
||
extern bool uart1_rx_needed;
|
||
|
||
static int start_rx_stream() {
|
||
memset(&RxScanContextSuccess, 0, sizeof(RxScanContextSuccess));
|
||
memset(&RxScanContextError, 0, sizeof(RxScanContextError));
|
||
memset(rxBuf, 0, MODEM_RX_BUFFER_LEN);
|
||
rx_idx = 0;
|
||
|
||
uart1_rx_needed = true;
|
||
//bg96.poll_uart = true;
|
||
|
||
return MODEM_STATUS_OK;
|
||
}
|
||
|
||
static void stop_rx_stream() {
|
||
uart1_rx_needed = false;
|
||
bg96.poll_uart = false;
|
||
}
|
||
|
||
/* Scan RX buffer with len characters in it for given string.
|
||
* Different from strstr, this function won't terminate on finding 0 in rxBuf.
|
||
* This handles modem's startup \0RDY indication.
|
||
*/
|
||
int scan_rx_buffer(int num_bytes, const char *str, ScanContext_t *scanContext,
|
||
const char *buf, int len) {
|
||
int str_len = strlen(str);
|
||
while (num_bytes > 0) {
|
||
/* Look for consecutive sequence of characters from str in buffer */
|
||
if (buf[scanContext->RxScannerIdx]
|
||
== str[scanContext->RxScannerState]) {
|
||
scanContext->RxScannerState++;
|
||
if (scanContext->RxScannerState == str_len) {
|
||
return MODEM_STATUS_OK;
|
||
}
|
||
} else if (buf[scanContext->RxScannerIdx] == str[0]) {
|
||
scanContext->RxScannerState = 1;
|
||
if (scanContext->RxScannerState == str_len) {
|
||
return MODEM_STATUS_OK;
|
||
}
|
||
} else {
|
||
scanContext->RxScannerState = 0;
|
||
}
|
||
|
||
if (++scanContext->RxScannerIdx == len) {
|
||
/* wrap the scanner around */
|
||
scanContext->RxScannerIdx = 0;
|
||
}
|
||
|
||
num_bytes--;
|
||
}
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
|
||
/* ------------------------------------------------------------------------- */
|
||
|
||
static const char* state_str(modem_state_t s) {
|
||
switch (s) {
|
||
case MODEM_STATE_INIT:
|
||
return "INIT";
|
||
case MODEM_STATE_READY:
|
||
return "READY";
|
||
case MODEM_STATE_WAIT_POWERUP:
|
||
return "WAIT_POWERUP";
|
||
case MODEM_STATE_WAIT_STARTUP:
|
||
return "WAIT_STARTUP";
|
||
case MODEM_STATE_WAIT_STARTUP_RDY:
|
||
return "WAIT_STARTUP_RDY";
|
||
case MODEM_STATE_WAIT_POWERDOWN:
|
||
return "WAIT_POWERDOWN";
|
||
case MODEM_STATE_CMD:
|
||
return "CMD";
|
||
default:
|
||
return "<unknown>";
|
||
}
|
||
}
|
||
|
||
static void transition(modem_state_t state_to) {
|
||
ESP_LOGI(TAG,"%s->%s\n", state_str(bg96.state), state_str(state_to));
|
||
bg96.state = state_to;
|
||
}
|
||
|
||
static int transition_ready(void) {
|
||
transition(MODEM_STATE_READY);
|
||
if (bg96.start_cb) {
|
||
bg96.start_cb(MODEM_STATUS_OK);
|
||
bg96.start_cb = 0; /* only send notification once */
|
||
}
|
||
return MODEM_STATUS_OK;
|
||
}
|
||
|
||
/* Monitor the stream periodically */
|
||
static int monitor_rx_stream(const char *success, const char *error) {
|
||
/* Copy bytes from the circular buffer to the receive buffer for processing.
|
||
* The goal is to look for complete success or error strings
|
||
*/
|
||
uint16_t prev_rx_idx = rx_idx;
|
||
|
||
int bytesCopied = board_uart_rx_stream_poll((uint8_t*) rxBuf, &rx_idx, sizeof(rxBuf));
|
||
|
||
if(bytesCopied > 0)
|
||
{
|
||
//ESP_LOGI(TAG,"Got %d bytes %d\r\n", bytesCopied, rx_idx);
|
||
//ESP_LOGI(TAG, "Uart RX: %s", rxBuf);
|
||
if(strstr(rxBuf,"+QIND: \"FOTA\",\"DOWNLOADING\""))
|
||
{
|
||
|
||
rx_idx = 0;
|
||
//ESP_LOGI(TAG, "Unecessary DFOTA DOWNLOADING LOGS");
|
||
ESP_LOGI(TAG, "%s",rxBuf);
|
||
}
|
||
else
|
||
{
|
||
ESP_LOGI(TAG, "Uart RX:");
|
||
}
|
||
|
||
}
|
||
else
|
||
{
|
||
rx_idx = prev_rx_idx;
|
||
}
|
||
|
||
if (rx_idx != 0) // if something in the buffer
|
||
{
|
||
/* Check for success and error strings in buffer */
|
||
if (success && scan_rx_buffer(bytesCopied, success, &RxScanContextSuccess, rxBuf, MODEM_RX_BUFFER_LEN - 1) == MODEM_STATUS_OK)
|
||
{
|
||
ESP_LOGI(TAG, "VERIFIED RESPONSE: %s", success);
|
||
return MODEM_STATUS_OK;
|
||
}
|
||
|
||
if (error && scan_rx_buffer(bytesCopied, error, &RxScanContextError, rxBuf, MODEM_RX_BUFFER_LEN - 1) == MODEM_STATUS_OK)
|
||
{
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
}
|
||
|
||
if(strstr(rxBuf,success))
|
||
{
|
||
ESP_LOGI(TAG, "VERIFIED RESPONSE: %s", success);
|
||
return MODEM_STATUS_OK;
|
||
}
|
||
|
||
if(strstr(rxBuf,error))
|
||
{
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
|
||
|
||
//ESP_LOGI(TAG, "Timeout .... didn't fined %s or %s", success,error);
|
||
|
||
|
||
|
||
/* So far found nothing that matches */
|
||
return MODEM_STATUS_TIMEOUT;
|
||
}
|
||
|
||
/* Send the current command in the sequence */
|
||
static int send_command(const modem_cmd_t *cmd) // const char* cmd, int timeout_ms)
|
||
{
|
||
int retval = MODEM_STATUS_OK;
|
||
|
||
/*Checking the passed command(check it it's zero or not)*/
|
||
if (cmd->response_match_str) {
|
||
/* Start the receive stream */
|
||
retval = start_rx_stream();
|
||
} else {
|
||
/*return MODEM_STATUS_OK */
|
||
retval = MODEM_STATUS_OK;
|
||
}
|
||
|
||
if (MODEM_STATUS_OK == retval) {
|
||
if(ESP_OK == esp_timer_start_once(modem_timer, 1000*(cmd->wait_ms)))
|
||
{
|
||
retval = MODEM_STATUS_OK;
|
||
}
|
||
if (MODEM_STATUS_OK == retval) {
|
||
const char *cmd_str = cmd->cmd_str;
|
||
/* Invoke setup function */
|
||
if (cmd->setup) {
|
||
if (MODEM_STATUS_OK
|
||
== cmd->setup(cmd->params, txBuf, sizeof(txBuf))) {
|
||
cmd_str = txBuf;
|
||
}
|
||
}
|
||
if (cmd_str) {
|
||
/* trace the command sent to modem */
|
||
ESP_LOGI(TAG,"SEND: %s",cmd_str);
|
||
uart_ifx_uart1_send_bytes((uint8_t *)cmd_str, strlen(cmd_str));
|
||
}
|
||
/* Invoke the optional command-specific send function */
|
||
if (cmd->send) {
|
||
cmd->send();
|
||
}
|
||
|
||
transition(MODEM_STATE_CMD);
|
||
} else {
|
||
stop_rx_stream();
|
||
}
|
||
}
|
||
|
||
return retval;
|
||
}
|
||
|
||
/* Run a command sequence
|
||
* Return index of last command the suceeded,
|
||
* if it matchs the number of commands-1 then it completed.
|
||
*/
|
||
|
||
static int start_cmd_sequence(void) {
|
||
#if FAKE_COMMS
|
||
/* Don't issue any commands */
|
||
if (bg96.cmd_complete_cb) {
|
||
bg96.cmd_complete_cb(MODEM_STATUS_OK);
|
||
bg96.cmd_complete_cb = 0;
|
||
}
|
||
return MODEM_STATUS_OK;
|
||
#else
|
||
int retval = MODEM_STATUS_OK;
|
||
|
||
bg96.cmd_sequence = 0;
|
||
|
||
/* Submit each command to the command state */
|
||
if (bg96.cmd_sequence < bg96.cmd_num) {
|
||
const modem_cmd_t *cmd = bg96.cmd_list[bg96.cmd_sequence];
|
||
if (cmd) {
|
||
bg96.cmd_retries = 0;
|
||
retval = send_command(cmd);
|
||
}
|
||
} else {
|
||
/* Sequence wasn't started for whatever reason, indicate to caller
|
||
* that it is done.
|
||
*/
|
||
if (bg96.cmd_complete_cb) {
|
||
bg96.cmd_complete_cb(MODEM_STATUS_OK);
|
||
bg96.cmd_complete_cb = 0;
|
||
}
|
||
}
|
||
return retval;
|
||
#endif
|
||
}
|
||
|
||
static int end_cmd_sequence(int status) {
|
||
stop_rx_stream();
|
||
|
||
ESP_LOGI(TAG,"Ending command sequence : %d %d\r\n", bg96.is_startup, status);
|
||
|
||
/* end a command sequence
|
||
* notify callback with result
|
||
*/
|
||
if (bg96.cmd_complete_cb) {
|
||
bg96.cmd_complete_cb(status);
|
||
bg96.cmd_complete_cb = 0;
|
||
}
|
||
|
||
if (bg96.is_startup) {
|
||
bg96.is_startup = false;
|
||
/* First time in ready */
|
||
transition_ready();
|
||
} else {
|
||
/* Go back to ready - only if we were in the CMD state.
|
||
* This is to support cases where callbacks modify the state
|
||
*/
|
||
if (bg96.state == MODEM_STATE_CMD) {
|
||
transition(MODEM_STATE_READY);
|
||
}
|
||
}
|
||
|
||
return MODEM_STATUS_OK;
|
||
}
|
||
|
||
/* Go to the next command if any.
|
||
Otherwise end it successfully.
|
||
*/
|
||
static int next_cmd_sequence(void) {
|
||
int retval = MODEM_STATUS_ERROR;
|
||
|
||
if (bg96.cmd_repeat) {
|
||
ESP_LOGI(TAG,"Repeating command\r\n");
|
||
/* repeat the same command if requested by a command handler. */
|
||
bg96.cmd_repeat = false;
|
||
} else {
|
||
/* Move to next command in sequence */
|
||
bg96.cmd_sequence++;
|
||
}
|
||
|
||
ESP_LOGI(TAG,"Next command sequence: %d/%d\r\n", bg96.cmd_sequence + 1,
|
||
bg96.cmd_num);
|
||
|
||
if (bg96.cmd_sequence == bg96.cmd_num) {
|
||
/* Notify success because we've completed all commands. */
|
||
retval = end_cmd_sequence(MODEM_STATUS_OK);
|
||
|
||
} else {
|
||
const modem_cmd_t *cmd = bg96.cmd_list[bg96.cmd_sequence];
|
||
if (cmd) {
|
||
bg96.cmd_retries = 0;
|
||
retval = send_command(cmd);
|
||
}
|
||
}
|
||
return retval;
|
||
}
|
||
|
||
/* Command sequence performed by modem at each startup before entering READY state. */
|
||
static int start_ready_cmd_sequence(void) {
|
||
bg96.cmd_num = 0;
|
||
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_ECHO_OFF])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
#if BOARD_USE_CTS_RTS
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_IFC])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
#endif
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_IDENT])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
#if MODEM_MODEM_FWVER_FROM_QGMR
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_QGMR])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
#endif
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_IMEI])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_ICCID])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
#if FAKE_NETWORK
|
||
/* Set time on modem to test programming of time with CCLK otherwise
|
||
* modem's default time is year 2080!!
|
||
*/
|
||
if (MODEM_STATUS_ERROR == add_cmd(&cmd_table[AT_CMD_IDX_SETCCLK])) {
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
#endif
|
||
|
||
ESP_LOGI(TAG,"Starting READY command sequence %d\r\n", bg96.cmd_num);
|
||
|
||
return start_cmd_sequence();
|
||
}
|
||
|
||
static int start_modem(void) {
|
||
int retval = MODEM_STATUS_OK;
|
||
|
||
bg96.is_startup = true;
|
||
|
||
#if MODEM_BLIND_MODEM == 0
|
||
|
||
/* Modem already started ?! */
|
||
if (port_modem_is_on()) {
|
||
#if MODEM_DEBUG_MODEM_POWER_STATE
|
||
//board_led_green_on();
|
||
hmi_choose_led(HMI_LED_GREEN);
|
||
#endif
|
||
ESP_LOGI(TAG,"Modem already started. Interface ready.\r\n");
|
||
retval = start_ready_cmd_sequence();
|
||
} else
|
||
#endif /* MODEM_BLIND_MODEM */
|
||
{
|
||
/* Start the receive stream before we start the modem to support the
|
||
* RDY method of determining when modem interface is up.
|
||
* We go through two phase: one is waiting for status to go high, then wait
|
||
* for RDY or a timeout.
|
||
*/
|
||
retval = start_rx_stream();
|
||
port_modem_ldo_pin(1);
|
||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||
if (MODEM_STATUS_OK == retval) {
|
||
/* Start a timer to time power key duration. */
|
||
if(ESP_OK == esp_timer_start_once(modem_timer, 1000*MODEM_PWRKEY_ON_DELAY_MS))
|
||
{
|
||
retval = MODEM_STATUS_OK;
|
||
}
|
||
|
||
if (MODEM_STATUS_OK == retval) {
|
||
ESP_LOGI(TAG,"Turning on - asserting power key\r\n");
|
||
port_modem_assert_pwrkey();
|
||
transition(MODEM_STATE_WAIT_POWERUP);
|
||
#if MODEM_DEBUG_MODEM_POWER_STATE
|
||
//board_led_green_on();
|
||
hmi_choose_led(HMI_LED_GREEN);
|
||
#endif
|
||
} else {
|
||
ESP_LOGI(TAG,"Failed to turn on modem\r\n");
|
||
stop_rx_stream();
|
||
}
|
||
}
|
||
}
|
||
return retval;
|
||
}
|
||
|
||
#if MODEM_BLIND_MODEM == 0
|
||
static int stop_modem_pwrkey(void) {
|
||
int retval = MODEM_STATUS_OK;
|
||
|
||
/* Stop any timer that might be on going */
|
||
esp_timer_stop(modem_timer);
|
||
|
||
if (port_modem_is_on()) {
|
||
/* Start a timer to time power key duration. */
|
||
if(ESP_OK == esp_timer_start_once(modem_timer, 1000*MODEM_PWRKEY_OFF_DELAY_MS))
|
||
{
|
||
retval = MODEM_STATUS_OK;
|
||
}
|
||
if (MODEM_STATUS_OK == retval) {
|
||
ESP_LOGI(TAG,"Turning off - asserting power key\r\n");
|
||
bg96.shutdown_counter = 0;
|
||
bg96.shutdown_qpowd = false;
|
||
port_modem_assert_pwrkey();
|
||
transition(MODEM_STATE_WAIT_POWERKEY);
|
||
} else {
|
||
ESP_LOGI(TAG,"Failed to turn off modem\r\n");
|
||
transition(MODEM_STATE_INIT);
|
||
port_modem_ldo_pin(0);
|
||
}
|
||
} else {
|
||
ESP_LOGI(TAG,"Turning off - modem already off\r\n");
|
||
transition(MODEM_STATE_INIT);
|
||
}
|
||
return retval;
|
||
}
|
||
#endif
|
||
|
||
static void shutdown_seq_complete_cb(int retval) {
|
||
if (MODEM_STATUS_OK == retval) {
|
||
esp_timer_stop(modem_timer);
|
||
/* Start a timer to monitor STATUS for shutdown. */
|
||
if(ESP_OK == esp_timer_start_once(modem_timer, 1000*MODEM_SHUTDOWN_STATUS_MONITOR_PERIOD_MS))
|
||
{
|
||
retval = MODEM_STATUS_OK;
|
||
}
|
||
bg96.shutdown_counter = 0;
|
||
bg96.shutdown_qpowd = true;
|
||
transition(MODEM_STATE_WAIT_POWERDOWN);
|
||
} else {
|
||
ESP_LOGI(TAG,"Failed to turn off with command\r\n");
|
||
#if MODEM_BLIND_MODEM
|
||
transition(MODEM_STATE_INIT);
|
||
port_modem_ldo_pin(0);
|
||
#else
|
||
stop_modem_pwrkey();
|
||
#endif
|
||
}
|
||
}
|
||
|
||
static int stop_modem(void) {
|
||
int retval = MODEM_STATUS_OK;
|
||
|
||
/* Stop any timer that might be on going */
|
||
esp_timer_stop(modem_timer);
|
||
|
||
#if MODEM_BLIND_MODEM == 0
|
||
if (port_modem_is_on())
|
||
#endif
|
||
{
|
||
/* Start the shutdown sequence */
|
||
retval = shutdown_sequence(shutdown_seq_complete_cb);
|
||
if (MODEM_STATUS_OK != retval) {
|
||
ESP_LOGI(TAG,"Failed to turn off modem with command\r\n");
|
||
#if MODEM_BLIND_MODEM == 0
|
||
retval = stop_modem_pwrkey();
|
||
#endif
|
||
}
|
||
}
|
||
#if MODEM_BLIND_MODEM == 0
|
||
else {
|
||
ESP_LOGI(TAG,"Turning off - modem already off\r\n");
|
||
transition(MODEM_STATE_INIT);
|
||
}
|
||
#endif
|
||
return retval;
|
||
}
|
||
|
||
/* !! Wait an additional period for the UART interface to become active.
|
||
* An alternative is: (from BG96 UART app note)
|
||
* Note: AT command can be input through UART port only after module is powered
|
||
* on and the Unsolicited Result Code "RDY" is output.
|
||
* Note: observed that a 0 is output before the RDY code.
|
||
* Note: Device outputs "RDY", then later "APP RDY". It doesn't respond until APP RDY.
|
||
* Note: Normally this is about 4500 ms after bootup. In some instances, this period
|
||
* elapses without detecting "APP RDY", even though modem responds to AT commands.
|
||
*
|
||
* Notes for BG77:
|
||
* RDY seems to appear about when STATUS is raised, this is about 1-2 seconds later.
|
||
* APP RDY seems to appear about 3 seconds after RDY.
|
||
*/
|
||
static int wait_modem_ready(void) {
|
||
int retval = MODEM_STATUS_OK;
|
||
|
||
/* Note that modem rx stream was started at begining of startup process
|
||
* to capture RDY whenever it arrives
|
||
*/
|
||
if(ESP_OK == esp_timer_start_once(modem_timer, 1000*MODEM_STARTUP_RDY_TIMEOUT_MS))
|
||
{
|
||
retval = MODEM_STATUS_OK;
|
||
}
|
||
|
||
if (MODEM_STATUS_OK == retval) {
|
||
transition(MODEM_STATE_WAIT_STARTUP_RDY);
|
||
ESP_LOGI(TAG,"Waiting for AT interface activation\r\n");
|
||
}
|
||
|
||
return retval;
|
||
}
|
||
|
||
/* ------------------------------------------------------------------------- */
|
||
#if (WIFI_NEEDED == 1)
|
||
extern bool server_uart_flag;
|
||
#endif
|
||
void uart_ifx_uart1_rx_cb(void) {
|
||
bg96.poll_uart = true;
|
||
#if (WIFI_NEEDED == 1)
|
||
server_uart_flag = 1;
|
||
#endif
|
||
}
|
||
|
||
static void timer_handler(void *context)
|
||
{
|
||
bg96.poll_timer = true;
|
||
}
|
||
|
||
static int state_machine(modem_event_t evt) {
|
||
int retval = MODEM_STATUS_OK;
|
||
switch (bg96.state) {
|
||
case MODEM_STATE_INIT:
|
||
if (evt == MODEM_EVENT_START) {
|
||
/* Indicate offloading data */
|
||
//hmi_set_offload_mode(true);
|
||
ESP_LOGI(TAG,"Process started.\n");
|
||
|
||
/* Start modem and set next state */
|
||
retval = start_modem();
|
||
} else {
|
||
//ESP_LOGW(TAG,"Unhandled event %d : state %d\r\n", evt, bg96.state);
|
||
}
|
||
break;
|
||
|
||
/* wait for modem powerkey assertion delay */
|
||
case MODEM_STATE_WAIT_POWERUP:
|
||
if (evt == MODEM_EVENT_TIMER) {
|
||
//board_modem_deassert_pwrkey();
|
||
port_modem_deassert_pwrkey();
|
||
/* Start a timer to poll for status. */
|
||
if(ESP_OK == esp_timer_start_once(modem_timer, 1000*MODEM_TIMER_GRANULARITY_MS))
|
||
{
|
||
retval = MODEM_STATUS_OK;
|
||
}
|
||
bg96.poll_periods = MODEM_STARTUP_STATUS_TIMEOUT_MS
|
||
/ MODEM_TIMER_GRANULARITY_MS;
|
||
transition(MODEM_STATE_WAIT_STARTUP);
|
||
ESP_LOGI(TAG,"Waiting for status activation\r\n");
|
||
} else if (evt == MODEM_EVENT_UART) {
|
||
/* Ignore UART events */
|
||
} else {
|
||
ESP_LOGW(TAG,"Unhandled event %d : state %d\r\n", evt, bg96.state);
|
||
}
|
||
break;
|
||
|
||
/* wait for modem status to go high */
|
||
case MODEM_STATE_WAIT_STARTUP:
|
||
if (evt == MODEM_EVENT_TIMER) {
|
||
#if MODEM_BLIND_MODEM
|
||
/* Wait for the AT interface to ready */
|
||
retval = wait_modem_ready();
|
||
#else
|
||
if (port_modem_is_on()) {
|
||
/* Wait for the AT interface to ready */
|
||
retval = wait_modem_ready();
|
||
} else if (--bg96.poll_periods > 0) {
|
||
/* Keep waiting */
|
||
esp_timer_start_once(modem_timer, 1000*MODEM_TIMER_GRANULARITY_MS);
|
||
} else {
|
||
/* Timed out. */
|
||
ESP_LOGI(TAG,"Modem startup timed out\r\n");
|
||
stop_rx_stream();
|
||
transition(MODEM_STATE_INIT);
|
||
bg96.start_cb(MODEM_STATUS_ERROR);
|
||
}
|
||
#endif /* MODEM_BLIND_MODEM */
|
||
} else if (evt == MODEM_EVENT_UART) {
|
||
/* Ignore UART events */
|
||
} else {
|
||
ESP_LOGI(TAG,"Unhandled event %d : state %d\r\n", evt, bg96.state);
|
||
retval = MODEM_STATUS_ERROR;
|
||
}
|
||
break;
|
||
|
||
/* wait for modem AT interface to come up */
|
||
case MODEM_STATE_WAIT_STARTUP_RDY:
|
||
|
||
if (evt == MODEM_EVENT_UART) {
|
||
/* monitor for the modem interface "ready" indication */
|
||
int res = monitor_rx_stream("RDY", NULL);
|
||
if (MODEM_STATUS_OK == res) {
|
||
/* Stop the timeout timer waiting for APP RDY now that we have it */
|
||
/* Note: APP RDY seems to come about 3 seconds after RDY. */
|
||
esp_timer_stop(modem_timer);
|
||
ESP_LOGI(TAG,"AT interface activated.\r\n");
|
||
// hmi_set_modem_error(false); /* clear modem error on off chance it actually recovered. */
|
||
retval = start_ready_cmd_sequence();
|
||
} else {
|
||
/* Keep listening */
|
||
}
|
||
} else if (evt == MODEM_EVENT_TIMER) {
|
||
#if MODEM_BLIND_MODEM
|
||
/* clear this anyways for blind modem testing */
|
||
hmi_set_modem_error(false);
|
||
#endif
|
||
/* Timed out. */
|
||
ESP_LOGW(TAG,"timeout waiting for modem ready\r\n");
|
||
/* Start ready sequence anyways */
|
||
//retval = start_ready_cmd_sequence();
|
||
retval = MODEM_STATUS_ERROR;
|
||
} else {
|
||
ESP_LOGI(TAG,"Unhandled event %d : state %d\r\n", evt, bg96.state);
|
||
retval = MODEM_STATUS_ERROR;
|
||
}
|
||
break;
|
||
|
||
/* waiting for response from command */
|
||
case MODEM_STATE_CMD:
|
||
|
||
if (evt == MODEM_EVENT_TIMER) {
|
||
/* Timeout */
|
||
stop_rx_stream();
|
||
|
||
const modem_cmd_t *cmd = bg96.cmd_list[bg96.cmd_sequence];
|
||
if (cmd && cmd->response_match_str) {
|
||
/* We will stop the sequence unless a handler can reverse this decision by
|
||
* returning an OK or there are retries available.
|
||
*/
|
||
int res = MODEM_STATUS_ERROR;
|
||
|
||
/* If the command had no responses to wait for, invoke the handler now */
|
||
//if (cmd->response_match_str == 0 && cmd->err_match_str == 0)
|
||
{
|
||
if (cmd->handler) {
|
||
res = cmd->handler(MODEM_STATUS_TIMEOUT, rxBuf, rx_idx);
|
||
}
|
||
}
|
||
|
||
if (res == MODEM_STATUS_OK) {
|
||
/* A success response from the handler can continue the sequence. */
|
||
retval = next_cmd_sequence();
|
||
} else {
|
||
/* Handler was not available or did not reverse the error condition. */
|
||
ESP_LOGW(TAG,"Command response timed out\r\n");
|
||
|
||
/* See if we need to retry */
|
||
if (bg96.cmd_retries++ < cmd->retries) {
|
||
ESP_LOGW(TAG,"retry (%d/%d) command (%d/%d): %s\r\n",
|
||
bg96.cmd_retries, cmd->retries,
|
||
bg96.cmd_sequence + 1, bg96.cmd_num,
|
||
cmd->cmd_str);
|
||
retval = send_command(cmd);
|
||
} else {
|
||
if(cmd->cmd_str)
|
||
{
|
||
ESP_LOGW(TAG,"Command failed: %s", cmd->cmd_str); /* command strings have \r\n */
|
||
}
|
||
else
|
||
{
|
||
ESP_LOGW(TAG,"The command that has the response %s ---> get failed", cmd->response_match_str);
|
||
}
|
||
retval = end_cmd_sequence(MODEM_STATUS_ERROR);
|
||
}
|
||
}
|
||
} else if (cmd->response_match_str == 0) {
|
||
/*Check if there's a timeout handle to be executed*/
|
||
if (cmd->handler) {
|
||
/*Call the Command handler*/
|
||
cmd->handler(MODEM_STATUS_OK, rxBuf, rx_idx);
|
||
}
|
||
/*Execute the next command in the command list*/
|
||
retval = next_cmd_sequence();
|
||
}
|
||
}
|
||
else if (evt == MODEM_EVENT_UART) {
|
||
/* Process the current command */
|
||
const modem_cmd_t *cmd = bg96.cmd_list[bg96.cmd_sequence];
|
||
if (cmd && cmd->response_match_str)
|
||
{
|
||
/* monitor for responses */
|
||
int res = monitor_rx_stream(cmd->response_match_str, cmd->err_match_str);
|
||
|
||
/* Run the handler for found success or error responses */
|
||
if((MODEM_STATUS_OK == res) || (MODEM_STATUS_ERROR == res))
|
||
{
|
||
if (cmd->handler)
|
||
{
|
||
/* A success response from the handler can continue the sequence. */
|
||
ESP_LOGI(TAG," going to handler");
|
||
res = cmd->handler(res, rxBuf, rx_idx);
|
||
}
|
||
}
|
||
|
||
if (MODEM_STATUS_ERROR == res)
|
||
{
|
||
esp_timer_stop(modem_timer);
|
||
/* matched the expected error response, fail the sequence */
|
||
ESP_LOGI(TAG,"MODEM_STATUS_ERROR -> end_cmd_sequence ");
|
||
retval = end_cmd_sequence(MODEM_STATUS_ERROR);
|
||
}
|
||
else if (MODEM_STATUS_OK == res)
|
||
{
|
||
esp_timer_stop(modem_timer);
|
||
ESP_LOGI(TAG,"MODEM_STATUS_OK -> next_cmd_sequence ");
|
||
/* matched the expected success response move on to the next */
|
||
retval = next_cmd_sequence();
|
||
}
|
||
else
|
||
{
|
||
/* nothing found yet */
|
||
}
|
||
}
|
||
} else {
|
||
ESP_LOGI(TAG,"Unhandled event %d : state %d\r\n", evt, bg96.state);
|
||
retval = MODEM_STATUS_ERROR;
|
||
}
|
||
|
||
break;
|
||
|
||
case MODEM_STATE_READY:
|
||
if (evt == MODEM_EVENT_TIMER) {
|
||
|
||
} else if (evt == MODEM_EVENT_SEND_CMD) {
|
||
/* request to send a command sequence */
|
||
/* must have already been setup */
|
||
} else if (evt == MODEM_EVENT_STOP) {
|
||
ESP_LOGI(TAG,"Process stopping.\n");
|
||
retval = stop_modem();
|
||
} else {
|
||
ESP_LOGI(TAG,"Unhandled event %d : state %d\r\n", evt, bg96.state);
|
||
}
|
||
break;
|
||
|
||
case MODEM_STATE_WAIT_POWERDOWN:
|
||
if (evt == MODEM_EVENT_TIMER) {
|
||
/* Monitor STATUS for the shutdown duration. If it is still active every 10 seconds
|
||
* we note that in a warning log.
|
||
* If it doesn't shutdown after 65 seconds as datasheet says we start an LED
|
||
* error sequence.
|
||
*/
|
||
#if MODEM_BLIND_MODEM == 0
|
||
if (port_modem_is_on()) {
|
||
bg96.shutdown_counter++;
|
||
/* Start a timer to monitor STATUS for shutdown. */
|
||
if(ESP_OK == esp_timer_start_once(modem_timer, 1000*MODEM_SHUTDOWN_STATUS_MONITOR_PERIOD_MS))
|
||
{
|
||
retval = MODEM_STATUS_OK;
|
||
}
|
||
if ((bg96.shutdown_counter % MODEM_SHUTDOWN_COUNT_WARNING_SEC)
|
||
== 0) {
|
||
ESP_LOGW(TAG,"Shutting down, modem still on %d\r\n",
|
||
bg96.shutdown_counter
|
||
/ MODEM_SHUTDOWN_COUNT_WARNING_SEC);
|
||
}
|
||
|
||
if (bg96.shutdown_counter > MODEM_SHUTDOWN_COUNT_LIMIT_SEC) {
|
||
/* Waited as long as we're going to. Try power key approach if we were
|
||
* doing the QPOWD approach.
|
||
*/
|
||
if (bg96.shutdown_qpowd) {
|
||
bg96.shutdown_qpowd_failures++;
|
||
ESP_LOGI(TAG,"Failed to shutdown modem with command. %d\r\n",
|
||
bg96.shutdown_qpowd_failures);
|
||
retval = stop_modem_pwrkey();
|
||
} else {
|
||
/* This is bad. Modem does not appear to be shutdown,
|
||
* and it is likely on next power up cycle it won't
|
||
* be in the right state to use.
|
||
* Solution is to have hard power control of the modem:
|
||
* disconnect the power rails, hopefully guaranteeing
|
||
* a startup in a known state.
|
||
* Without hard power control user must remove batteries.
|
||
*/
|
||
bg96.shutdown_pwrkey_failures++;
|
||
ESP_LOGI(TAG,"Failed to shutdown modem. %d\r\n",
|
||
bg96.shutdown_pwrkey_failures);
|
||
/* Install an LED sequence to indicate this error condition.
|
||
* User would need to remove batteries to recover likely.
|
||
*/
|
||
// hmi_set_modem_error(true);
|
||
transition(MODEM_STATE_INIT);
|
||
port_modem_ldo_pin(0);
|
||
}
|
||
}
|
||
} else
|
||
#endif /* MODEM_BLIND_MODEM */
|
||
{
|
||
#if MODEM_DEBUG_MODEM_POWER_STATE
|
||
board_led_green_off();
|
||
#endif
|
||
ESP_LOGI(TAG,"Powered down, count=%d [%d %d]\r\n",
|
||
bg96.shutdown_counter, bg96.shutdown_qpowd_failures,
|
||
bg96.shutdown_pwrkey_failures);
|
||
transition(MODEM_STATE_INIT);
|
||
port_modem_ldo_pin(0);
|
||
}
|
||
} else {
|
||
ESP_LOGW(TAG,"Unhandled event %d : state %d\r\n", evt, bg96.state);
|
||
}
|
||
break;
|
||
|
||
case MODEM_STATE_WAIT_POWERKEY:
|
||
if (evt == MODEM_EVENT_TIMER) {
|
||
port_modem_deassert_pwrkey();
|
||
ESP_LOGI(TAG,"Powering down with power key.\r\n");
|
||
if(ESP_OK == esp_timer_start_once(modem_timer, 1000*MODEM_SHUTDOWN_STATUS_MONITOR_PERIOD_MS))
|
||
{
|
||
retval = MODEM_STATUS_OK;
|
||
}
|
||
transition(MODEM_STATE_WAIT_POWERDOWN);
|
||
} else {
|
||
ESP_LOGW(TAG,"Unhandled event %d : state %d\r\n", evt, bg96.state);
|
||
}
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
return retval;
|
||
}
|
||
|
||
/* ------------------------------------------------------------------------- */
|
||
|
||
/* Initialize. */
|
||
int modem_init(void) {
|
||
int retval = MODEM_STATUS_OK;
|
||
|
||
memset(&bg96, 0, sizeof(bg96));
|
||
|
||
/* Note imei is 15 character string */
|
||
memset(bg96.imei, '0', sizeof(bg96.imei) - 1);
|
||
|
||
//timer_initiating(MODEM_TIMER_ID, timer_handler);
|
||
//timer_starting(MODEM_TIMER_ID, 1000);
|
||
const esp_timer_create_args_t modem_timer_args = {
|
||
.callback = &timer_handler,
|
||
/* argument specified here will be passed to timer callback function */
|
||
.arg = (void*) modem_timer,
|
||
.name = "modem-timer"
|
||
};
|
||
esp_timer_create(&modem_timer_args, &modem_timer);
|
||
|
||
ESP_LOGI(TAG,"Process initialized.\n");
|
||
|
||
return retval;
|
||
}
|
||
|
||
/* Start the process */
|
||
int modem_start(modem_start_cb_t cb) {
|
||
|
||
#if FAKE_COMMS
|
||
/* Go directly to ready state. Add an IMEI and fw ver */
|
||
strcpy(bg96.fw_ver, "BG95M2LAR01A01"); // BG77LAR02A04
|
||
|
||
// Units deployed
|
||
//strcpy(bg96.imei, "866349041329859");
|
||
//strcpy(bg96.imei, "866349041332549");
|
||
//strcpy(bg96.imei, "866349041331970");
|
||
|
||
// 866349041329859 -> (extract) 904132985 -> (hex) 35E3F979 -> major=0x35E3 minor=0xF979
|
||
strcpy(bg96.imei, "866349041329859");
|
||
|
||
ESP_LOGI(TAG,"IMEI No: %s\r\n", bg96.imei);
|
||
config_set_device_id_from_imei(bg96.imei);
|
||
|
||
transition(MODEM_STATE_READY);
|
||
if (cb) {
|
||
cb(MODEM_STATUS_OK);
|
||
}
|
||
return MODEM_STATUS_OK;
|
||
#else
|
||
bg96.start_cb = cb;
|
||
int retval = state_machine(MODEM_EVENT_START);
|
||
//xTaskCreate(modem_poll, "BG77_POLL", 2048, NULL, 9, NULL);
|
||
return retval;
|
||
#endif
|
||
}
|
||
|
||
/* Stop the process */
|
||
int modem_stop(void) {
|
||
#if FAKE_COMMS
|
||
transition(MODEM_STATE_INIT);
|
||
return MODEM_STATUS_OK;
|
||
#else
|
||
int retval = state_machine(MODEM_EVENT_STOP);
|
||
return retval;
|
||
#endif
|
||
}
|
||
|
||
/* Poll the process */
|
||
int modem_poll(void) {
|
||
int retval = MODEM_STATUS_OK;
|
||
if (bg96.poll_timer) {
|
||
bg96.poll_timer = false;
|
||
retval = state_machine(MODEM_EVENT_TIMER);
|
||
} else if (bg96.poll_uart) {
|
||
//bg96.poll_uart = false;
|
||
retval = state_machine(MODEM_EVENT_UART);
|
||
}
|
||
|
||
return retval;
|
||
}
|
||
|
||
/* Check if the process needs to be polled */
|
||
bool modem_needs_poll(void) {
|
||
return bg96.poll_timer || bg96.poll_uart;
|
||
}
|
||
|
||
/* Check if the process is started */
|
||
bool modem_is_started(void) {
|
||
return bg96.state != MODEM_STATE_INIT;
|
||
}
|
||
|
||
/* Check if the process is ready */
|
||
bool modem_is_ready(void) {
|
||
return bg96.state == MODEM_STATE_READY;
|
||
}
|
||
|
||
const char* modem_get_imei(void) {
|
||
return bg96.imei;
|
||
}
|
||
|
||
const char* modem_get_iccid(void)
|
||
{
|
||
return bg96.iccid;
|
||
}
|
||
|
||
|
||
const modem_signal_strength_t* modem_get_signal_strength(void) {
|
||
return &bg96.sig_strength;
|
||
}
|
||
|
||
const char* modem_get_fw_ver(void) {
|
||
return bg96.fw_ver;
|
||
}
|
||
|
||
int modem_http_get_buf(char **bufptr, int *len) {
|
||
#if FAKE_COMMS || FAKE_NETWORK
|
||
|
||
#if 0 // TEST MODEM UPDATE SP5 SEQUENCE
|
||
|
||
/* First comms: GET CONFIG (ignore flags because first contact) then GET WHITELIST.
|
||
* scond comms: GET CONFIG, check flags, then GET WHITELIST
|
||
*/
|
||
static int iter = 0;
|
||
if (iter == 0) {
|
||
/* Put in a test configuration record SP3 for comms process to use */
|
||
bg96.http_params.buf = rxBuf;
|
||
/* flags scan_int_SEC scan_win_MSEC tx_pwr_DB broadcast_int_MSEC comms_int_MIN */
|
||
/* 0x1 - Whitelist
|
||
* 0x2 - MCU update
|
||
* 0x4 - Modem update
|
||
*/
|
||
bg96.http_params.len = snprintf(bg96.http_params.buf, sizeof(rxBuf), "SP3 %s 1599777618 05 15 2500 1 800 2 EP", bg96.imei);
|
||
}
|
||
else if (iter == 1) {
|
||
/* Put in a test configuration record SP4 for comms process to use */
|
||
bg96.http_params.buf = rxBuf;
|
||
bg96.http_params.len = snprintf(bg96.http_params.buf, sizeof(rxBuf), "SP4 %s 1599777618 01,0AFF4C001005511C4EAB522599000000 02,20026425603AB04037501A9E3E3EC785 03,9FFE0000000000000000000000000000 EP", bg96.imei);
|
||
|
||
}
|
||
else if (iter == 2) {
|
||
/* Put in a test configuration record SP3 for comms process to use */
|
||
bg96.http_params.buf = rxBuf;
|
||
/* flags scan_int_SEC scan_win_MSEC tx_pwr_DB broadcast_int_MSEC comms_int_MIN */
|
||
bg96.http_params.len = snprintf(bg96.http_params.buf, sizeof(rxBuf), "SP3 %s 1599777618 05 15 2500 1 800 2 EP", bg96.imei);
|
||
}
|
||
else if (iter == 3) {
|
||
/* Put in a test configuration record SP4 for comms process to use */
|
||
bg96.http_params.buf = rxBuf;
|
||
bg96.http_params.len = snprintf(bg96.http_params.buf, sizeof(rxBuf), "SP4 %s 1599777618 01,0AFF4C001005091C2AC447CC28D56500 02,000906031EC0A8014500000001000000 03,000906031EC0A8014500000001000000 EP", bg96.imei);
|
||
}
|
||
else if (iter == 4) {
|
||
/* Put in a test configuration record SP5 for comms process to use */
|
||
bg96.http_params.buf = rxBuf;
|
||
//bg96.http_params.len = snprintf(bg96.http_params.buf, sizeof(rxBuf), "SP5 %s 1599777618 BG77LAR02A04 EP", bg96.imei);
|
||
bg96.http_params.len = snprintf(bg96.http_params.buf, sizeof(rxBuf), "SP5 %s 1599777618 BG77LAR02A03 EP", bg96.imei);
|
||
}
|
||
|
||
if (++iter > 4) {
|
||
iter = 0;
|
||
}
|
||
|
||
#endif
|
||
|
||
|
||
#if 0 // TEST MCU UPDATE SP5 SEQUENCE
|
||
|
||
/* First comms: GET CONFIG (ignore flags because first contact) then GET WHITELIST.
|
||
* scond comms: GET CONFIG, check flags, then GET WHITELIST
|
||
*/
|
||
static int iter = 0;
|
||
if (iter == 0) {
|
||
/* Put in a test configuration record SP3 for comms process to use */
|
||
bg96.http_params.buf = rxBuf;
|
||
/* flags scan_int_SEC scan_win_MSEC tx_pwr_DB broadcast_int_MSEC comms_int_MIN */
|
||
/* 0x1 - Whitelist
|
||
* 0x2 - MCU update
|
||
* 0x4 - Modem update
|
||
*/
|
||
bg96.http_params.len = snprintf(bg96.http_params.buf, sizeof(rxBuf), "SP3 %s 1599777618 02 15 2500 1 800 2 EP", bg96.imei);
|
||
}
|
||
else if (iter == 1) {
|
||
/* Put in a test configuration record SP4 for comms process to use */
|
||
bg96.http_params.buf = rxBuf;
|
||
bg96.http_params.len = snprintf(bg96.http_params.buf, sizeof(rxBuf), "SP5 %s 1599777618 LRSM0005_v2 EP", bg96.imei);
|
||
|
||
}else if (iter == 2) {
|
||
/* Put in a test configuration record SP3 for comms process to use */
|
||
bg96.http_params.buf = rxBuf;
|
||
/* flags scan_int_SEC scan_win_MSEC tx_pwr_DB broadcast_int_MSEC comms_int_MIN */
|
||
bg96.http_params.len = snprintf(bg96.http_params.buf, sizeof(rxBuf), "SP3 %s 1599777618 01 15 2500 1 800 2 EP", bg96.imei);
|
||
}
|
||
else if (iter == 3) {
|
||
/* Put in a test configuration record SP4 for comms process to use */
|
||
bg96.http_params.buf = rxBuf;
|
||
bg96.http_params.len = snprintf(bg96.http_params.buf, sizeof(rxBuf), "SP4 %s 1599777618 01,0AFF4C001005091C2AC447CC28D56500 02,000906031EC0A8014500000001000000 03,000906031EC0A8014500000001000000 EP", bg96.imei);
|
||
}
|
||
else if (iter == 4) {
|
||
/* Put in a test configuration record SP5 for comms process to use */
|
||
bg96.http_params.buf = rxBuf;
|
||
//bg96.http_params.len = snprintf(bg96.http_params.buf, sizeof(rxBuf), "SP5 %s 1599777618 BG77LAR02A04 EP", bg96.imei);
|
||
bg96.http_params.len = snprintf(bg96.http_params.buf, sizeof(rxBuf), "SP5 %s 1599777618 BG77LAR02A03 EP", bg96.imei);
|
||
}
|
||
|
||
if (++iter > 4) {
|
||
iter = 0;
|
||
}
|
||
|
||
#endif
|
||
|
||
#if 1
|
||
|
||
/* First comms: GET CONFIG (ignore flags because first contact) then GET WHITELIST.
|
||
* scond comms: GET CONFIG, check flags, then GET WHITELIST
|
||
*/
|
||
static int iter = 0;
|
||
if (iter == 0) {
|
||
/* Put in a test configuration record SP3 for comms process to use */
|
||
bg96.http_params.buf = rxBuf;
|
||
/* flags scan_int_SEC scan_win_MSEC tx_pwr_DB broadcast_int_MSEC comms_int_MIN */
|
||
/* 0x1 - Whitelist
|
||
* 0x2 - MCU update
|
||
* 0x4 - Modem update
|
||
*/
|
||
bg96.http_params.len = snprintf(bg96.http_params.buf, sizeof(rxBuf), "SP3 %s 1599777618 01 15 2500 1 800 2 EP", bg96.imei);
|
||
}
|
||
else if (iter == 1) {
|
||
/* Put in a test configuration record SP4 for comms process to use */
|
||
bg96.http_params.buf = rxBuf;
|
||
bg96.http_params.len = snprintf(bg96.http_params.buf, sizeof(rxBuf), "SP4 %s 1599777618 01,0AFF4C001005511C4EAB522599000000 02,20026425603AB04037501A9E3E3EC785 03,9FFE0000000000000000000000000000 EP", bg96.imei);
|
||
|
||
}
|
||
else if (iter == 2) {
|
||
/* Put in a test configuration record SP3 for comms process to use */
|
||
bg96.http_params.buf = rxBuf;
|
||
/* flags scan_int_SEC scan_win_MSEC tx_pwr_DB broadcast_int_MSEC comms_int_MIN */
|
||
bg96.http_params.len = snprintf(bg96.http_params.buf, sizeof(rxBuf), "SP3 %s 1599777618 05 15 2500 1 800 2 EP", bg96.imei);
|
||
}
|
||
else if (iter == 3) {
|
||
/* Put in a test configuration record SP4 for comms process to use */
|
||
bg96.http_params.buf = rxBuf;
|
||
bg96.http_params.len = snprintf(bg96.http_params.buf, sizeof(rxBuf), "SP4 %s 1599777618 01,0AFF4C001005091C2AC447CC28D56500 02,000906031EC0A8014500000001000000 03,000906031EC0A8014500000001000000 EP", bg96.imei);
|
||
}
|
||
else if (iter == 4) {
|
||
/* Put in a test configuration record SP5 for comms process to use */
|
||
bg96.http_params.buf = rxBuf;
|
||
//bg96.http_params.len = snprintf(bg96.http_params.buf, sizeof(rxBuf), "SP5 %s 1599777618 BG77LAR02A04 EP", bg96.imei);
|
||
bg96.http_params.len = snprintf(bg96.http_params.buf, sizeof(rxBuf), "SP5 %s 1599777618 BG77LAR02A03 EP", bg96.imei);
|
||
}
|
||
|
||
if (++iter > 4) {
|
||
iter = 0;
|
||
}
|
||
|
||
#endif
|
||
|
||
#endif
|
||
|
||
if (bufptr && len) {
|
||
if (bg96.http_params.buf && bg96.http_params.len > 0) {
|
||
*bufptr = bg96.http_params.buf;
|
||
*len = bg96.http_params.len;
|
||
return MODEM_STATUS_OK;
|
||
}
|
||
*bufptr = 0;
|
||
*len = 0;
|
||
}
|
||
return MODEM_STATUS_ERROR;
|
||
}
|
||
|
||
/* ------ Process Callbacks ------------------------- */
|
||
|
||
__attribute__((weak)) void modem_ready_cb(void) {
|
||
}
|
||
|