update
This commit is contained in:
+12
-1
@@ -1,4 +1,14 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
|
espressif/esp_codec_dev:
|
||||||
|
component_hash: 896c67360ae1f8dedaf8a53dfe48c015317fa455f061a5165307892296990028
|
||||||
|
dependencies:
|
||||||
|
- name: idf
|
||||||
|
require: private
|
||||||
|
version: '>=4.0'
|
||||||
|
source:
|
||||||
|
registry_url: https://components.espressif.com/
|
||||||
|
type: service
|
||||||
|
version: 1.5.10
|
||||||
espressif/esp_tinyusb:
|
espressif/esp_tinyusb:
|
||||||
component_hash: 8e57a14ac14d8e4d4588b5b9222977b96475323bcebae3c838919bb4e8587887
|
component_hash: 8e57a14ac14d8e4d4588b5b9222977b96475323bcebae3c838919bb4e8587887
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -49,9 +59,10 @@ dependencies:
|
|||||||
type: idf
|
type: idf
|
||||||
version: 6.0.0
|
version: 6.0.0
|
||||||
direct_dependencies:
|
direct_dependencies:
|
||||||
|
- espressif/esp_codec_dev
|
||||||
- espressif/esp_tinyusb
|
- espressif/esp_tinyusb
|
||||||
- espressif/led_strip
|
- espressif/led_strip
|
||||||
- idf
|
- idf
|
||||||
manifest_hash: 4367414e2d87717eea085884b361169910107724286ca676c237567381b84306
|
manifest_hash: ef62d5f630d2fef4437689964fe6bd9bff7fe496aa1d7a7d95e6cd6db62ff7c7
|
||||||
target: esp32s3
|
target: esp32s3
|
||||||
version: 3.0.0
|
version: 3.0.0
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ idf_component_register(SRCS "main.c"
|
|||||||
"drivers/fonts.c"
|
"drivers/fonts.c"
|
||||||
"drivers/st7789.c"
|
"drivers/st7789.c"
|
||||||
"drivers/st7789.h"
|
"drivers/st7789.h"
|
||||||
|
"drivers/servergprs.c"
|
||||||
|
"drivers/servergprs.h"
|
||||||
|
"drivers/sim800.c"
|
||||||
|
"drivers/sim800.h"
|
||||||
"drivers/tca8418.c"
|
"drivers/tca8418.c"
|
||||||
"drivers/tca8418.h"
|
"drivers/tca8418.h"
|
||||||
"drivers/ws2812.c"
|
"drivers/ws2812.c"
|
||||||
|
|||||||
+14
-114
@@ -11,6 +11,8 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define TAG "ES8311"
|
||||||
|
|
||||||
i2c_master_dev_handle_t es8311_i2c_dev;
|
i2c_master_dev_handle_t es8311_i2c_dev;
|
||||||
|
|
||||||
int es8311_write(uint8_t reg, uint8_t val) {
|
int es8311_write(uint8_t reg, uint8_t val) {
|
||||||
@@ -100,122 +102,20 @@ void es8311_init(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reset sequence
|
// Reset sequence
|
||||||
es8311_write(ES8311_RESET_REG00, 0x1F);
|
es8311_write(ES8311_RESET_REG00, 0x1F);
|
||||||
vTaskDelay(pdMS_TO_TICKS(20));
|
vTaskDelay(pdMS_TO_TICKS(20));
|
||||||
es8311_write(ES8311_RESET_REG00, 0x00);
|
es8311_write(ES8311_RESET_REG00, 0x00);
|
||||||
es8311_write(ES8311_RESET_REG00, 0x80); // Power-on
|
es8311_write(ES8311_RESET_REG00, 0x80); // Power-on command
|
||||||
vTaskDelay(pdMS_TO_TICKS(20));
|
|
||||||
|
|
||||||
// Start analog circuitry
|
es8311_write(ES8311_CLK_MANAGER_REG01,
|
||||||
es8311_write(ES8311_SYSTEM_REG0D, 0x01);
|
ES8311_CLK_MANAGER_REG01_MCLK_SEL_FROM_BCLK |
|
||||||
vTaskDelay(pdMS_TO_TICKS(20));
|
0x3F
|
||||||
|
);
|
||||||
|
|
||||||
// Configure I2S format - Slave mode
|
es8311_write(ES8311_CLK_MANAGER_REG06,
|
||||||
es8311_write(ES8311_RESET_REG00, 0x80); // Ensure slave mode
|
ES8311_CLK_MANAGER_REG06_NORMAL_BCLK |
|
||||||
|
ES8311_CLK_MANAGER_REG06_CONTINUAL_BCLK
|
||||||
es8311_write(ES8311_SDPIN_REG,
|
);
|
||||||
ES8311_SDPIN_FORMAT_I2S | ES8311_SDPIN_WORD_16BIT |
|
|
||||||
ES8311_SDPIN_LR_NORMAL_POLARITY | ES8311_SDPIN_UNMUTE |
|
|
||||||
ES8311_SDPIN_SEL_LEFT_TO_DAC);
|
|
||||||
|
|
||||||
es8311_write(ES8311_SDPOUT_REG,
|
|
||||||
ES8311_SDPOUT_FORMAT_I2S | ES8311_SDPOUT_WORD_16BIT |
|
|
||||||
ES8311_SDPOUT_LR_NORMAL_POLARITY | ES8311_SDPOUT_UNMUTE);
|
|
||||||
|
|
||||||
/*
|
|
||||||
// Clock configuration for 48kHz from BCLK
|
|
||||||
es8311_write(ES8311_CLK_MANAGER_REG01,
|
|
||||||
ES8311_CLK_MANAGER_REG01_MCLK_INV_OFF |
|
|
||||||
ES8311_CLK_MANAGER_REG01_MCLK_ON |
|
|
||||||
ES8311_CLK_MANAGER_REG01_MCLK_SEL_FROM_BCLK |
|
|
||||||
ES8311_CLK_MANAGER_REG01_BCLK_ON);
|
|
||||||
*/
|
|
||||||
|
|
||||||
es8311_write(ES8311_CLK_MANAGER_REG01,
|
|
||||||
ES8311_CLK_MANAGER_REG01_BCLK_ON);
|
|
||||||
|
|
||||||
/*
|
|
||||||
es8311_write(ES8311_CLK_MANAGER_REG02, 0x00);
|
|
||||||
es8311_write(ES8311_CLK_MANAGER_REG03, 0x10);
|
|
||||||
es8311_write(ES8311_CLK_MANAGER_REG04, 0x10);
|
|
||||||
es8311_write(ES8311_CLK_MANAGER_REG05, 0x00);
|
|
||||||
*/
|
|
||||||
|
|
||||||
// CRITICAL: Set LRCK divider
|
|
||||||
es8311_write(ES8311_CLK_MANAGER_REG06,
|
|
||||||
ES8311_CLK_MANAGER_REG06_CONTINUAL_BCLK |
|
|
||||||
ES8311_CLK_MANAGER_REG06_NORMAL_BCLK |
|
|
||||||
ES8311_CLK_MANAGER_REG06_DIV_BCLK_4);
|
|
||||||
|
|
||||||
es8311_write(ES8311_CLK_MANAGER_REG07,
|
|
||||||
ES8311_CLK_MANAGER_REG07_ADCDAT_NORMAL_MODE |
|
|
||||||
ES8311_CLK_MANAGER_REG07_BCLK_LRCLK_NORMAL_MODE);
|
|
||||||
|
|
||||||
// MISSING REGISTER - LRCK divider low byte
|
|
||||||
es8311_write(ES8311_CLK_MANAGER_REG08, 0xFF);
|
|
||||||
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(20));
|
|
||||||
|
|
||||||
// Power up and enable everything
|
|
||||||
es8311_write(ES8311_SYSTEM_REG0E, ES8311_SYSTEM_REG0E_PGA_ENABLE |
|
|
||||||
ES8311_SYSTEM_REG0E_PDN_MOD_ENABLE |
|
|
||||||
ES8311_SYSTEM_REG0E_MOD_NORMAL);
|
|
||||||
|
|
||||||
es8311_write(ES8311_SYSTEM_REG12, 0x00); // DAC on
|
|
||||||
es8311_write(ES8311_SYSTEM_REG13, 0x10); // Output enable
|
|
||||||
|
|
||||||
es8311_write(ES8311_SYSTEM_REG0F,
|
|
||||||
ES8311_SYSTEM_REG0F_DAC_NORMAL_MODE |
|
|
||||||
ES8311_SYSTEM_REG0F_PGA_NORMAL_MODE |
|
|
||||||
ES8311_SYSTEM_REG0F_PGA_OUTPUT_NORMAL_MODE |
|
|
||||||
ES8311_SYSTEM_REG0F_VCMMOD_NORMAL_MODE |
|
|
||||||
ES8311_SYSTEM_REG0F_ADC_REFERENCE_NORMAL_MODE |
|
|
||||||
ES8311_SYSTEM_REG0F_DAC_REFERENCE_NORMAL_MODE |
|
|
||||||
ES8311_SYSTEM_REG0F_FLASH_NORMAL_MODE |
|
|
||||||
ES8311_SYSTEM_REG0F_INT1_NORMAL_MODE);
|
|
||||||
|
|
||||||
// Microphone configuration
|
|
||||||
es8311_write(ES8311_SYSTEM_REG14, ES8311_SYSTEM_REG14_DMIC_OFF |
|
|
||||||
ES8311_SYSTEM_REG14_MIC1 |
|
|
||||||
ES8311_SYSTEM_REG14_GAIN_30DB);
|
|
||||||
|
|
||||||
es8311_write(ES8311_ADC_REG16, ES8311_ADC_REG16_ADC_GAIN_24DB);
|
|
||||||
|
|
||||||
es8311_write(ES8311_ADC_REG1C, ES8311_ADC_REG1C_HPF_DYNAMIC_HPF |
|
|
||||||
ES8311_ADC_REG1C_ADCEQ_BYPASS);
|
|
||||||
|
|
||||||
es8311_write(ES8311_ADC_REG18, ES8311_ADC_REG18_AUTO_LEVEL_CONTROL_ENABLE |
|
|
||||||
ES8311_ADC_REG18_AUTO_MUTE_DISABLE |
|
|
||||||
ES8311_ADC_REG18_0_25DB_PER_65536LRCK);
|
|
||||||
|
|
||||||
es8311_write(ES8311_ADC_REG19, ES8311_ADC_REG19_ALC_MIN_LEVEL_NEG_30_1DB |
|
|
||||||
ES8311_ADC_REG19_ALC_MAX_LEVEL_NEG_6_0DB);
|
|
||||||
|
|
||||||
es8311_write(ES8311_ADC_REG1A, ES8311_ADC_REG1A_AUTOMUTE_NEG_96DB |
|
|
||||||
ES8311_ADC_REG1A_AUTOMUTE_32768_SAMPLES);
|
|
||||||
|
|
||||||
es8311_write(ES8311_GPIO_REG44, ES8311_GPIO_REG44_ADCDAT_SEL_ADC_ADC |
|
|
||||||
ES8311_GPIO_REG44_ADCDAT_SEL_NO_LOOPBACK);
|
|
||||||
//ES8311_GPIO_REG44_ADCDAT_ADC_TO_DAC);
|
|
||||||
|
|
||||||
es8311_write(ES8311_ADC_REG15, ES8311_ADC_REG15_RAMPRATE_0_25_4096LRCK);
|
|
||||||
es8311_write(ES8311_DAC_REG37, ES8311_DAC_REG37_RAMPRATE_0_25_4096LRCK);
|
|
||||||
|
|
||||||
es8311_set_adc_volume(5);
|
|
||||||
es8311_set_dac_volume(5);
|
|
||||||
|
|
||||||
es8311_write(ES8311_DAC_REG31, ES8311_DAC_REG31_MUTE_TO8 |
|
|
||||||
ES8311_DAC_REG31_DSM_UNMUTE |
|
|
||||||
ES8311_DAC_REG31_DEM_UNMUTE);
|
|
||||||
|
|
||||||
es8311_write(ES8311_DAC_REG34,
|
|
||||||
ES8311_DAC_REG34_DRC_DISABLE |
|
|
||||||
ES8311_DAC_REG34_DRC_WINSIZE_0_25_65536LRCK);
|
|
||||||
|
|
||||||
es8311_write(ES8311_DAC_REG35, ES8311_DAC_REG35_DRC_MAX_LEVEL_NEG_6_0DB |
|
|
||||||
ES8311_DAC_REG35_DRC_MIN_LEVEL_NEG_30_1DB);
|
|
||||||
|
|
||||||
printf("ES8311: Initialization complete\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int audio_write(const int16_t *samples, size_t count) {
|
int audio_write(const int16_t *samples, size_t count) {
|
||||||
|
|||||||
+2
-2
@@ -51,7 +51,7 @@
|
|||||||
*/
|
*/
|
||||||
#define HEADER_CS GPIO_NUM_5
|
#define HEADER_CS GPIO_NUM_5
|
||||||
// also has i2c bus
|
// also has i2c bus
|
||||||
#define HEADER_UART_RX GPIO_NUM_13
|
#define HEADER_UART_RX GPIO_NUM_15
|
||||||
#define HEADER_UART_TX GPIO_NUM_15
|
#define HEADER_UART_TX GPIO_NUM_13
|
||||||
|
|
||||||
void set_pin_dirs();
|
void set_pin_dirs();
|
||||||
|
|||||||
@@ -0,0 +1,130 @@
|
|||||||
|
#include "servergprs.h"
|
||||||
|
|
||||||
|
#include "psa_crypto_driver_esp_aes_gcm.h"
|
||||||
|
|
||||||
|
char linebufIn[1024];
|
||||||
|
char *linebufInPtr = linebufIn;
|
||||||
|
|
||||||
|
#define MAX_FRAME 512
|
||||||
|
|
||||||
|
static uint8_t rx_buf[MAX_FRAME];
|
||||||
|
static size_t rx_len = 0;
|
||||||
|
static uint16_t expected_len = 0;
|
||||||
|
static int state = 0;
|
||||||
|
|
||||||
|
void process_encrypted_frame(uint8_t *data, size_t len)
|
||||||
|
{
|
||||||
|
// layout:
|
||||||
|
// [4B device_id][4B counter][12B nonce][ciphertext...][16B tag]
|
||||||
|
|
||||||
|
if (len < 36) return;
|
||||||
|
|
||||||
|
uint8_t *device_id = data;
|
||||||
|
uint8_t *counter = data + 4;
|
||||||
|
uint8_t *nonce = data + 8;
|
||||||
|
uint8_t *cipher = data + 20;
|
||||||
|
size_t cipher_len = len - 36;
|
||||||
|
uint8_t *tag = data + len - 16;
|
||||||
|
|
||||||
|
uint8_t plaintext[512];
|
||||||
|
size_t plaintext_len = 0;
|
||||||
|
|
||||||
|
psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT;
|
||||||
|
|
||||||
|
psa_status_t st = esp_crypto_aes_gcm_decrypt(
|
||||||
|
&attr,
|
||||||
|
shared_key,
|
||||||
|
sizeof(shared_key),
|
||||||
|
PSA_ALG_GCM,
|
||||||
|
nonce, 12,
|
||||||
|
NULL, 0,
|
||||||
|
cipher, cipher_len,
|
||||||
|
plaintext, sizeof(plaintext),
|
||||||
|
&plaintext_len
|
||||||
|
);
|
||||||
|
|
||||||
|
if (st != PSA_SUCCESS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_message(plaintext, plaintext_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_secure_packet(uint8_t *msg, size_t msg_len)
|
||||||
|
{
|
||||||
|
uint8_t nonce[12];
|
||||||
|
generate_random(nonce, 12);
|
||||||
|
|
||||||
|
uint8_t cipher[512];
|
||||||
|
size_t cipher_len = 0;
|
||||||
|
|
||||||
|
uint8_t tag[16];
|
||||||
|
size_t tag_len = 0;
|
||||||
|
|
||||||
|
esp_crypto_aes_gcm_encrypt(
|
||||||
|
&attr,
|
||||||
|
shared_key,
|
||||||
|
sizeof(shared_key),
|
||||||
|
PSA_ALG_GCM,
|
||||||
|
nonce, 12,
|
||||||
|
NULL, 0,
|
||||||
|
msg, msg_len,
|
||||||
|
cipher, sizeof(cipher),
|
||||||
|
&cipher_len
|
||||||
|
);
|
||||||
|
|
||||||
|
// build frame:
|
||||||
|
// [LEN][NONCE][CIPHER][TAG]
|
||||||
|
|
||||||
|
uint16_t total =
|
||||||
|
12 + cipher_len + 16;
|
||||||
|
|
||||||
|
uint8_t out[600];
|
||||||
|
|
||||||
|
out[0] = (total >> 8) & 0xFF;
|
||||||
|
out[1] = total & 0xFF;
|
||||||
|
|
||||||
|
memcpy(out + 2, nonce, 12);
|
||||||
|
memcpy(out + 14, cipher, cipher_len);
|
||||||
|
memcpy(out + 14 + cipher_len, tag, 16);
|
||||||
|
|
||||||
|
sim800_tcp_send(out, total + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void tcp_on_byte(char c)
|
||||||
|
{
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
// WAIT FOR LENGTH (2 bytes)
|
||||||
|
case 0:
|
||||||
|
rx_buf[rx_len++] = c;
|
||||||
|
if (rx_len == 2)
|
||||||
|
{
|
||||||
|
expected_len = (rx_buf[0] << 8) | rx_buf[1];
|
||||||
|
rx_len = 0;
|
||||||
|
|
||||||
|
if (expected_len > MAX_FRAME) {
|
||||||
|
rx_len = 0;
|
||||||
|
state = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// READ FRAME
|
||||||
|
case 1:
|
||||||
|
rx_buf[rx_len++] = c;
|
||||||
|
|
||||||
|
if (rx_len >= expected_len)
|
||||||
|
{
|
||||||
|
process_encrypted_frame(rx_buf, rx_len);
|
||||||
|
|
||||||
|
rx_len = 0;
|
||||||
|
state = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "string.h"
|
||||||
|
#include "stddef.h"
|
||||||
|
#include "ctype.h"
|
||||||
|
#include "sim800.h"
|
||||||
|
|
||||||
|
//#include <mbedtls/chachapoly.h>
|
||||||
|
|
||||||
|
extern char linebufIn[1024];
|
||||||
|
extern char *linebufInPtr;
|
||||||
|
|
||||||
|
void tcp_on_byte(char c);
|
||||||
@@ -0,0 +1,855 @@
|
|||||||
|
#include "sim800.h"
|
||||||
|
#include "drivers/pins.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "freertos/idf_additions.h"
|
||||||
|
#include "projdefs.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#define SIM800_UART UART_NUM_2
|
||||||
|
|
||||||
|
static QueueHandle_t uart_queue;
|
||||||
|
|
||||||
|
static char smsBufSend[512];
|
||||||
|
static uint8_t tcp_internal_buf[512];
|
||||||
|
static uint8_t *tcp_send_buf = NULL;
|
||||||
|
static volatile int tcp_send_len = 0;
|
||||||
|
static volatile bool tcp_waiting_prompt = false;
|
||||||
|
|
||||||
|
static volatile bool tcp_send_in_progress = false;
|
||||||
|
|
||||||
|
static char line_buf[512];
|
||||||
|
static volatile size_t line_pos = 0;
|
||||||
|
|
||||||
|
static const char *TAG = "SIM800";
|
||||||
|
|
||||||
|
static volatile bool sim_ready = false;
|
||||||
|
static volatile bool sms_ready = false;
|
||||||
|
static volatile bool sim_needs_pin = false;
|
||||||
|
|
||||||
|
static SemaphoreHandle_t sim800_done;
|
||||||
|
static bool sim800_waiting = false;
|
||||||
|
static bool sim800_result = false;
|
||||||
|
static modem_t modem;
|
||||||
|
|
||||||
|
static bool sms_waiting_prompt = false;
|
||||||
|
|
||||||
|
static SemaphoreHandle_t sim800_mutex;
|
||||||
|
|
||||||
|
static SemaphoreHandle_t sms_mutex;
|
||||||
|
|
||||||
|
void print_state() {
|
||||||
|
switch (modem.state) {
|
||||||
|
|
||||||
|
case MODEM_STATE_OFF:
|
||||||
|
ESP_LOGI(TAG, "State is OFF");
|
||||||
|
break;
|
||||||
|
case MODEM_STATE_INIT:
|
||||||
|
ESP_LOGI(TAG, "State is INIT");
|
||||||
|
break;
|
||||||
|
case MODEM_STATE_READY:
|
||||||
|
ESP_LOGI(TAG, "State is Ready");
|
||||||
|
break;
|
||||||
|
case MODEM_STATE_REGISTERING:
|
||||||
|
ESP_LOGI(TAG, "State is Registering");
|
||||||
|
break;
|
||||||
|
case MODEM_STATE_REGISTERED:
|
||||||
|
ESP_LOGI(TAG, "State is Registered");
|
||||||
|
break;
|
||||||
|
case MODEM_STATE_SMS_READY:
|
||||||
|
ESP_LOGI(TAG, "State is SMS Ready");
|
||||||
|
break;
|
||||||
|
case MODEM_STATE_CALL_ACTIVE:
|
||||||
|
ESP_LOGI(TAG, "State is Call active");
|
||||||
|
break;
|
||||||
|
case MODEM_STATE_GPRS_CONNECTING:
|
||||||
|
ESP_LOGI(TAG, "State is GPRS Connecting");
|
||||||
|
break;
|
||||||
|
case MODEM_STATE_GPRS_UP:
|
||||||
|
ESP_LOGI(TAG, "State is GPRS UP");
|
||||||
|
break;
|
||||||
|
case MODEM_STATE_TCP_CONNECTING:
|
||||||
|
ESP_LOGI(TAG, "State is TCP Connecting");
|
||||||
|
break;
|
||||||
|
case MODEM_STATE_TCP_CONNECTED:
|
||||||
|
ESP_LOGI(TAG, "State is TCP Connected");
|
||||||
|
break;
|
||||||
|
case MODEM_STATE_ERROR:
|
||||||
|
ESP_LOGI(TAG, "State is Error");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sim800_uart_init(void) {
|
||||||
|
uart_config_t uart_config = {
|
||||||
|
.baud_rate = 9600,
|
||||||
|
.data_bits = UART_DATA_8_BITS,
|
||||||
|
.parity = UART_PARITY_DISABLE,
|
||||||
|
.stop_bits = UART_STOP_BITS_1,
|
||||||
|
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||||
|
.source_clk = UART_SCLK_APB,
|
||||||
|
};
|
||||||
|
|
||||||
|
uart_driver_install(SIM800_UART, 2048, 2048, 20, &uart_queue, 0);
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "UART queue: %p", uart_queue);
|
||||||
|
|
||||||
|
uart_param_config(SIM800_UART, &uart_config);
|
||||||
|
|
||||||
|
uart_set_pin(SIM800_UART, HEADER_UART_TX, HEADER_UART_RX, UART_PIN_NO_CHANGE,
|
||||||
|
UART_PIN_NO_CHANGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void modem_update_flags(void) {
|
||||||
|
modem.in_call = (modem.state == MODEM_STATE_CALL_ACTIVE);
|
||||||
|
|
||||||
|
modem.gprs_active = (modem.state == MODEM_STATE_GPRS_UP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void modem_set_state(modem_state_t new_state) {
|
||||||
|
xSemaphoreTake(modem.state_mutex, portMAX_DELAY);
|
||||||
|
|
||||||
|
if (modem.state == new_state) {
|
||||||
|
xSemaphoreGive(modem.state_mutex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "STATE: %d -> %d", modem.state, new_state);
|
||||||
|
|
||||||
|
modem.state = new_state;
|
||||||
|
|
||||||
|
print_state();
|
||||||
|
|
||||||
|
xSemaphoreGive(modem.state_mutex);
|
||||||
|
|
||||||
|
modem_update_flags();
|
||||||
|
}
|
||||||
|
|
||||||
|
void modem_handle_event(modem_event_t ev) {
|
||||||
|
switch (modem.state) {
|
||||||
|
|
||||||
|
// -----------------------
|
||||||
|
case MODEM_STATE_INIT:
|
||||||
|
if (ev == EV_MODEM_OK) {
|
||||||
|
modem_set_state(MODEM_STATE_READY);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// -----------------------
|
||||||
|
case MODEM_STATE_READY:
|
||||||
|
if (ev == EV_NETWORK_REG_OK) {
|
||||||
|
modem_set_state(MODEM_STATE_REGISTERED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ev == EV_INCOMING_CALL) {
|
||||||
|
bool was_gprs = modem.gprs_active;
|
||||||
|
|
||||||
|
modem_set_state(MODEM_STATE_CALL_ACTIVE);
|
||||||
|
|
||||||
|
if (was_gprs) {
|
||||||
|
sim800_command("AT+CIPSHUT", 5000);
|
||||||
|
modem_handle_event(EV_GPRS_DOWN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ev == EV_SMS_RECEIVED) {
|
||||||
|
// stay in same state (SMS is async service)
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// -----------------------
|
||||||
|
case MODEM_STATE_REGISTERED:
|
||||||
|
if (ev == EV_GPRS_UP) {
|
||||||
|
modem_set_state(MODEM_STATE_GPRS_UP);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ev == EV_INCOMING_CALL) {
|
||||||
|
modem_set_state(MODEM_STATE_CALL_ACTIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ev == EV_NETWORK_LOST) {
|
||||||
|
modem_set_state(MODEM_STATE_REGISTERING);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// -----------------------
|
||||||
|
case MODEM_STATE_GPRS_UP:
|
||||||
|
if (ev == EV_GPRS_DOWN) {
|
||||||
|
modem.tcp_connected = false;
|
||||||
|
modem_set_state(MODEM_STATE_SMS_READY);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ev == EV_INCOMING_CALL) {
|
||||||
|
// SIM800 limitation: calls break data
|
||||||
|
modem_set_state(MODEM_STATE_CALL_ACTIVE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// -----------------------
|
||||||
|
case MODEM_STATE_CALL_ACTIVE:
|
||||||
|
if (ev == EV_CALL_ENDED) {
|
||||||
|
modem_set_state(MODEM_STATE_SMS_READY);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool modem_start_gprs(void) {
|
||||||
|
if (modem.state != MODEM_STATE_REGISTERED &&
|
||||||
|
modem.state != MODEM_STATE_SMS_READY)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
modem_set_state(MODEM_STATE_GPRS_CONNECTING);
|
||||||
|
|
||||||
|
// Always reset stack first
|
||||||
|
sim800_command("AT+CIPSHUT", 10000);
|
||||||
|
|
||||||
|
sim800_command("AT+CIPMUX=0", 10000);
|
||||||
|
|
||||||
|
// Ensure network attach (retry is IMPORTANT)
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
if (sim800_command("AT+CGATT=1", 3000))
|
||||||
|
break;
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sim800_command("AT+CGATT?", 2000)) {
|
||||||
|
ESP_LOGW(TAG, "CGATT check failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sim800_command("AT+CSTT=\"internet\"", 5000))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!sim800_command("AT+CIICR", 15000))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
|
|
||||||
|
sim800_command("AT+CIFSR", 100);
|
||||||
|
|
||||||
|
if (!sim800_command("AT+CIPHEAD=1", 15000))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
modem_handle_event(EV_GPRS_UP);
|
||||||
|
modem_set_state(MODEM_STATE_GPRS_UP);
|
||||||
|
ESP_LOGI(TAG, "STARTED GPRS");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sim800_csq_task(void *arg) {
|
||||||
|
while (1) {
|
||||||
|
/*
|
||||||
|
if (modem.state == MODEM_STATE_TCP_CONNECTED ||
|
||||||
|
modem.state == MODEM_STATE_GPRS_UP) {
|
||||||
|
sim800_command("AT+CSQ", 2000);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if (modem.need_gprs_restart && modem.network_registered) {
|
||||||
|
modem.need_gprs_restart = false;
|
||||||
|
ESP_LOGI(TAG, "STARTING GPRS");
|
||||||
|
print_state();
|
||||||
|
modem_start_gprs();
|
||||||
|
print_state();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
|
}
|
||||||
|
|
||||||
|
print_state();
|
||||||
|
if (modem.state == MODEM_STATE_GPRS_UP) {
|
||||||
|
sim800_tcp_connect("brn.systems", 6969);
|
||||||
|
if (modem.state != MODEM_STATE_TCP_CONNECTED) {
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(5000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sim800_task(void *arg)
|
||||||
|
{
|
||||||
|
uart_event_t event;
|
||||||
|
uint8_t *data = malloc(1024);
|
||||||
|
|
||||||
|
char lineBuf[128];
|
||||||
|
int linePos = 0;
|
||||||
|
|
||||||
|
int ipdRemaining = 0;
|
||||||
|
int ipdActive = 0;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (xQueueReceive(uart_queue, &event, portMAX_DELAY))
|
||||||
|
{
|
||||||
|
if (event.type == UART_DATA)
|
||||||
|
{
|
||||||
|
int len = uart_read_bytes(SIM800_UART, data, event.size, pdMS_TO_TICKS(100));
|
||||||
|
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
char c = data[i];
|
||||||
|
|
||||||
|
/* =========================
|
||||||
|
RAW TCP MODE (NO PARSING)
|
||||||
|
========================= */
|
||||||
|
if (ipdActive)
|
||||||
|
{
|
||||||
|
tcp_on_byte(c);
|
||||||
|
|
||||||
|
if (--ipdRemaining <= 0)
|
||||||
|
{
|
||||||
|
ipdActive = 0;
|
||||||
|
ESP_LOGI(TAG, "TCP RX END");
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =========================
|
||||||
|
CONTROL LINE BUILDING
|
||||||
|
========================= */
|
||||||
|
if (c == '\r')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (c == '\n')
|
||||||
|
{
|
||||||
|
if (linePos > 0)
|
||||||
|
{
|
||||||
|
lineBuf[linePos] = 0;
|
||||||
|
|
||||||
|
/* =========================
|
||||||
|
DETECT +IPD HEADER
|
||||||
|
========================= */
|
||||||
|
if (strncmp(lineBuf, "+IPD,", 5) == 0)
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
char *p = strchr(lineBuf, ':');
|
||||||
|
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
*p = 0;
|
||||||
|
sscanf(lineBuf, "+IPD,%d", &len);
|
||||||
|
|
||||||
|
ipdRemaining = len;
|
||||||
|
ipdActive = 1;
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "TCP RX START len=%d", len);
|
||||||
|
|
||||||
|
// if data after ':' already exists in same packet
|
||||||
|
p++;
|
||||||
|
while (*p && ipdRemaining > 0)
|
||||||
|
{
|
||||||
|
tcp_on_byte(*p++);
|
||||||
|
ipdRemaining--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ipdRemaining <= 0)
|
||||||
|
{
|
||||||
|
ipdActive = 0;
|
||||||
|
ESP_LOGI(TAG, "TCP RX END (inline)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sim800_handle_line(lineBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
linePos = 0;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =========================
|
||||||
|
BUILD LINE BUFFER (CTRL)
|
||||||
|
========================= */
|
||||||
|
if (linePos < sizeof(lineBuf) - 1)
|
||||||
|
{
|
||||||
|
lineBuf[linePos++] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.type == UART_FIFO_OVF)
|
||||||
|
{
|
||||||
|
ESP_LOGW(TAG, "FIFO overflow");
|
||||||
|
uart_flush_input(SIM800_UART);
|
||||||
|
xQueueReset(uart_queue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sim800_handle_line(char *line) {
|
||||||
|
ESP_LOGI(TAG, "LINE: [%s]", line);
|
||||||
|
|
||||||
|
// -------------------------
|
||||||
|
// COMMAND RESPONSE HANDLER
|
||||||
|
// -------------------------
|
||||||
|
if (sim800_waiting) {
|
||||||
|
|
||||||
|
if (strcmp(line, "OK") == 0) {
|
||||||
|
ESP_LOGI(TAG, "Command successful");
|
||||||
|
sim800_result = true;
|
||||||
|
sim800_waiting = false;
|
||||||
|
xSemaphoreGive(sim800_done);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(line, "ERROR") == 0) {
|
||||||
|
sim800_result = false;
|
||||||
|
sim800_waiting = false;
|
||||||
|
tcp_send_in_progress = false;
|
||||||
|
xSemaphoreGive(sim800_done);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (strstr(line, "ERROR") != 0) {
|
||||||
|
sim800_result = false;
|
||||||
|
sim800_waiting = false;
|
||||||
|
tcp_send_in_progress = false;
|
||||||
|
xSemaphoreGive(sim800_done);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------
|
||||||
|
// CALL EVENTS
|
||||||
|
// -------------------------
|
||||||
|
if (strcmp(line, "RING") == 0) {
|
||||||
|
ESP_LOGI(TAG, "Incoming call");
|
||||||
|
modem.in_call = true;
|
||||||
|
if (modem.state == MODEM_STATE_GPRS_UP) {
|
||||||
|
sim800_command("AT+CIPSHUT", 10000);
|
||||||
|
modem_handle_event(EV_GPRS_DOWN);
|
||||||
|
}
|
||||||
|
modem_handle_event(EV_INCOMING_CALL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp(line, "NO CARRIER", 11) == 0) {
|
||||||
|
ESP_LOGI(TAG, "Call ended");
|
||||||
|
modem.in_call = false;
|
||||||
|
modem_handle_event(EV_CALL_ENDED);
|
||||||
|
|
||||||
|
if (modem.network_registered) {
|
||||||
|
modem.need_gprs_restart = true;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp(line, "BUSY", 4) == 0) {
|
||||||
|
modem.in_call = false;
|
||||||
|
modem_handle_event(EV_CALL_ENDED);
|
||||||
|
if (modem.network_registered) {
|
||||||
|
modem.need_gprs_restart = true;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------
|
||||||
|
// SMS EVENTS
|
||||||
|
// -------------------------
|
||||||
|
if (strncmp(line, "+CMTI:", 6) == 0) {
|
||||||
|
int index = -1;
|
||||||
|
sscanf(line, "+CMTI: \"SM\",%d", &index);
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "New SMS at index %d", index);
|
||||||
|
|
||||||
|
char cmd[32];
|
||||||
|
snprintf(cmd, sizeof(cmd), "AT+CMGR=%d", index);
|
||||||
|
sim800_command(cmd, 5000);
|
||||||
|
|
||||||
|
modem_handle_event(EV_SMS_RECEIVED);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp(line, "+CMGR:", 6) == 0) {
|
||||||
|
ESP_LOGI(TAG, "SMS header received");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------
|
||||||
|
// SIGNAL QUALITY
|
||||||
|
// -------------------------
|
||||||
|
if (strncmp(line, "+CSQ:", 5) == 0) {
|
||||||
|
int rssi, ber;
|
||||||
|
|
||||||
|
if (sscanf(line, "+CSQ: %d,%d", &rssi, &ber) == 2) {
|
||||||
|
|
||||||
|
modem.signal = rssi;
|
||||||
|
modem.last_rssi = rssi;
|
||||||
|
modem.last_ber = ber;
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "CSQ RSSI=%d BER=%d", rssi, ber);
|
||||||
|
|
||||||
|
// Optional: trigger behavior
|
||||||
|
if (rssi == 99) {
|
||||||
|
ESP_LOGW(TAG, "No signal");
|
||||||
|
} else if (rssi < 10) {
|
||||||
|
ESP_LOGW(TAG, "Weak signal");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------
|
||||||
|
// NETWORK REGISTRATION
|
||||||
|
// -------------------------
|
||||||
|
if (strncmp(line, "+CREG:", 6) == 0) {
|
||||||
|
ESP_LOGI(TAG, "Network registration: %s", line);
|
||||||
|
int n, stat;
|
||||||
|
if (strlen(line) > 10) {
|
||||||
|
sscanf(line, "+CREG: %d,%d", &n, &stat);
|
||||||
|
ESP_LOGI(TAG, "Network registration data: %d,%d", n, stat);
|
||||||
|
|
||||||
|
if (stat == 1 || stat == 5) {
|
||||||
|
modem.network_registered = 1;
|
||||||
|
ESP_LOGI(TAG, "REGISTERED");
|
||||||
|
modem_handle_event(EV_NETWORK_REG_OK);
|
||||||
|
} else {
|
||||||
|
modem.network_registered = 0;
|
||||||
|
modem_handle_event(EV_NETWORK_LOST);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sscanf(line, "+CREG: %d", &stat);
|
||||||
|
ESP_LOGI(TAG, "Network registration data: %d,%d", stat);
|
||||||
|
|
||||||
|
if (stat == 1 || stat == 5) {
|
||||||
|
modem.network_registered = 1;
|
||||||
|
ESP_LOGI(TAG, "REGISTERED");
|
||||||
|
modem_handle_event(EV_NETWORK_REG_OK);
|
||||||
|
} else {
|
||||||
|
modem.network_registered = 0;
|
||||||
|
modem_handle_event(EV_NETWORK_LOST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------
|
||||||
|
// GPRS / DATA EVENTS
|
||||||
|
// -------------------------
|
||||||
|
if (strncmp(line, "CONNECT OK", 10) == 0) {
|
||||||
|
ESP_LOGI(TAG, "TCP connected");
|
||||||
|
modem_set_state(MODEM_STATE_TCP_CONNECTED);
|
||||||
|
|
||||||
|
modem.tcp_connected = true;
|
||||||
|
|
||||||
|
modem_set_state(MODEM_STATE_TCP_CONNECTED);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strstr(line, "CONNECT FAIL")) {
|
||||||
|
modem.tcp_connected = false;
|
||||||
|
modem_set_state(MODEM_STATE_GPRS_UP);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strstr(line, "+CPIN: READY")) {
|
||||||
|
sim_ready = true;
|
||||||
|
modem_handle_event(EV_MODEM_OK);
|
||||||
|
ESP_LOGI(TAG, "SIM ready");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strstr(line, "+CPIN: SIM PIN")) {
|
||||||
|
sim_needs_pin = true;
|
||||||
|
ESP_LOGI(TAG, "SIM needs pin");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strstr(line, "CALL Ready")) {
|
||||||
|
modem.network_registered = 1;
|
||||||
|
ESP_LOGI(TAG, "SMS subsystem ready");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strstr(line, "SMS Ready")) {
|
||||||
|
sms_ready = true;
|
||||||
|
modem.network_registered = 1;
|
||||||
|
ESP_LOGI(TAG, "SMS subsystem ready");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp(line, "SEND OK", 7) == 0) {
|
||||||
|
ESP_LOGI(TAG, "Data sent");
|
||||||
|
tcp_send_in_progress = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp(line, "CLOSED", 6) == 0) {
|
||||||
|
tcp_send_in_progress = false;
|
||||||
|
modem.tcp_connected = false;
|
||||||
|
modem_set_state(MODEM_STATE_GPRS_UP);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (strncmp(line, "+IPD,", 5) == 0) {
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "TCP DATA: %s", line);
|
||||||
|
|
||||||
|
int len = 0;
|
||||||
|
sscanf(line, "+IPD,%d", &len);
|
||||||
|
// format: +IPD,len:data
|
||||||
|
char *p = strchr(line, ':');
|
||||||
|
if (p) {
|
||||||
|
p++;
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "RX TCP payload: %s", p);
|
||||||
|
|
||||||
|
// TODO: forward to your app layer
|
||||||
|
tcp_on_data(p, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (strncmp(line, "+RECEIVE", 8) == 0) {
|
||||||
|
|
||||||
|
char *payload = strchr(line, ':');
|
||||||
|
|
||||||
|
int pipe = 0;
|
||||||
|
if (payload) {
|
||||||
|
payload++; // skip ':'
|
||||||
|
int len = 0;
|
||||||
|
sscanf(line, "+RECEIVE,%d,%d", &pipe, &len);
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "TCP RX (%d): %.*s", pipe, len, payload);
|
||||||
|
|
||||||
|
tcp_on_data(payload, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void sim800_parse(char *data) {
|
||||||
|
while (*data) {
|
||||||
|
|
||||||
|
char c = *data++;
|
||||||
|
|
||||||
|
putchar(c);
|
||||||
|
|
||||||
|
if (c == '\r')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (line_buf[0] == '>') {
|
||||||
|
|
||||||
|
if (sms_waiting_prompt) {
|
||||||
|
sms_waiting_prompt = false;
|
||||||
|
|
||||||
|
uart_write_bytes(SIM800_UART, smsBufSend, strlen(smsBufSend));
|
||||||
|
uint8_t ctrlz = 0x1A;
|
||||||
|
uart_write_bytes(SIM800_UART, &ctrlz, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tcp_waiting_prompt) {
|
||||||
|
ESP_LOGI(TAG, "Got TCP >");
|
||||||
|
tcp_waiting_prompt = false;
|
||||||
|
|
||||||
|
uart_write_bytes(SIM800_UART, tcp_send_buf, tcp_send_len);
|
||||||
|
|
||||||
|
uint8_t ctrlz = 0x1A;
|
||||||
|
uart_write_bytes(SIM800_UART, &ctrlz, 1);
|
||||||
|
tcp_send_in_progress = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '\n') {
|
||||||
|
|
||||||
|
if (line_pos > 0) {
|
||||||
|
|
||||||
|
line_buf[line_pos] = 0;
|
||||||
|
|
||||||
|
sim800_handle_line(line_buf);
|
||||||
|
|
||||||
|
line_pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line_pos < sizeof(line_buf) - 1) {
|
||||||
|
line_buf[line_pos++] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sim800_send(const char *cmd) {
|
||||||
|
ESP_LOGI(TAG, "TX: %s", cmd);
|
||||||
|
|
||||||
|
uart_write_bytes(SIM800_UART, cmd, strlen(cmd));
|
||||||
|
|
||||||
|
uart_write_bytes(SIM800_UART, "\r\n", 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sim800_command(const char *cmd, uint32_t timeout_ms) {
|
||||||
|
xSemaphoreTake(sim800_mutex, portMAX_DELAY);
|
||||||
|
|
||||||
|
sim800_waiting = true;
|
||||||
|
sim800_result = false;
|
||||||
|
|
||||||
|
sim800_send(cmd);
|
||||||
|
|
||||||
|
bool ok = xSemaphoreTake(sim800_done, pdMS_TO_TICKS(timeout_ms));
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
sim800_waiting = false; // important cleanup
|
||||||
|
ESP_LOGW(TAG, "Timeout");
|
||||||
|
|
||||||
|
xSemaphoreGive(sim800_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool result = sim800_result;
|
||||||
|
|
||||||
|
sim800_waiting = false;
|
||||||
|
xSemaphoreGive(sim800_mutex);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_modem(void *arg) {
|
||||||
|
modem.state_mutex = xSemaphoreCreateMutex();
|
||||||
|
modem.state = MODEM_STATE_INIT;
|
||||||
|
modem.network_registered = 0;
|
||||||
|
modem.in_call = false;
|
||||||
|
modem.gprs_active = false;
|
||||||
|
modem.need_gprs_restart = true;
|
||||||
|
sim800_done = xSemaphoreCreateBinary();
|
||||||
|
sim800_mutex = xSemaphoreCreateMutex();
|
||||||
|
sms_mutex = xSemaphoreCreateMutex();
|
||||||
|
xTaskCreate(sim800_task, "sim800_task", 4096, NULL, 10, NULL);
|
||||||
|
sim800_command("AT+CFUN=1,1", 1);
|
||||||
|
while (1) {
|
||||||
|
if (sim800_command("AT", 1000)) {
|
||||||
|
ESP_LOGI(TAG, "Modem alive");
|
||||||
|
sim800_command("ATE0", 100);
|
||||||
|
sim800_command("AT+IPR=115200", 100);
|
||||||
|
uart_set_baudrate(SIM800_UART, 115200);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(50));
|
||||||
|
while (!sim_needs_pin) {
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
|
}
|
||||||
|
sim800_command("AT+CPIN=\"1577\"", 5000); // change to used sim, this is a test pin
|
||||||
|
while (!sim_ready) {
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
while (!sms_ready) {
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
sim800_command("AT+CREG=1", 3000);
|
||||||
|
while (!modem.network_registered) {
|
||||||
|
sim800_command("AT+CREG?", 3000);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
|
}
|
||||||
|
sim800_command("AT+CMEE=2", 100);
|
||||||
|
sim800_command("AT+CMGF=1", 3000);
|
||||||
|
sim800_command("AT+CNMI=2,1,0,0,0", 3000);
|
||||||
|
xTaskCreate(sim800_csq_task, "csq_task", 3072, NULL, 5, NULL);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
ESP_LOGE(TAG, "No response");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (1) {
|
||||||
|
vTaskDelay(pdTICKS_TO_MS(1000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sim800_send_sms(const char *number, const char *msg) {
|
||||||
|
xSemaphoreTake(sms_mutex, portMAX_DELAY);
|
||||||
|
|
||||||
|
strcpy(smsBufSend, msg);
|
||||||
|
|
||||||
|
char cmd[64];
|
||||||
|
snprintf(cmd, sizeof(cmd), "AT+CMGS=\"%s\"", number);
|
||||||
|
|
||||||
|
sms_waiting_prompt = true;
|
||||||
|
sim800_send(cmd);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sim800_call(const char *number) {
|
||||||
|
if (modem.gprs_active) {
|
||||||
|
sim800_command("AT+CIPSHUT", 5000);
|
||||||
|
modem_handle_event(EV_GPRS_DOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
char cmd[64];
|
||||||
|
snprintf(cmd, sizeof(cmd), "ATD%s;", number);
|
||||||
|
|
||||||
|
return sim800_command(cmd, 15000);
|
||||||
|
}
|
||||||
|
bool sim800_hangup(void) { return sim800_command("ATH", 3000); }
|
||||||
|
|
||||||
|
bool sim800_answer(void) { return sim800_command("ATA", 5000); }
|
||||||
|
|
||||||
|
bool sim800_tcp_connect(const char *host, int port) {
|
||||||
|
if (modem.state != MODEM_STATE_GPRS_UP)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
snprintf(modem.tcp_host, sizeof(modem.tcp_host), "%s", host);
|
||||||
|
modem.tcp_port = port;
|
||||||
|
|
||||||
|
modem_set_state(MODEM_STATE_TCP_CONNECTING);
|
||||||
|
|
||||||
|
char cmd[128];
|
||||||
|
snprintf(cmd, sizeof(cmd), "AT+CIPSTART=\"TCP\",\"%s\",\"%d\"", host, port);
|
||||||
|
|
||||||
|
if (!sim800_command(cmd, 15000)) {
|
||||||
|
modem_set_state(MODEM_STATE_GPRS_UP);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sim800_tcp_send(const void *data, int len) {
|
||||||
|
if (modem.state != MODEM_STATE_TCP_CONNECTED)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (tcp_send_in_progress)
|
||||||
|
return false;
|
||||||
|
tcp_send_in_progress = true;
|
||||||
|
|
||||||
|
xSemaphoreTake(sim800_mutex, portMAX_DELAY);
|
||||||
|
|
||||||
|
memcpy(tcp_internal_buf, data, len);
|
||||||
|
tcp_send_buf = tcp_internal_buf;
|
||||||
|
tcp_send_len = len;
|
||||||
|
tcp_waiting_prompt = true;
|
||||||
|
|
||||||
|
char cmd[32];
|
||||||
|
snprintf(cmd, sizeof(cmd), "AT+CIPSEND=%d", len);
|
||||||
|
sim800_send(cmd);
|
||||||
|
|
||||||
|
// actual sending happens when '>' arrives in parser
|
||||||
|
|
||||||
|
xSemaphoreGive(sim800_mutex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sim800_tcp_close(void) {
|
||||||
|
if (!modem.tcp_connected)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
bool ok = sim800_command("AT+CIPCLOSE", 5000);
|
||||||
|
|
||||||
|
modem.tcp_connected = false;
|
||||||
|
|
||||||
|
modem_set_state(MODEM_STATE_GPRS_UP);
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "driver/uart.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/queue.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "pins.h"
|
||||||
|
#include "servergprs.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
SemaphoreHandle_t done;
|
||||||
|
char response[256];
|
||||||
|
bool success;
|
||||||
|
} sim800_cmd_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MODEM_STATE_OFF = 0,
|
||||||
|
MODEM_STATE_INIT,
|
||||||
|
MODEM_STATE_READY,
|
||||||
|
|
||||||
|
MODEM_STATE_REGISTERING,
|
||||||
|
MODEM_STATE_REGISTERED,
|
||||||
|
|
||||||
|
MODEM_STATE_SMS_READY,
|
||||||
|
|
||||||
|
MODEM_STATE_CALL_ACTIVE,
|
||||||
|
|
||||||
|
MODEM_STATE_GPRS_CONNECTING,
|
||||||
|
MODEM_STATE_GPRS_UP,
|
||||||
|
|
||||||
|
MODEM_STATE_TCP_CONNECTING,
|
||||||
|
MODEM_STATE_TCP_CONNECTED,
|
||||||
|
|
||||||
|
MODEM_STATE_ERROR
|
||||||
|
} modem_state_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
modem_state_t state;
|
||||||
|
|
||||||
|
bool in_call;
|
||||||
|
bool gprs_active;
|
||||||
|
bool need_gprs_restart;
|
||||||
|
|
||||||
|
int signal;
|
||||||
|
int network_registered;
|
||||||
|
|
||||||
|
int last_rssi;
|
||||||
|
int last_ber;
|
||||||
|
|
||||||
|
bool tcp_connected;
|
||||||
|
char tcp_host[64];
|
||||||
|
int tcp_port;
|
||||||
|
|
||||||
|
SemaphoreHandle_t state_mutex;
|
||||||
|
} modem_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EV_NONE = 0,
|
||||||
|
|
||||||
|
EV_MODEM_OK,
|
||||||
|
EV_MODEM_ERROR,
|
||||||
|
|
||||||
|
EV_NETWORK_REG_OK,
|
||||||
|
EV_NETWORK_LOST,
|
||||||
|
|
||||||
|
EV_INCOMING_CALL,
|
||||||
|
EV_CALL_ENDED,
|
||||||
|
|
||||||
|
EV_SMS_RECEIVED,
|
||||||
|
|
||||||
|
EV_GPRS_UP,
|
||||||
|
EV_GPRS_DOWN
|
||||||
|
} modem_event_t;
|
||||||
|
|
||||||
|
|
||||||
|
void print_state();
|
||||||
|
|
||||||
|
void sim800_uart_init(void);
|
||||||
|
|
||||||
|
void modem_update_flags(void);
|
||||||
|
|
||||||
|
void modem_set_state(modem_state_t new_state);
|
||||||
|
|
||||||
|
void modem_handle_event(modem_event_t ev);
|
||||||
|
|
||||||
|
bool modem_start_gprs(void);
|
||||||
|
|
||||||
|
void sim800_csq_task(void *arg);
|
||||||
|
|
||||||
|
void sim800_task(void *arg);
|
||||||
|
|
||||||
|
void sim800_handle_line(char *line);
|
||||||
|
|
||||||
|
void sim800_parse(char *data);
|
||||||
|
|
||||||
|
void sim800_send(const char *cmd);
|
||||||
|
|
||||||
|
bool sim800_command(const char *cmd, uint32_t timeout_ms);
|
||||||
|
|
||||||
|
void init_modem(void *arg);
|
||||||
|
|
||||||
|
bool sim800_send_sms(const char *number, const char *msg);
|
||||||
|
|
||||||
|
bool sim800_call(const char *number);
|
||||||
|
|
||||||
|
bool sim800_hangup(void);
|
||||||
|
|
||||||
|
bool sim800_answer(void);
|
||||||
|
|
||||||
|
bool sim800_tcp_connect(const char *host, int port);
|
||||||
|
|
||||||
|
bool sim800_tcp_send(const void *data, int len);
|
||||||
|
|
||||||
|
bool sim800_tcp_close(void);
|
||||||
@@ -16,3 +16,4 @@ dependencies:
|
|||||||
# public: true
|
# public: true
|
||||||
espressif/esp_tinyusb: ~2.2.0
|
espressif/esp_tinyusb: ~2.2.0
|
||||||
espressif/led_strip: ^3.0.0
|
espressif/led_strip: ^3.0.0
|
||||||
|
espressif/esp_codec_dev: ^1.5.9
|
||||||
|
|||||||
+40
-2
@@ -1,9 +1,12 @@
|
|||||||
|
#include <ctype.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "driver/gpio.h"
|
#include "driver/gpio.h"
|
||||||
#include "drivers/fonts.h"
|
#include "drivers/fonts.h"
|
||||||
#include "drivers/i2c.h"
|
#include "drivers/i2c.h"
|
||||||
|
#include "drivers/sim800.h"
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
|
|
||||||
@@ -21,13 +24,19 @@
|
|||||||
#include "hal/gpio_types.h"
|
#include "hal/gpio_types.h"
|
||||||
#include "projdefs.h"
|
#include "projdefs.h"
|
||||||
|
|
||||||
|
char linebuf[1024];
|
||||||
|
char *linebufPtr = linebuf;
|
||||||
|
|
||||||
void app_main(void) {
|
void app_main(void) {
|
||||||
|
memset(linebuf, 0, sizeof(linebuf));
|
||||||
printf("boot\n");
|
printf("boot\n");
|
||||||
set_pin_dirs();
|
set_pin_dirs();
|
||||||
battery_start_task();
|
battery_start_task();
|
||||||
i2c_init(BUS_I2C_SDA, BUS_I2C_SCL);
|
i2c_init(BUS_I2C_SDA, BUS_I2C_SCL);
|
||||||
|
|
||||||
ws2812_init();
|
ws2812_init();
|
||||||
|
sim800_uart_init();
|
||||||
|
xTaskCreate(init_modem, "init_modem", 4096, NULL, 10, NULL);
|
||||||
audio_i2s_init();
|
audio_i2s_init();
|
||||||
vTaskDelay(pdMS_TO_TICKS(10));
|
vTaskDelay(pdMS_TO_TICKS(10));
|
||||||
es8311_init();
|
es8311_init();
|
||||||
@@ -66,13 +75,40 @@ void app_main(void) {
|
|||||||
font5x7);
|
font5x7);
|
||||||
while (tca8418_read(&key, &pressed)) {
|
while (tca8418_read(&key, &pressed)) {
|
||||||
|
|
||||||
|
char c = getKeyboardChar(key);
|
||||||
|
|
||||||
|
if (!pressed) {
|
||||||
|
if (isprint(c)) {
|
||||||
|
*(linebufPtr++) = c;
|
||||||
|
} else {
|
||||||
|
switch (c) {
|
||||||
|
case '\n':
|
||||||
|
sim800_tcp_send(linebuf, linebufPtr - linebuf);
|
||||||
|
linebufPtr = linebuf;
|
||||||
|
memset(linebuf, 0, sizeof(linebuf));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\b':
|
||||||
|
if (linebufPtr > linebuf) {
|
||||||
|
*(linebufPtr--) = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (linebufPtr > linebuf + 1023) {
|
||||||
|
linebufPtr = linebuf + 1023;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
snprintf(buf, sizeof(buf), "key=%c %s %d %s", getKeyboardChar(key),
|
snprintf(buf, sizeof(buf), "key=%c %s %d %s", getKeyboardChar(key),
|
||||||
getKeyboardKeyName(key), key, pressed ? "pressed" : "released");
|
getKeyboardKeyName(key), key, pressed ? "pressed" : "released");
|
||||||
printf("%s\n", buf);
|
printf("%s\n", buf);
|
||||||
|
|
||||||
st7789_draw_string(30, 30, buf, 0x07E0, 0x0000, true, fontHitachi);
|
*/
|
||||||
audio_beep();
|
|
||||||
|
// audio_beep();
|
||||||
}
|
}
|
||||||
|
st7789_draw_string(30, 30, linebuf, 0x07E0, 0x0000, true, fontHitachi);
|
||||||
|
|
||||||
bmi270_data_t bmiData;
|
bmi270_data_t bmiData;
|
||||||
|
|
||||||
@@ -88,6 +124,8 @@ void app_main(void) {
|
|||||||
snprintf(buf, sizeof(buf), "BAT: %d%%(%.3fV)", getBatteryPercentage(),
|
snprintf(buf, sizeof(buf), "BAT: %d%%(%.3fV)", getBatteryPercentage(),
|
||||||
getBatteryVoltage());
|
getBatteryVoltage());
|
||||||
st7789_draw_string(140, 10, buf, 0x07E0, 0x0000, true, fontHitachi);
|
st7789_draw_string(140, 10, buf, 0x07E0, 0x0000, true, fontHitachi);
|
||||||
|
|
||||||
|
st7789_draw_string(30, 90, linebufIn, 0x07E0, 0x0000, true, fontHitachi);
|
||||||
st7789_flush();
|
st7789_flush();
|
||||||
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(20)); // 50 fps max
|
vTaskDelay(pdMS_TO_TICKS(20)); // 50 fps max
|
||||||
|
|||||||
Reference in New Issue
Block a user