mirror of
https://github.com/m5stack/M5Stack_MicroPython.git
synced 2026-05-20 10:14:44 -07:00
Updated MicroPython scheduler functions Updated all affected modules esp-idf sdspi_host driver refactored Using SDCard in SPI mode and display at the same time now works Tested on M5Stack & Adafruit 2.4" TFT Featherwing Display module refactored uses (modified) esp-idf spi-master driver 16-bit color mode added low level display functions added get TP calibration constants function added Backlight on/off function added M5Stack & GENERIC display types added display initialization sequence for unknown display types can now be handled from MicroPython tpcalib frozen module updated I2C module refactored SLAVE mode added Low level I2C functions added esp-idf i2c driver modified SPI module updated UART module updated network module updated machine module: added method for reading internal ESP32 temperature sensor _thread module: status of the system tasks is now available in _thread.list() os module: SDCard mode can now be configured from MicroPython time.ticks_xx() functions now returns correct tick count after time update rtc module updated Added MPU9250 frozen module (available on M5Stack) Experimental Bluetooth support, not yet finished Experimental support for eve display modules, not yet finished License file added License information in many source files updated/added
1532 lines
39 KiB
C
1532 lines
39 KiB
C
/*
|
|
* This file is part of the MicroPython ESP32 project, https://github.com/loboris/MicroPython_ESP32_psRAM_LoBo
|
|
*
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2018 LoBo (https://github.com/loboris)
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*/
|
|
|
|
#include "sdkconfig.h"
|
|
|
|
#ifdef CONFIG_MICROPY_USE_GSM
|
|
|
|
#include <string.h>
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
#include "esp_system.h"
|
|
#include "esp_log.h"
|
|
|
|
#include "driver/uart.h"
|
|
#include "driver/gpio.h"
|
|
#include "tcpip_adapter.h"
|
|
#include "netif/ppp/pppos.h"
|
|
#include "netif/ppp/ppp.h"
|
|
#include "lwip/pppapi.h"
|
|
|
|
#include "libs/libGSM.h"
|
|
#include "py/runtime.h"
|
|
#include "mphalport.h"
|
|
|
|
extern int MainTaskCore;
|
|
|
|
#define BUF_SIZE (1024)
|
|
#define GSM_OK_Str "OK"
|
|
#define PPPOSMUTEX_TIMEOUT 5000 / portTICK_RATE_MS
|
|
|
|
#define PPPOS_CLIENT_STACK_SIZE 1024*3
|
|
|
|
// shared variables, use mutex to access them
|
|
static uint8_t gsm_status = GSM_STATE_FIRSTINIT;
|
|
static int do_pppos_connect = 1;
|
|
static uint32_t pppos_rx_count;
|
|
static uint32_t pppos_tx_count;
|
|
static uint8_t pppos_task_started = 0;
|
|
static uint8_t gsm_rfOff = 0;
|
|
|
|
static void *New_SMS_cb = NULL;
|
|
static uint32_t SMS_check_interval = 0;
|
|
static uint8_t debug = 0;
|
|
static uint8_t doCheckSMS = 1;
|
|
|
|
// local variables
|
|
static TaskHandle_t PPPoSTaskHandle = NULL;
|
|
static QueueHandle_t pppos_mutex = NULL;
|
|
static char PPP_User[GSM_MAX_NAME_LEN] = {0};
|
|
static char PPP_Pass[GSM_MAX_NAME_LEN] = {0};
|
|
static char GSM_APN[GSM_MAX_NAME_LEN] = {0};
|
|
static int uart_num = UART_NUM_1;
|
|
static int gsm_pin_tx = UART_PIN_NO_CHANGE;
|
|
static int gsm_pin_rx = UART_PIN_NO_CHANGE;
|
|
static int gsm_pin_cts = UART_PIN_NO_CHANGE;
|
|
static int gsm_pin_rts = UART_PIN_NO_CHANGE;
|
|
static int gsm_baudrate = 115200;
|
|
static uint8_t tcpip_adapter_initialized = 0;
|
|
static uint32_t sms_timer = 0;
|
|
|
|
// The PPP control block
|
|
static ppp_pcb *ppp = NULL;
|
|
|
|
// The PPP IP interface
|
|
struct netif ppp_netif;
|
|
|
|
static const char *TAG = "[PPPOS CLIENT]";
|
|
|
|
typedef struct
|
|
{
|
|
char *cmd;
|
|
int16_t cmdSize;
|
|
char *cmdResponseOnOk;
|
|
uint16_t timeoutMs;
|
|
uint16_t delayMs;
|
|
uint8_t skip;
|
|
}GSM_Cmd;
|
|
|
|
static GSM_Cmd cmd_AT =
|
|
{
|
|
.cmd = "AT\r\n",
|
|
.cmdSize = sizeof("AT\r\n")-1,
|
|
.cmdResponseOnOk = GSM_OK_Str,
|
|
.timeoutMs = 300,
|
|
.delayMs = 0,
|
|
.skip = 0,
|
|
};
|
|
|
|
static GSM_Cmd cmd_NoSMSInd =
|
|
{
|
|
.cmd = "AT+CNMI=0,0,0,0,0\r\n",
|
|
.cmdSize = -1,
|
|
.cmdResponseOnOk = GSM_OK_Str,
|
|
.timeoutMs = 1000,
|
|
.delayMs = 0,
|
|
.skip = 0,
|
|
};
|
|
|
|
static GSM_Cmd cmd_Reset =
|
|
{
|
|
.cmd = "ATZ\r\n",
|
|
.cmdSize = -1,
|
|
.cmdResponseOnOk = GSM_OK_Str,
|
|
.timeoutMs = 300,
|
|
.delayMs = 0,
|
|
.skip = 0,
|
|
};
|
|
|
|
static GSM_Cmd cmd_RFOn =
|
|
{
|
|
.cmd = "AT+CFUN=1\r\n",
|
|
.cmdSize = -1,
|
|
.cmdResponseOnOk = GSM_OK_Str,
|
|
.timeoutMs = 10000,
|
|
.delayMs = 1000,
|
|
.skip = 0,
|
|
};
|
|
|
|
static GSM_Cmd cmd_EchoOff =
|
|
{
|
|
.cmd = "ATE0\r\n",
|
|
.cmdSize = -1,
|
|
.cmdResponseOnOk = GSM_OK_Str,
|
|
.timeoutMs = 300,
|
|
.delayMs = 0,
|
|
.skip = 0,
|
|
};
|
|
|
|
static GSM_Cmd cmd_Pin =
|
|
{
|
|
.cmd = "AT+CPIN?\r\n",
|
|
.cmdSize = -1,
|
|
.cmdResponseOnOk = "CPIN: READY",
|
|
.timeoutMs = 5000,
|
|
.delayMs = 0,
|
|
.skip = 0,
|
|
};
|
|
|
|
static GSM_Cmd cmd_Reg =
|
|
{
|
|
.cmd = "AT+CREG?\r\n",
|
|
.cmdSize = -1,
|
|
.cmdResponseOnOk = "CREG: 0,1",
|
|
.timeoutMs = 3000,
|
|
.delayMs = 2000,
|
|
.skip = 0,
|
|
};
|
|
|
|
static GSM_Cmd cmd_APN =
|
|
{
|
|
.cmd = NULL,
|
|
.cmdSize = 0,
|
|
.cmdResponseOnOk = GSM_OK_Str,
|
|
.timeoutMs = 8000,
|
|
.delayMs = 0,
|
|
.skip = 0,
|
|
};
|
|
|
|
static GSM_Cmd cmd_Connect =
|
|
{
|
|
.cmd = "AT+CGDATA=\"PPP\",1\r\n",
|
|
//.cmd = "ATDT*99***1#\r\n",
|
|
.cmdSize = -1,
|
|
.cmdResponseOnOk = "CONNECT",
|
|
.timeoutMs = 30000,
|
|
.delayMs = 1000,
|
|
.skip = 0,
|
|
};
|
|
|
|
static GSM_Cmd *GSM_Init[] =
|
|
{
|
|
&cmd_AT,
|
|
&cmd_Reset,
|
|
&cmd_EchoOff,
|
|
&cmd_RFOn,
|
|
&cmd_Pin,
|
|
&cmd_Reg,
|
|
&cmd_NoSMSInd,
|
|
&cmd_APN,
|
|
&cmd_Connect,
|
|
};
|
|
|
|
#define GSM_InitCmdsSize (sizeof(GSM_Init)/sizeof(GSM_Cmd *))
|
|
|
|
|
|
// PPP status callback
|
|
//--------------------------------------------------------------
|
|
static void ppp_status_cb(ppp_pcb *pcb, int err_code, void *ctx)
|
|
{
|
|
struct netif *pppif = ppp_netif(pcb);
|
|
LWIP_UNUSED_ARG(ctx);
|
|
|
|
switch(err_code) {
|
|
case PPPERR_NONE: {
|
|
if (debug) {
|
|
ESP_LOGI(TAG,"status_cb: Connected");
|
|
#if PPP_IPV4_SUPPORT
|
|
ESP_LOGI(TAG," ipaddr = %s", ipaddr_ntoa(&pppif->ip_addr));
|
|
ESP_LOGI(TAG," gateway = %s", ipaddr_ntoa(&pppif->gw));
|
|
ESP_LOGI(TAG," netmask = %s", ipaddr_ntoa(&pppif->netmask));
|
|
#endif
|
|
|
|
#if PPP_IPV6_SUPPORT
|
|
ESP_LOGI(TAG," ip6addr = %s", ip6addr_ntoa(netif_ip6_addr(pppif, 0)));
|
|
#endif
|
|
}
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
gsm_status = GSM_STATE_CONNECTED;
|
|
xSemaphoreGive(pppos_mutex);
|
|
break;
|
|
}
|
|
case PPPERR_PARAM: {
|
|
if (debug) {
|
|
ESP_LOGE(TAG,"status_cb: Invalid parameter");
|
|
}
|
|
break;
|
|
}
|
|
case PPPERR_OPEN: {
|
|
if (debug) {
|
|
ESP_LOGE(TAG,"status_cb: Unable to open PPP session");
|
|
}
|
|
break;
|
|
}
|
|
case PPPERR_DEVICE: {
|
|
if (debug) {
|
|
ESP_LOGE(TAG,"status_cb: Invalid I/O device for PPP");
|
|
}
|
|
break;
|
|
}
|
|
case PPPERR_ALLOC: {
|
|
if (debug) {
|
|
ESP_LOGE(TAG,"status_cb: Unable to allocate resources");
|
|
}
|
|
break;
|
|
}
|
|
case PPPERR_USER: {
|
|
/* ppp_free(); -- can be called here */
|
|
if (debug) {
|
|
ESP_LOGW(TAG,"status_cb: User interrupt (disconnected)");
|
|
}
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
gsm_status = GSM_STATE_DISCONNECTED;
|
|
xSemaphoreGive(pppos_mutex);
|
|
break;
|
|
}
|
|
case PPPERR_CONNECT: {
|
|
if (debug) {
|
|
ESP_LOGE(TAG,"status_cb: Connection lost");
|
|
}
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
gsm_status = GSM_STATE_DISCONNECTED;
|
|
xSemaphoreGive(pppos_mutex);
|
|
break;
|
|
}
|
|
case PPPERR_AUTHFAIL: {
|
|
if (debug) {
|
|
ESP_LOGE(TAG,"status_cb: Failed authentication challenge");
|
|
}
|
|
break;
|
|
}
|
|
case PPPERR_PROTOCOL: {
|
|
if (debug) {
|
|
ESP_LOGE(TAG,"status_cb: Failed to meet protocol");
|
|
}
|
|
break;
|
|
}
|
|
case PPPERR_PEERDEAD: {
|
|
if (debug) {
|
|
ESP_LOGE(TAG,"status_cb: Connection timeout");
|
|
}
|
|
break;
|
|
}
|
|
case PPPERR_IDLETIMEOUT: {
|
|
if (debug) {
|
|
ESP_LOGE(TAG,"status_cb: Idle Timeout");
|
|
}
|
|
break;
|
|
}
|
|
case PPPERR_CONNECTTIME: {
|
|
if (debug) {
|
|
ESP_LOGE(TAG,"status_cb: Max connect time reached");
|
|
}
|
|
break;
|
|
}
|
|
case PPPERR_LOOPBACK: {
|
|
if (debug) {
|
|
ESP_LOGE(TAG,"status_cb: Loopback detected");
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
if (debug) {
|
|
ESP_LOGE(TAG,"status_cb: Unknown error code %d", err_code);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// === Handle sending data to GSM modem ===
|
|
//------------------------------------------------------------------------------
|
|
static u32_t ppp_output_callback(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx)
|
|
{
|
|
uint32_t ret = uart_write_bytes(uart_num, (const char*)data, len);
|
|
uart_wait_tx_done(uart_num, 10 / portTICK_RATE_MS);
|
|
if (ret > 0) {
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
pppos_rx_count += ret;
|
|
xSemaphoreGive(pppos_mutex);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
static void infoCommand(char *cmd, int cmdSize, char *info)
|
|
{
|
|
char buf[cmdSize+2];
|
|
memset(buf, 0, cmdSize+2);
|
|
|
|
for (int i=0; i<cmdSize;i++) {
|
|
if ((cmd[i] != 0x00) && ((cmd[i] < 0x20) || (cmd[i] > 0x7F))) buf[i] = '.';
|
|
else buf[i] = cmd[i];
|
|
if (buf[i] == '\0') break;
|
|
}
|
|
ESP_LOGI(TAG,"%s [%s]", info, buf);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------------
|
|
static int atCmd_waitResponse(char * cmd, char *resp, char * resp1, int cmdSize, int timeout, char **response, int size, char *cmddata)
|
|
{
|
|
char data[256] = {'\0'};
|
|
int len, res = 1, tot = 0, timeoutCnt = 0;
|
|
size_t blen = 0;
|
|
|
|
// ** Send command to GSM
|
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
|
uart_flush(uart_num);
|
|
|
|
if (cmd != NULL) {
|
|
if (cmdSize == -1) cmdSize = strlen(cmd);
|
|
if (debug) {
|
|
infoCommand(cmd, cmdSize, "AT COMMAND:");
|
|
}
|
|
uart_write_bytes(uart_num, (const char*)cmd, cmdSize);
|
|
uart_wait_tx_done(uart_num, 100 / portTICK_RATE_MS);
|
|
}
|
|
|
|
if (response != NULL) {
|
|
// === Read GSM response into buffer ===
|
|
char *pbuf = *response;
|
|
// wait for first response data
|
|
while (blen == 0) {
|
|
uart_get_buffered_data_len(uart_num, &blen);
|
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
|
timeoutCnt += 10;
|
|
if (timeoutCnt > timeout) break;
|
|
}
|
|
len = uart_read_bytes(uart_num, (uint8_t*)data, 256, 50 / portTICK_RATE_MS);
|
|
// Add response to buffer
|
|
while (len > 0) {
|
|
if ((tot+len) >= size) {
|
|
// Need to expand the buffer
|
|
char *ptemp = realloc(pbuf, size+512);
|
|
if (ptemp == NULL) {
|
|
if (debug) {
|
|
ESP_LOGE(TAG,"AT RESPONSE (to buffer): Error reallocating buffer of size %d", size+512);
|
|
}
|
|
// Ignore any new data sent by modem
|
|
while (len > 0) {
|
|
len = uart_read_bytes(uart_num, (uint8_t*)data, 256, 100 / portTICK_RATE_MS);
|
|
}
|
|
return tot; // return success with received bytes
|
|
}
|
|
else if (debug) {
|
|
ESP_LOGD(TAG,"AT RESPONSE (to buffer): buffer reallocated, new size: %d", size+512);
|
|
}
|
|
size += 512;
|
|
pbuf = ptemp;
|
|
}
|
|
memcpy(pbuf+tot, data, len); // append response to the buffer
|
|
tot += len; // increase total received count
|
|
pbuf[tot] = '\0'; // terminate string
|
|
if (resp != NULL) {
|
|
// Check terminating string
|
|
if (strstr(pbuf, resp)) {
|
|
if (debug) {
|
|
ESP_LOGI(TAG,"RESPONSE terminator detected");
|
|
}
|
|
if (cmddata) {
|
|
if (debug) {
|
|
ESP_LOGI(TAG,"Sending data");
|
|
}
|
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
|
// Send data after response
|
|
uart_write_bytes(uart_num, (const char*)cmddata, strlen(cmddata));
|
|
uart_wait_tx_done(uart_num, 1000 / portTICK_RATE_MS);
|
|
// Read the response after the data was sent
|
|
resp = NULL;
|
|
// wait for first response data
|
|
timeoutCnt = 0;
|
|
blen = 0;
|
|
while (blen == 0) {
|
|
uart_get_buffered_data_len(uart_num, &blen);
|
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
|
timeoutCnt += 10;
|
|
if (timeoutCnt > timeout) break;
|
|
}
|
|
len = uart_read_bytes(uart_num, (uint8_t*)data, 256, 50 / portTICK_RATE_MS);
|
|
continue;
|
|
}
|
|
// Ignore any new data sent by modem
|
|
while (len > 0) {
|
|
len = uart_read_bytes(uart_num, (uint8_t*)data, 256, 100 / portTICK_RATE_MS);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
len = uart_read_bytes(uart_num, (uint8_t*)data, 256, 100 / portTICK_RATE_MS);
|
|
}
|
|
*response = pbuf;
|
|
if (debug) {
|
|
ESP_LOGI(TAG,"AT RESPONSE (to buffer): len=%d", tot);
|
|
}
|
|
return tot;
|
|
}
|
|
|
|
// === Receive response to temporary buffer, wait for and check the response ===
|
|
char sresp[256] = {'\0'};
|
|
int idx = 0;
|
|
while(1)
|
|
{
|
|
memset(data, 0, 256);
|
|
len = 0;
|
|
len = uart_read_bytes(uart_num, (uint8_t*)data, 256, 10 / portTICK_RATE_MS);
|
|
if (len > 0) {
|
|
for (int i=0; i<len;i++) {
|
|
if (idx < 256) {
|
|
if ((data[i] >= 0x20) && (data[i] < 0x80)) sresp[idx++] = data[i];
|
|
else sresp[idx++] = 0x2e;
|
|
}
|
|
}
|
|
tot += len;
|
|
}
|
|
else {
|
|
if (tot > 0) {
|
|
// Check the response
|
|
if (strstr(sresp, resp) != NULL) {
|
|
if (debug) {
|
|
ESP_LOGI(TAG,"AT RESPONSE: [%s]", sresp);
|
|
}
|
|
break;
|
|
}
|
|
else {
|
|
if (resp1 != NULL) {
|
|
if (strstr(sresp, resp1) != NULL) {
|
|
if (debug) {
|
|
ESP_LOGI(TAG,"AT RESPONSE (1): [%s]", sresp);
|
|
}
|
|
res = 2;
|
|
break;
|
|
}
|
|
}
|
|
// no match
|
|
if (debug) {
|
|
ESP_LOGI(TAG,"AT BAD RESPONSE: [%s]", sresp);
|
|
}
|
|
res = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
timeoutCnt += 10;
|
|
if (timeoutCnt > timeout) {
|
|
// timeout
|
|
if (debug) {
|
|
ESP_LOGE(TAG,"AT: TIMEOUT");
|
|
}
|
|
res = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
//------------------------------------
|
|
static void _disconnect(uint8_t rfOff)
|
|
{
|
|
int res = atCmd_waitResponse("AT\r\n", GSM_OK_Str, NULL, 4, 1000, NULL, 0, NULL);
|
|
if (res == 1) {
|
|
if (rfOff) {
|
|
cmd_Reg.timeoutMs = 10000;
|
|
res = atCmd_waitResponse("AT+CFUN=4\r\n", GSM_OK_Str, NULL, 11, 10000, NULL, 0, NULL); // disable RF function
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (debug) {
|
|
ESP_LOGI(TAG,"ONLINE, DISCONNECTING...");
|
|
}
|
|
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
|
uart_flush(uart_num);
|
|
uart_write_bytes(uart_num, "+++", 3);
|
|
uart_wait_tx_done(uart_num, 10 / portTICK_RATE_MS);
|
|
vTaskDelay(1100 / portTICK_PERIOD_MS);
|
|
|
|
int n = 0;
|
|
res = atCmd_waitResponse("ATH\r\n", GSM_OK_Str, "NO CARRIER", 5, 3000, NULL, 0, NULL);
|
|
while (res == 0) {
|
|
n++;
|
|
if (n > 10) {
|
|
if (debug) {
|
|
ESP_LOGI(TAG,"STILL CONNECTED.");
|
|
}
|
|
n = 0;
|
|
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
|
uart_flush(uart_num);
|
|
uart_write_bytes(uart_num, "+++", 3);
|
|
uart_wait_tx_done(uart_num, 10 / portTICK_RATE_MS);
|
|
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
|
}
|
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
|
res = atCmd_waitResponse("ATH\r\n", GSM_OK_Str, "NO CARRIER", 5, 3000, NULL, 0, NULL);
|
|
}
|
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
|
if (rfOff) {
|
|
cmd_Reg.timeoutMs = 10000;
|
|
res = atCmd_waitResponse("AT+CFUN=4\r\n", GSM_OK_Str, NULL, 11, 3000, NULL, 0, NULL);
|
|
}
|
|
if (debug) {
|
|
ESP_LOGI(TAG,"DISCONNECTED.");
|
|
}
|
|
}
|
|
|
|
//----------------------------
|
|
static void enableAllInitCmd()
|
|
{
|
|
for (int idx = 0; idx < GSM_InitCmdsSize; idx++) {
|
|
GSM_Init[idx]->skip = 0;
|
|
}
|
|
}
|
|
|
|
//--------------------
|
|
static void checkSMS()
|
|
{
|
|
if ((New_SMS_cb) && (SMS_check_interval > 0) && (doCheckSMS)) {
|
|
// Check for new SMS and schedule MicroPython callback function
|
|
uint8_t dbg = debug;
|
|
debug = 0;
|
|
if (sms_timer > SMS_check_interval) {
|
|
sms_timer = 0;
|
|
SMS_indexes indexes;
|
|
int nmsg = smsCount(SMS_LIST_NEW, &indexes, SMS_SORT_NONE);
|
|
if (nmsg > 0) {
|
|
if (nmsg > 100) nmsg = 100;
|
|
// Create a string containing SMS indexes
|
|
char sidx[4];
|
|
char *sindexes = calloc(nmsg*3, 1);
|
|
if (sindexes) {
|
|
for (int i=0; i<nmsg; i++) {
|
|
sprintf(sidx, "%d;", indexes.idx[i]);
|
|
strcat(sindexes, sidx);
|
|
}
|
|
mp_sched_carg_t *carg = make_cargs(MP_SCHED_CTYPE_SINGLE);
|
|
if (!carg) goto end;
|
|
if (!make_carg_entry(carg, 0, MP_SCHED_ENTRY_TYPE_STR, strlen(sindexes), (const uint8_t *)sindexes, NULL)) goto end;
|
|
|
|
mp_sched_schedule(New_SMS_cb, mp_const_none, carg);
|
|
end:
|
|
free(sindexes);
|
|
}
|
|
}
|
|
}
|
|
else sms_timer += 100;
|
|
debug = dbg;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* PPPoS TASK
|
|
* Handles GSM initialization, disconnects and GSM modem responses
|
|
*/
|
|
//-----------------------------
|
|
static void pppos_client_task()
|
|
{
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
pppos_task_started = 1;
|
|
xSemaphoreGive(pppos_mutex);
|
|
|
|
char PPP_ApnATReq[strlen(GSM_APN)+24];
|
|
// Allocate receive buffer
|
|
char* data = (char*) malloc(BUF_SIZE);
|
|
if (data == NULL) {
|
|
if (debug) {
|
|
ESP_LOGE(TAG,"Failed to allocate data buffer.");
|
|
}
|
|
goto exit;
|
|
}
|
|
|
|
uart_hw_flowcontrol_t flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
|
|
// Initialize the UART pins
|
|
if (gpio_set_direction(gsm_pin_tx, GPIO_MODE_OUTPUT)) goto exit;
|
|
if (gpio_set_direction(gsm_pin_rx, GPIO_MODE_INPUT)) goto exit;
|
|
if (gpio_set_pull_mode(gsm_pin_rx, GPIO_PULLUP_ONLY)) goto exit;
|
|
if ((gsm_pin_rts >=0) && (gsm_pin_cts >= 0)) {
|
|
if (gpio_set_direction(gsm_pin_rts, GPIO_MODE_OUTPUT)) goto exit;
|
|
if (gpio_set_direction(gsm_pin_cts, GPIO_MODE_INPUT)) goto exit;
|
|
if (gpio_set_pull_mode(gsm_pin_cts, GPIO_PULLUP_ONLY)) goto exit;
|
|
flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS;
|
|
}
|
|
else if (gsm_pin_rts >=0) {
|
|
if (gpio_set_direction(gsm_pin_rts, GPIO_MODE_OUTPUT)) goto exit;
|
|
flow_ctrl = UART_HW_FLOWCTRL_RTS;
|
|
}
|
|
else if (gsm_pin_cts >= 0) {
|
|
if (gpio_set_direction(gsm_pin_cts, GPIO_MODE_INPUT)) goto exit;
|
|
if (gpio_set_pull_mode(gsm_pin_cts, GPIO_PULLUP_ONLY)) goto exit;
|
|
flow_ctrl = UART_HW_FLOWCTRL_CTS;
|
|
}
|
|
|
|
uart_config_t uart_config = {
|
|
.baud_rate = gsm_baudrate,
|
|
.data_bits = UART_DATA_8_BITS,
|
|
.parity = UART_PARITY_DISABLE,
|
|
.stop_bits = UART_STOP_BITS_1,
|
|
.flow_ctrl = flow_ctrl
|
|
};
|
|
if (flow_ctrl & UART_HW_FLOWCTRL_RTS) uart_config.rx_flow_ctrl_thresh = UART_FIFO_LEN/2;
|
|
|
|
// Configure UART parameters
|
|
if (uart_param_config(uart_num, &uart_config)) goto exit;
|
|
// Set UART pins(TX, RX, RTS, CTS)
|
|
if (uart_set_pin(uart_num, gsm_pin_tx, gsm_pin_rx, gsm_pin_rts, gsm_pin_cts)) goto exit;
|
|
if (uart_driver_install(uart_num, BUF_SIZE * 2, BUF_SIZE * 2, 0, NULL, 0)) goto exit;
|
|
|
|
// Set APN from config
|
|
sprintf(PPP_ApnATReq, "AT+CGDCONT=1,\"IP\",\"%s\"\r\n", GSM_APN);
|
|
cmd_APN.cmd = PPP_ApnATReq;
|
|
cmd_APN.cmdSize = strlen(PPP_ApnATReq);
|
|
|
|
_disconnect(1); // Disconnect if connected
|
|
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
pppos_tx_count = 0;
|
|
pppos_rx_count = 0;
|
|
gsm_status = GSM_STATE_FIRSTINIT;
|
|
xSemaphoreGive(pppos_mutex);
|
|
|
|
enableAllInitCmd();
|
|
|
|
while(1)
|
|
{
|
|
if (debug) {
|
|
ESP_LOGI(TAG,"GSM initialization start");
|
|
}
|
|
vTaskDelay(500 / portTICK_PERIOD_MS);
|
|
|
|
if (do_pppos_connect <= 0) {
|
|
cmd_Connect.skip = 1;
|
|
cmd_APN.skip = 1;
|
|
}
|
|
int gsmCmdIter = 0;
|
|
int nfail = 0;
|
|
|
|
// ===== GSM Initialization loop =========================================================================
|
|
while(gsmCmdIter < GSM_InitCmdsSize)
|
|
{
|
|
if (GSM_Init[gsmCmdIter]->skip) {
|
|
if (debug) {
|
|
infoCommand(GSM_Init[gsmCmdIter]->cmd, GSM_Init[gsmCmdIter]->cmdSize, "Skip command:");
|
|
}
|
|
gsmCmdIter++;
|
|
continue;
|
|
}
|
|
if (atCmd_waitResponse(GSM_Init[gsmCmdIter]->cmd,
|
|
GSM_Init[gsmCmdIter]->cmdResponseOnOk, NULL,
|
|
GSM_Init[gsmCmdIter]->cmdSize,
|
|
GSM_Init[gsmCmdIter]->timeoutMs, NULL, 0, NULL) == 0)
|
|
{
|
|
// * No response or not as expected, start from first initialization command
|
|
if (debug) {
|
|
ESP_LOGW(TAG,"Wrong response, restarting...");
|
|
}
|
|
|
|
if (++nfail > 20) goto exit;
|
|
|
|
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
|
gsmCmdIter = 0;
|
|
continue;
|
|
}
|
|
|
|
if (GSM_Init[gsmCmdIter]->delayMs > 0) vTaskDelay(GSM_Init[gsmCmdIter]->delayMs / portTICK_PERIOD_MS);
|
|
GSM_Init[gsmCmdIter]->skip = 1;
|
|
if (GSM_Init[gsmCmdIter] == &cmd_Reg) GSM_Init[gsmCmdIter]->delayMs = 0;
|
|
// Next command
|
|
gsmCmdIter++;
|
|
}
|
|
// =======================================================================================================
|
|
|
|
if (debug) {
|
|
ESP_LOGI(TAG,"GSM initialized.");
|
|
}
|
|
|
|
// === GSM is now initiated ===
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
if (gsm_status == GSM_STATE_FIRSTINIT) {
|
|
// ** After first successful initialization create PPP control block
|
|
xSemaphoreGive(pppos_mutex);
|
|
ppp = pppapi_pppos_create(&ppp_netif,
|
|
ppp_output_callback, ppp_status_cb, NULL);
|
|
|
|
if (ppp == NULL) {
|
|
if (debug) {
|
|
ESP_LOGE(TAG, "Error initializing PPPoS");
|
|
}
|
|
break; // end task
|
|
}
|
|
if (debug) {
|
|
ESP_LOGI(TAG, "PPPoS control block created");
|
|
}
|
|
}
|
|
else {
|
|
gsm_status = GSM_STATE_IDLE;
|
|
xSemaphoreGive(pppos_mutex);
|
|
}
|
|
|
|
int gstat = 0;
|
|
if (do_pppos_connect <= 0) {
|
|
// === Connection to the Internet was not requested, stay in idle mode ===
|
|
if (debug) {
|
|
ESP_LOGI(TAG, "PPPoS IDLE mode");
|
|
}
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
gsm_status = GSM_STATE_IDLE;
|
|
xSemaphoreGive(pppos_mutex);
|
|
// === Wait for connect request ===
|
|
gstat = 0;
|
|
while (gstat == 0) {
|
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
gstat = do_pppos_connect;
|
|
checkSMS();
|
|
xSemaphoreGive(pppos_mutex);
|
|
}
|
|
if (gstat < 0) break; // terminate task
|
|
gsmCmdIter = 0;
|
|
enableAllInitCmd();
|
|
cmd_Connect.skip = 0;
|
|
cmd_APN.skip = 0;
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
do_pppos_connect = 1;
|
|
xSemaphoreGive(pppos_mutex);
|
|
if (debug) {
|
|
mp_hal_stdout_tx_newline();
|
|
ESP_LOGI(TAG, "Connect requested.");
|
|
}
|
|
continue;
|
|
}
|
|
if (gstat < 0) break; // terminate task
|
|
|
|
// === Connect to the Internet ===========================
|
|
pppapi_set_default(ppp);
|
|
pppapi_set_auth(ppp, PPPAUTHTYPE_PAP, PPP_User, PPP_Pass);
|
|
//pppapi_set_auth(ppp, PPPAUTHTYPE_NONE, PPP_User, PPP_Pass);
|
|
|
|
pppapi_connect(ppp, 0);
|
|
// =======================================================
|
|
gstat = 1;
|
|
|
|
// ===== LOOP: Handle GSM modem responses & disconnects =====
|
|
while(1) {
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
if (do_pppos_connect <= 0) {
|
|
// === Disconnect was requested ===
|
|
int end_task = do_pppos_connect;
|
|
do_pppos_connect = 1;
|
|
xSemaphoreGive(pppos_mutex);
|
|
if (debug) {
|
|
mp_hal_stdout_tx_newline();
|
|
ESP_LOGI(TAG, "Disconnect requested.");
|
|
}
|
|
|
|
pppapi_close(ppp, 0);
|
|
gstat = 1;
|
|
while (gsm_status != GSM_STATE_DISCONNECTED) {
|
|
// Handle data received from GSM
|
|
memset(data, 0, BUF_SIZE);
|
|
int len = uart_read_bytes(uart_num, (uint8_t*)data, BUF_SIZE, 30 / portTICK_RATE_MS);
|
|
if (len > 0) {
|
|
pppos_input_tcpip(ppp, (u8_t*)data, len);
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
pppos_tx_count += len;
|
|
xSemaphoreGive(pppos_mutex);
|
|
}
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
gstat = gsm_status;
|
|
xSemaphoreGive(pppos_mutex);
|
|
}
|
|
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
|
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
uint8_t rfoff = gsm_rfOff;
|
|
xSemaphoreGive(pppos_mutex);
|
|
_disconnect(rfoff); // Disconnect GSM if still connected
|
|
|
|
if (debug) {
|
|
ESP_LOGI(TAG, "Disconnected.");
|
|
}
|
|
|
|
gsmCmdIter = 0;
|
|
enableAllInitCmd();
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
gsm_status = GSM_STATE_IDLE;
|
|
do_pppos_connect = 0;
|
|
xSemaphoreGive(pppos_mutex);
|
|
|
|
if (end_task < 0) goto exit;
|
|
|
|
// === Wait for reconnect request ===
|
|
gstat = 0;
|
|
while (gstat == 0) {
|
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
gstat = do_pppos_connect;
|
|
checkSMS();
|
|
xSemaphoreGive(pppos_mutex);
|
|
}
|
|
if (gstat < 0) break; // terminate task
|
|
if (debug) {
|
|
mp_hal_stdout_tx_newline();
|
|
ESP_LOGI(TAG, "Reconnect requested.");
|
|
}
|
|
break;
|
|
}
|
|
|
|
// === Check if disconnected ==============
|
|
if (gsm_status == GSM_STATE_DISCONNECTED) {
|
|
gsm_status = GSM_STATE_IDLE;
|
|
xSemaphoreGive(pppos_mutex);
|
|
if (debug) {
|
|
mp_hal_stdout_tx_newline();
|
|
ESP_LOGE(TAG, "Disconnected, trying again...");
|
|
}
|
|
|
|
pppapi_close(ppp, 0);
|
|
|
|
enableAllInitCmd();
|
|
gsmCmdIter = 0;
|
|
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
|
// Initialize the GSM modem again
|
|
break;
|
|
}
|
|
else xSemaphoreGive(pppos_mutex);
|
|
|
|
// === Handle data received from GSM ================================================
|
|
memset(data, 0, BUF_SIZE);
|
|
int len = uart_read_bytes(uart_num, (uint8_t*)data, BUF_SIZE, 30 / portTICK_RATE_MS);
|
|
if (len > 0) {
|
|
pppos_input_tcpip(ppp, (u8_t*)data, len);
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
pppos_tx_count += len;
|
|
xSemaphoreGive(pppos_mutex);
|
|
}
|
|
// ==================================================================================
|
|
|
|
} // Handle GSM modem responses & disconnects loop
|
|
if (gstat < 0) break; // terminate task
|
|
} // main task loop
|
|
|
|
exit:
|
|
// Terminate GSM task
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
if (data) free(data); // free data buffer
|
|
if (ppp) ppp_free(ppp); // free PPP control block
|
|
|
|
pppos_task_started = 0;
|
|
gsm_status = GSM_STATE_FIRSTINIT;
|
|
uart_driver_delete(uart_num);
|
|
xSemaphoreGive(pppos_mutex);
|
|
|
|
if (debug) {
|
|
ESP_LOGE(TAG, "PPPoS TASK TERMINATED");
|
|
}
|
|
vTaskDelete(NULL);
|
|
}
|
|
|
|
//===================================================================================================================
|
|
int ppposInit(int tx, int rx, int rts, int cts, int bdr, char *user, char *pass, char *apn, uint8_t wait, int doconn)
|
|
{
|
|
if (pppos_mutex != NULL) xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
do_pppos_connect = doconn;
|
|
int gstat = 0;
|
|
int task_s = pppos_task_started;
|
|
if (pppos_mutex != NULL) xSemaphoreGive(pppos_mutex);
|
|
|
|
if (task_s == 0) {
|
|
// PPPoS task not running
|
|
gsm_pin_tx = tx;
|
|
gsm_pin_rx = rx;
|
|
gsm_pin_cts = cts;
|
|
gsm_pin_rts = rts;
|
|
gsm_baudrate = bdr;
|
|
strncpy(PPP_User, user, GSM_MAX_NAME_LEN);
|
|
strncpy(PPP_Pass, pass, GSM_MAX_NAME_LEN);
|
|
strncpy(GSM_APN, apn, GSM_MAX_NAME_LEN);
|
|
|
|
if (pppos_mutex == NULL) pppos_mutex = xSemaphoreCreateMutex();
|
|
if (pppos_mutex == NULL) return -1;
|
|
|
|
if (tcpip_adapter_initialized == 0) {
|
|
tcpip_adapter_init();
|
|
tcpip_adapter_initialized = 1;
|
|
}
|
|
#if CONFIG_MICROPY_USE_BOTH_CORES
|
|
xTaskCreate(&pppos_client_task, "GSM_PPPoS", PPPOS_CLIENT_STACK_SIZE, NULL, CONFIG_MICROPY_TASK_PRIORITY+1, &PPPoSTaskHandle);
|
|
#else
|
|
// Select GSM task core
|
|
int task_core = MainTaskCore;
|
|
#if !CONFIG_FREERTOS_UNICORE
|
|
if (task_core == 0) task_core = 1;
|
|
else task_core = 0;
|
|
#endif
|
|
|
|
xTaskCreatePinnedToCore(&pppos_client_task, "GSM_PPPoS", PPPOS_CLIENT_STACK_SIZE, NULL, CONFIG_MICROPY_TASK_PRIORITY+1, &PPPoSTaskHandle, task_core);
|
|
#endif
|
|
if (PPPoSTaskHandle == NULL) return -2;
|
|
|
|
while (task_s == 0) {
|
|
vTaskDelay(10 / portTICK_RATE_MS);
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
task_s = pppos_task_started;
|
|
xSemaphoreGive(pppos_mutex);
|
|
}
|
|
}
|
|
|
|
if (wait == 0) return 0;
|
|
|
|
// Wait until ready
|
|
gstat = 0;
|
|
while ((gstat != GSM_STATE_IDLE) && (gstat != GSM_STATE_CONNECTED)) {
|
|
vTaskDelay(10 / portTICK_RATE_MS);
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
gstat = gsm_status;
|
|
task_s = pppos_task_started;
|
|
xSemaphoreGive(pppos_mutex);
|
|
if (task_s == 0) return -3;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//================
|
|
int ppposConnect()
|
|
{
|
|
if (pppos_mutex == NULL) return -1;
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
do_pppos_connect = 1;
|
|
int gstat = gsm_status;
|
|
int task_s = pppos_task_started;
|
|
xSemaphoreGive(pppos_mutex);
|
|
|
|
if (task_s == 0) return -2;
|
|
if (gstat == GSM_STATE_CONNECTED) return 0;
|
|
|
|
while (gstat != 1) {
|
|
vTaskDelay(10 / portTICK_RATE_MS);
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
gstat = gsm_status;
|
|
task_s = pppos_task_started;
|
|
xSemaphoreGive(pppos_mutex);
|
|
if (task_s == 0) return 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//===================================================
|
|
void ppposDisconnect(uint8_t end_task, uint8_t rfoff)
|
|
{
|
|
if (pppos_mutex == NULL) return;
|
|
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
int gstat = gsm_status;
|
|
int task_s = pppos_task_started;
|
|
xSemaphoreGive(pppos_mutex);
|
|
|
|
if (task_s == 0) return;
|
|
|
|
if ((gstat == GSM_STATE_IDLE) && (end_task == 0)) return;
|
|
|
|
vTaskDelay(2000 / portTICK_RATE_MS);
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
if (end_task) do_pppos_connect = -1;
|
|
else do_pppos_connect = 0;
|
|
gsm_rfOff = rfoff;
|
|
xSemaphoreGive(pppos_mutex);
|
|
|
|
gstat = 0;
|
|
while ((gstat == 0) && (task_s != 0)) {
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
gstat = do_pppos_connect;
|
|
task_s = pppos_task_started;
|
|
xSemaphoreGive(pppos_mutex);
|
|
vTaskDelay(10 / portTICK_RATE_MS);
|
|
}
|
|
if (task_s == 0) return;
|
|
|
|
while ((gstat != 0) && (task_s != 0)) {
|
|
vTaskDelay(100 / portTICK_RATE_MS);
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
gstat = do_pppos_connect;
|
|
task_s = pppos_task_started;
|
|
xSemaphoreGive(pppos_mutex);
|
|
}
|
|
}
|
|
|
|
//===================
|
|
int ppposStatus()
|
|
{
|
|
if (pppos_mutex == NULL) return GSM_STATE_FIRSTINIT;
|
|
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
int gstat = gsm_status;
|
|
xSemaphoreGive(pppos_mutex);
|
|
|
|
return gstat;
|
|
}
|
|
|
|
//========================================================
|
|
void getRxTxCount(uint32_t *rx, uint32_t *tx, uint8_t rst)
|
|
{
|
|
if (pppos_mutex == NULL) {
|
|
*rx = 0;
|
|
*tx = 0;
|
|
}
|
|
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
*rx = pppos_rx_count;
|
|
*tx = pppos_tx_count;
|
|
if (rst) {
|
|
pppos_rx_count = 0;
|
|
pppos_tx_count = 0;
|
|
}
|
|
xSemaphoreGive(pppos_mutex);
|
|
}
|
|
|
|
//===================
|
|
void resetRxTxCount()
|
|
{
|
|
if (pppos_mutex == NULL) return;
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
pppos_rx_count = 0;
|
|
pppos_tx_count = 0;
|
|
xSemaphoreGive(pppos_mutex);
|
|
}
|
|
|
|
//=============
|
|
int gsm_RFOff()
|
|
{
|
|
if (pppos_mutex == NULL) return 1;
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
int gstat = gsm_status;
|
|
xSemaphoreGive(pppos_mutex);
|
|
|
|
if (gstat != GSM_STATE_IDLE) return 0;
|
|
|
|
uint8_t f = 1;
|
|
char buf[64] = {'\0'};
|
|
char *pbuf = buf;
|
|
int res = atCmd_waitResponse("AT+CFUN?\r\n", NULL, NULL, -1, 2000, &pbuf, 63, NULL);
|
|
if (res > 0) {
|
|
if (strstr(buf, "+CFUN: 4")) f = 0;
|
|
}
|
|
|
|
if (f) {
|
|
cmd_Reg.timeoutMs = 500;
|
|
return atCmd_waitResponse("AT+CFUN=4\r\n", GSM_OK_Str, NULL, 11, 10000, NULL, 0, NULL); // disable RF function
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
//============
|
|
int gsm_RFOn()
|
|
{
|
|
if (pppos_mutex == NULL) return 1;
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
int gstat = gsm_status;
|
|
xSemaphoreGive(pppos_mutex);
|
|
|
|
if (gstat != GSM_STATE_IDLE) return 0;
|
|
|
|
uint8_t f = 1;
|
|
char buf[64] = {'\0'};
|
|
char *pbuf = buf;
|
|
int res = atCmd_waitResponse("AT+CFUN?\r\n", NULL, NULL, -1, 2000, &pbuf, 63, NULL);
|
|
if (res > 0) {
|
|
if (strstr(buf, "+CFUN: 1")) f = 0;
|
|
}
|
|
|
|
if (f) {
|
|
cmd_Reg.timeoutMs = 0;
|
|
return atCmd_waitResponse("AT+CFUN=1\r\n", GSM_OK_Str, NULL, 11, 10000, NULL, 0, NULL); // disable RF function
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
// ==== SMS Functions ==========================================================================
|
|
|
|
//--------------------
|
|
static int sms_ready()
|
|
{
|
|
if (ppposStatus() != GSM_STATE_IDLE) return 0;
|
|
int ret = 0;
|
|
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
doCheckSMS = 0;
|
|
xSemaphoreGive(pppos_mutex);
|
|
|
|
int res = atCmd_waitResponse("AT+CFUN?\r\n", "+CFUN: 1", NULL, -1, 1000, NULL, 0, NULL);
|
|
if (res != 1) goto exit;
|
|
|
|
res = atCmd_waitResponse("AT+CMGF=1\r\n", GSM_OK_Str, NULL, -1, 1000, NULL, 0, NULL);
|
|
if (res != 1) goto exit;
|
|
ret = 1;
|
|
|
|
//res = atCmd_waitResponse("AT+CPMS=\"SM\"\r\n", GSM_OK_Str, NULL, -1, 1000, NULL, 0, NULL);
|
|
//if (res != 1) goto exit;
|
|
exit:
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
doCheckSMS = 1;
|
|
xSemaphoreGive(pppos_mutex);
|
|
|
|
return ret;
|
|
}
|
|
|
|
//---------------------------------------
|
|
time_t sms_time(char * msg_time, int *tz)
|
|
{
|
|
if (strlen(msg_time) >= 20) {
|
|
// Convert message time to time structure
|
|
int hh,mm,ss,yy,mn,dd, tz;
|
|
struct tm tm;
|
|
sscanf(msg_time, "%u/%u/%u,%u:%u:%u%d", &yy, &mn, &dd, &hh, &mm, &ss, &tz);
|
|
tm.tm_hour = hh;
|
|
tm.tm_min = mm;
|
|
tm.tm_sec = ss;
|
|
tm.tm_year = yy+100;
|
|
tm.tm_mon = mn-1;
|
|
tm.tm_mday = dd;
|
|
if (tz) tz = tz/4; // time zone info
|
|
return mktime(&tm); // Linux time
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Parse message in buffer to message structure
|
|
//---------------------------------------------------------------
|
|
static int getSMS(char *msgstart, SMS_Msg *msg, uint8_t msgalloc)
|
|
{
|
|
char *msgidx = msgstart;
|
|
// Clear message structure
|
|
memset(msg, 0, sizeof(SMS_Msg));
|
|
|
|
// Get message info
|
|
char *pend = strstr(msgidx, "\r\n");
|
|
if (pend == NULL) return 0;
|
|
|
|
int len = pend-msgidx;
|
|
char hdr[len+4];
|
|
char buf[32];
|
|
|
|
memset(hdr, 0, len+4);
|
|
memcpy(hdr, msgidx, len);
|
|
hdr[len] = '\0';
|
|
|
|
if (msgalloc) {
|
|
msgidx = pend + 2;
|
|
// Allocate message body buffer and copy the data
|
|
len = strlen(msgidx);
|
|
msg->msg = (char *)calloc(len+1, 1);
|
|
if (msg->msg) {
|
|
memcpy(msg->msg, msgidx, len);
|
|
msg->msg[len] = '\0';
|
|
}
|
|
}
|
|
|
|
// Parse message info
|
|
msgidx = hdr;
|
|
pend = strstr(hdr, ",\"");
|
|
int i = 1;
|
|
while (pend != NULL) {
|
|
len = pend-msgidx;
|
|
if ((len < 32) && (len > 0)) {
|
|
memset(buf, 0, 32);
|
|
strncpy(buf, msgidx, len);
|
|
buf[len] = '\0';
|
|
if (buf[len-1] == '"') buf[len-1] = '\0';
|
|
|
|
if (i == 1) {
|
|
msg->idx = (int)strtol(buf, NULL, 0); // message index
|
|
}
|
|
else if (i == 2) strcpy(msg->stat, buf); // message status
|
|
else if (i == 3) strcpy(msg->from, buf); // phone number of message sender
|
|
else if (i == 5) strcpy(msg->time, buf); // the time when the message was sent
|
|
}
|
|
i++;
|
|
msgidx = pend + 2;
|
|
pend = strstr(msgidx, ",\"");
|
|
if (pend == NULL) pend = strstr(msgidx, "\"");
|
|
}
|
|
|
|
msg->time_value = sms_time(msg->time, &msg->tz);
|
|
|
|
return 1;
|
|
}
|
|
|
|
// Get message index and time
|
|
//-----------------------------------------------------
|
|
static int getSMSindex(char *msgstart, time_t *msgtime)
|
|
{
|
|
char *msgidx = msgstart;
|
|
// Get message info
|
|
char *pend = strstr(msgidx, "\r\n");
|
|
if (pend == NULL) return 0;
|
|
|
|
int len = pend-msgidx;
|
|
char hdr[len+4];
|
|
char buf[32];
|
|
char msg_time[32] = {'\0'};
|
|
int msg_idx = 0;
|
|
|
|
memcpy(hdr, msgidx, len);
|
|
hdr[len] = '\0';
|
|
|
|
// Parse message info
|
|
msgidx = hdr;
|
|
pend = strstr(hdr, ",\"");
|
|
int i = 1;
|
|
while (pend != NULL) {
|
|
len = pend-msgidx;
|
|
if ((len < 32) && (len > 0)) {
|
|
memset(buf, 0, 32);
|
|
memcpy(buf, msgidx, len);
|
|
buf[len] = '\0';
|
|
if (buf[len-1] == '"') buf[len-1] = '\0';
|
|
|
|
if (i == 1) msg_idx = (int)strtol(buf, NULL, 0); // message index
|
|
else if (i == 5) strcpy(msg_time, buf); // the time when the message was sent
|
|
}
|
|
i++;
|
|
msgidx = pend + 2;
|
|
// find next entry
|
|
pend = strstr(msgidx, ",\"");
|
|
if (pend == NULL) pend = strstr(msgidx, "\"");
|
|
}
|
|
|
|
*msgtime = sms_time(msg_time, NULL);
|
|
|
|
return msg_idx;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------------
|
|
static int checkMessages(uint8_t rd_status, int sms_idx, SMS_Msg *msg, SMS_indexes *indexes, uint8_t sort)
|
|
{
|
|
int timeoutCnt = 0;
|
|
size_t blen = 0;
|
|
|
|
// ** Send command to GSM
|
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
|
uart_flush(uart_num);
|
|
|
|
if (rd_status == SMS_LIST_NEW) uart_write_bytes(uart_num, SMS_LIST_NEW_STR, strlen(SMS_LIST_NEW_STR));
|
|
else if (rd_status == SMS_LIST_OLD) uart_write_bytes(uart_num, SMS_LIST_OLD_STR, strlen(SMS_LIST_OLD_STR));
|
|
else uart_write_bytes(uart_num, SMS_LIST_ALL_STR, strlen(SMS_LIST_ALL_STR));
|
|
|
|
uart_wait_tx_done(uart_num, 100 / portTICK_RATE_MS);
|
|
|
|
// ** Read GSM response
|
|
// wait for first response data
|
|
while (blen == 0) {
|
|
uart_get_buffered_data_len(uart_num, &blen);
|
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
|
timeoutCnt += 10;
|
|
if (timeoutCnt > 1000) {
|
|
if (debug) {
|
|
ESP_LOGE(TAG,"Check SMS, no response (timeout)");
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (indexes !=NULL) memset(indexes, 0, sizeof(SMS_indexes));
|
|
|
|
char *rbuffer = calloc(1024, 1);
|
|
if (rbuffer == NULL) {
|
|
if (debug) {
|
|
ESP_LOGE(TAG,"Check SMS, Error allocating receive buffer");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int len, buflen = 0, nmsg = 0;
|
|
uint8_t idx_found = 0;
|
|
char *msgstart = rbuffer;
|
|
char *msgend = NULL;
|
|
char *bufptr = rbuffer;
|
|
while (1) {
|
|
len = uart_read_bytes(uart_num, (uint8_t*)bufptr, 1023-buflen, 50 / portTICK_RATE_MS);
|
|
if (len == 0) break;
|
|
buflen += len;
|
|
bufptr += len;
|
|
*bufptr = '\0';
|
|
|
|
// Check message start string
|
|
msgstart = strstr(rbuffer, "+CMGL: ");
|
|
if (msgstart) msgend = strstr(msgstart, "\r\n\r\n");
|
|
|
|
while ((msgstart) && (msgend)) {
|
|
*msgend = '\0';
|
|
// We have the whole message in the buffer
|
|
nmsg++;
|
|
if ((indexes !=NULL) && (nmsg < 33)) indexes->idx[nmsg-1] = getSMSindex(msgstart+7, &indexes->time[nmsg-1]);
|
|
if ((sms_idx == nmsg) && (msg != NULL)) {
|
|
getSMS(msgstart+7, msg, 1);
|
|
// Ignore remaining data from module
|
|
while (len > 0) {
|
|
len = uart_read_bytes(uart_num, (uint8_t*)rbuffer, 1023, 50 / portTICK_RATE_MS);
|
|
}
|
|
// and return
|
|
idx_found = 1;
|
|
break;
|
|
}
|
|
|
|
// Delete the message
|
|
memmove(rbuffer, msgend+4, buflen - (msgend-rbuffer+4));
|
|
buflen -= (msgend-rbuffer+4);
|
|
bufptr = rbuffer+buflen;
|
|
*bufptr = '\0';
|
|
|
|
// Check message start string
|
|
msgend = NULL;
|
|
msgstart = strstr(rbuffer, "+CMGL: ");
|
|
if (msgstart) msgend = strstr(msgstart, "\r\n\r\n");
|
|
}
|
|
}
|
|
|
|
free(rbuffer);
|
|
|
|
if ((msg != NULL) && (idx_found == 0)) return 0;
|
|
|
|
if ((nmsg > 0) && (indexes != NULL) && (sort != SMS_SORT_NONE)) {
|
|
// Sort messages
|
|
bool f;
|
|
int temp;
|
|
time_t tempt;
|
|
for (int i=0; i<nmsg; ++i) {
|
|
for (int j=i+1; j<nmsg; ++j) {
|
|
if (sort == SMS_SORT_ASC) f = (indexes->time[i] > indexes->time[j]);
|
|
else f = (indexes->time[i] < indexes->time[j]);
|
|
if (f) {
|
|
temp = indexes->idx[i];
|
|
tempt = indexes->time[i];
|
|
indexes->idx[i] = indexes->idx[j];
|
|
indexes->time[i] = indexes->time[j];
|
|
indexes->idx[j] = temp;
|
|
indexes->time[j] = tempt;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nmsg;
|
|
}
|
|
|
|
//==================================
|
|
int smsSend(char *smsnum, char *msg)
|
|
{
|
|
if (sms_ready() == 0) return 0;
|
|
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
doCheckSMS = 0;
|
|
xSemaphoreGive(pppos_mutex);
|
|
|
|
char *msgbuf = NULL;
|
|
int res = 0;
|
|
char buf[64];
|
|
int len = strlen(msg);
|
|
|
|
sprintf(buf, "AT+CMGS=\"%s\"\r\n", smsnum);
|
|
res = atCmd_waitResponse(buf, "> ", NULL, -1, 1000, NULL, 0, NULL);
|
|
if (res != 1) {
|
|
atCmd_waitResponse("\x1B", GSM_OK_Str, NULL, 1, 1000, NULL, 0, NULL);
|
|
res = 0;
|
|
goto exit;
|
|
}
|
|
|
|
msgbuf = malloc(len+2);
|
|
if (msgbuf == NULL) {
|
|
res = 0;
|
|
goto exit;
|
|
}
|
|
|
|
sprintf(msgbuf, "%s\x1A", msg);
|
|
res = atCmd_waitResponse(msgbuf, "+CMGS: ", "ERROR", len+1, 40000, NULL, 0, NULL);
|
|
if (res != 1) {
|
|
res = atCmd_waitResponse("\x1B", GSM_OK_Str, NULL, 1, 1000, NULL, 0, NULL);
|
|
res = 0;
|
|
}
|
|
exit:
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
doCheckSMS = 1;
|
|
xSemaphoreGive(pppos_mutex);
|
|
|
|
if (msgbuf) free(msgbuf);
|
|
return res;
|
|
}
|
|
|
|
//============================================================
|
|
int smsCount(uint8_t type, SMS_indexes *indexes, uint8_t sort)
|
|
{
|
|
if (sms_ready() == 0) return -1;
|
|
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
doCheckSMS = 0;
|
|
xSemaphoreGive(pppos_mutex);
|
|
|
|
int res = checkMessages(type, 0, NULL, indexes, sort);
|
|
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
doCheckSMS = 1;
|
|
xSemaphoreGive(pppos_mutex);
|
|
|
|
return res;
|
|
}
|
|
|
|
//===================================================================================================
|
|
int getMessagesList(uint8_t rd_status, int sms_idx, SMS_Msg *msg, SMS_indexes *indexes, uint8_t sort)
|
|
{
|
|
if (sms_ready() == 0) return -1;
|
|
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
doCheckSMS = 0;
|
|
xSemaphoreGive(pppos_mutex);
|
|
|
|
int res = checkMessages(rd_status, sms_idx, msg, indexes, sort);
|
|
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
doCheckSMS = 1;
|
|
xSemaphoreGive(pppos_mutex);
|
|
|
|
return res;
|
|
}
|
|
|
|
//====================
|
|
int smsDelete(int idx)
|
|
{
|
|
if (sms_ready() == 0) return 0;
|
|
|
|
char buf[64];
|
|
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
doCheckSMS = 0;
|
|
xSemaphoreGive(pppos_mutex);
|
|
|
|
sprintf(buf,"AT+CMGD=%d\r\n", idx);
|
|
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
doCheckSMS = 1;
|
|
xSemaphoreGive(pppos_mutex);
|
|
|
|
return atCmd_waitResponse(buf, GSM_OK_Str, NULL, -1, 5000, NULL, 0, NULL);
|
|
}
|
|
|
|
//=============================================
|
|
int setSMS_cb(void *cb_func, uint32_t interval)
|
|
{
|
|
if (pppos_mutex == NULL) return 0;
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
New_SMS_cb = cb_func;
|
|
SMS_check_interval = interval;
|
|
xSemaphoreGive(pppos_mutex);
|
|
return 1;
|
|
}
|
|
|
|
//========================
|
|
void setDebug(uint8_t dbg)
|
|
{
|
|
if (pppos_mutex != NULL) xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
debug = dbg;
|
|
if (debug) esp_log_level_set(TAG, ESP_LOG_DEBUG);
|
|
else esp_log_level_set(TAG, ESP_LOG_NONE);
|
|
if (pppos_mutex != NULL) xSemaphoreGive(pppos_mutex);
|
|
}
|
|
|
|
//=======================================*============================================
|
|
int at_Cmd(char *cmd, char* resp, char **buffer, int buf_size, int tmo, char *cmddata)
|
|
{
|
|
if (ppposStatus() != GSM_STATE_IDLE) return 0;
|
|
xSemaphoreTake(pppos_mutex, PPPOSMUTEX_TIMEOUT);
|
|
|
|
int res = atCmd_waitResponse(cmd, resp, NULL, -1, tmo, buffer, buf_size, cmddata);
|
|
|
|
xSemaphoreGive(pppos_mutex);
|
|
return res;
|
|
}
|
|
|
|
|
|
#endif
|