Browse Source

feat: add disconnect root-cause diagnostics

dev-rebuild
蔡享 1 month ago
parent
commit
cb27a046f2
  1. 97
      applications/VK_Client.c
  2. 2
      applications/VK_Com.c
  3. 281
      applications/drv_ec800k.c
  4. 32
      applications/drv_ec800k.h

97
applications/VK_Client.c

@ -32,6 +32,8 @@
static char cmd_cmd[128] = {0};
static void lte_diag_finish_disconnect(void);
no_carrier_match_t _no_carrier_t = {0};
/*关闭TCP连接*/
@ -39,6 +41,11 @@ void client_tcp_close(Cclient_t *client) {
char close_cmd[24];
client->connect_sta = false;
BSP_LTE_SetDataTxPaused(true);
if (lte_diag.disconnect_report_pending) {
BSP_LTE_CollectNetworkSnapshot();
lte_diag_finish_disconnect();
}
rt_snprintf(close_cmd, sizeof(close_cmd), AT_QICLOSE, client->connect_ID);
BSP_LTE_SendCmd(close_cmd, DEFAULT_EXPECT, DEFAULT_ERROR,
LTE_CMD_WAIT_QICLOSE);
@ -149,6 +156,7 @@ static const char *disconnect_reason_name(lte_disconnect_reason_t reason) {
case LTE_DISC_AT_TIMEOUT: return "AT_TIMEOUT";
case LTE_DISC_QIOPEN_FAILED: return "QIOPEN_FAILED";
case LTE_DISC_MODULE_RESET: return "MODULE_RESET";
case LTE_DISC_SERVER_SILENCE: return "SERVER_SILENCE";
default: return "UNKNOWN";
}
}
@ -167,6 +175,7 @@ void lte_diag_disconnect(lte_disconnect_reason_t reason) {
lte_diag.disconnect_count++;
lte_diag.last_disconnect_reason = reason;
lte_diag.last_disconnect_tick = now;
lte_diag.disconnect_report_pending = true;
LOG_I("[DISC] reason=%s count=%u connected_ticks=%u",
disconnect_reason_name(reason), lte_diag.disconnect_count,
@ -176,10 +185,13 @@ void lte_diag_disconnect(lte_disconnect_reason_t reason) {
lte_diag.uart2_rx_events, lte_diag.uart2_write_failures,
lte_diag.uart2_error_count, lte_diag.uart3_error_count,
lte_diag.last_uart_error_code);
LOG_I("[DISC] fmu_rx=%u fmu_tx=%u server_rx=%u read_events=%u silence_timeout=%u",
lte_diag.fmu_rx_bytes, lte_diag.fmu_tx_bytes,
lte_diag.server_rx_bytes, lte_diag.server_rx_read_events,
lte_diag.server_silence_timeout_count);
LOG_I("[CONN] fmu_rx=%u fmu_tx=%u fmu_hb=%u server_rx=%u server_hb=%u events=%u",
lte_diag.fmu_rx_bytes - lte_diag.conn_fmu_rx_base,
lte_diag.fmu_tx_bytes - lte_diag.conn_fmu_tx_base,
lte_diag.fmu_heartbeats - lte_diag.conn_fmu_heartbeat_base,
lte_diag.server_rx_bytes - lte_diag.conn_server_rx_base,
lte_diag.server_heartbeats - lte_diag.conn_server_heartbeat_base,
lte_diag.server_rx_read_events - lte_diag.conn_server_events_base);
LOG_I("[DISC] age_uart2_rx=%u age_uart2_tx=%u age_fmu_rx=%u age_server_rx=%u",
diag_age(now, lte_diag.last_uart2_rx_tick),
diag_age(now, lte_diag.last_uart2_tx_tick),
@ -191,13 +203,76 @@ void lte_diag_disconnect(lte_disconnect_reason_t reason) {
LOG_I("[DISC] attempts=%u reconnects=%u qioopen_fail=%u resets=%u",
lte_diag.connect_attempts, lte_diag.reconnect_count,
lte_diag.qioopen_failures, lte_diag.reset_count);
LOG_I("[DISC] csq=%d cereg=%u pdp=%u heap=%u/%u min_free=%u",
lte_dev.csq, lte_dev.eps_sta, lte_dev.reset_flag == DTU_CF_NO_NEED_RESET,
heap_used, heap_total, heap_total - heap_max);
LOG_I("[DISC] heap=%u/%u min_free=%u", heap_used, heap_total,
heap_total - heap_max);
if (reason == LTE_DISC_AT_TIMEOUT || reason == LTE_DISC_QIOPEN_FAILED ||
reason == LTE_DISC_MODULE_RESET) {
const char *classification = reason == LTE_DISC_QIOPEN_FAILED
? "SOCKET_OPEN"
: "MODEM_OR_DEVICE";
LOG_I("[CLASS] class=%s confidence=MEDIUM net_snapshot=unavailable",
classification);
lte_diag.disconnect_report_pending = false;
}
lte_dev.client1->connect_sta = false;
}
static const char *diag_text_or_unknown(const char *text) {
return text[0] == '\0' ? "?" : text;
}
static void lte_diag_finish_disconnect(void) {
const lte_network_snapshot_t *network = &lte_diag.network;
rt_tick_t now = lte_diag.last_disconnect_tick;
rt_uint32_t connected_ms = now - lte_diag.connect_tick;
rt_uint32_t fmu_hb =
lte_diag.fmu_heartbeats - lte_diag.conn_fmu_heartbeat_base;
rt_uint32_t server_hb =
lte_diag.server_heartbeats - lte_diag.conn_server_heartbeat_base;
const char *classification = "UNKNOWN";
const char *confidence = "LOW";
const char *evidence = "insufficient";
bool registration_bad = network->cereg >= 0 && network->cereg != 1 &&
network->cereg != 5;
LOG_I("[NET] oper=%s rat=%s band=%s channel=%u tac=%s cell=%s",
diag_text_or_unknown(network->oper),
diag_text_or_unknown(network->rat),
diag_text_or_unknown(network->band), network->channel,
diag_text_or_unknown(network->tac),
diag_text_or_unknown(network->cell));
LOG_I("[NET] cereg=%d cgatt=%d pdp=%d csq=%d pdpdeact=%u",
network->cereg, network->cgatt, network->pdp, network->csq,
lte_dev.socket_pdpdeact_pending ? 1 : 0);
LOG_I("[PATH] tcp_ack=unavailable mode=transparent");
if (lte_dev.socket_pdpdeact_pending || registration_bad ||
network->cgatt == 0 || network->pdp == 0) {
classification = "CELLULAR";
confidence = "HIGH";
evidence = lte_dev.socket_pdpdeact_pending ? "pdpdeact" : "registration";
} else if (connected_ms >= 25000 && connected_ms <= 40000 &&
fmu_hb == 0 && server_hb >= 5) {
classification = "SERVER_POLICY";
confidence = "HIGH";
evidence = "no_fmu_hb_30s";
} else if (lte_diag.last_disconnect_reason == LTE_DISC_SERVER_SILENCE) {
classification = "SERVER_OR_DOWNLINK";
confidence = "MEDIUM";
evidence = "server_silence";
} else if (diag_age(now, lte_diag.last_server_rx_tick) <= 5000) {
classification = "REMOTE_CLOSE";
confidence = "MEDIUM";
evidence = "recent_server_rx";
}
LOG_I("[CLASS] class=%s confidence=%s evidence=%s", classification,
confidence, evidence);
lte_diag.disconnect_report_pending = false;
}
/*将EC800K软件复位*/
int16_t EC800K_Reset(void) {
@ -372,6 +447,7 @@ static bool client_exit_transparent_mode(CLte_dev_t *pLte_dev) {
sizeof(pLte_dev->at_buf) - 1);
if (len > 0) {
lte_diag_uart2_rx((rt_size_t)len);
lte_diag_modem_text(pLte_dev->at_buf, (rt_size_t)len);
pLte_dev->at_buf[len] = '\0';
if (rt_strstr((const char *)pLte_dev->at_buf, DEFAULT_EXPECT) != RT_NULL) {
return true;
@ -391,7 +467,7 @@ void client_yield(CLte_dev_t *pLte_dev) {
lte_diag.server_silence_timeout_count++;
LOG_W("server silence timeout, reconnect\n");
if (client_exit_transparent_mode(pLte_dev)) {
pLte_dev->client1->connect_sta = false;
lte_diag_disconnect(LTE_DISC_SERVER_SILENCE);
client_tcp_close(pLte_dev->client1);
} else {
lte_diag_disconnect(LTE_DISC_AT_TIMEOUT);
@ -408,6 +484,7 @@ void client_yield(CLte_dev_t *pLte_dev) {
sizeof(pLte_dev->at_buf));
if (len > 0) {
lte_diag_uart2_rx((rt_size_t)len);
lte_diag_modem_text(pLte_dev->at_buf, (rt_size_t)len);
/*收到TCP关闭的消息*/
if (strstr((const char *)pLte_dev->at_buf, CLOSED)) {
LOG_W("[URC] closed received");
@ -437,9 +514,7 @@ void client_yield(CLte_dev_t *pLte_dev) {
}
rt_device_t fmu_com = fmu_com_get();
lte_diag.server_rx_bytes += len;
lte_diag.server_rx_read_events++;
lte_diag.last_server_rx_tick = rt_tick_get();
lte_diag_server_data(pLte_dev->at_buf, len);
if (fmu_com) {
rt_ssize_t written = rt_device_write(fmu_com, 0,
pLte_dev->at_buf, len);

2
applications/VK_Com.c

@ -86,7 +86,7 @@ void com_task(void) {
while (1) {
len = rt_device_read(fmu_com, 0, buff, sizeof(buff));
if (len > 0) {
lte_diag_fmu_rx(len);
lte_diag_fmu_data(buff, len);
if (lte_dev.client1->connect_sta == true &&
lte_dev.data_tx_paused == false) {
/* 仅在客户端2连接时转发 */

281
applications/drv_ec800k.c

@ -38,6 +38,143 @@ CLte_dev_t lte_dev = {
lte_diag_t lte_diag = {0};
static bool lte_log_clock_query_done = false;
static rt_uint8_t pdpdeact_match_position = 0;
typedef struct {
rt_uint16_t remaining;
rt_uint16_t checksum;
rt_uint16_t received_checksum;
rt_uint8_t magic;
rt_uint8_t phase;
rt_uint8_t position;
rt_uint8_t payload_length;
rt_uint8_t incompat_flags;
bool heartbeat;
} mavlink_diag_parser_t;
static mavlink_diag_parser_t fmu_mavlink_parser;
static mavlink_diag_parser_t server_mavlink_parser;
static int parse_decimal(const char **text) {
int value = 0;
bool found = false;
const char *p = *text;
while (*p == ' ') p++;
while (*p >= '0' && *p <= '9') {
found = true;
value = value * 10 + (*p++ - '0');
}
*text = p;
return found ? value : -1;
}
static void copy_csv_token(const char **text, char *output, rt_size_t capacity) {
const char *p = *text;
rt_size_t used = 0;
char terminator = ',';
if (capacity == 0) return;
while (*p == ' ' || *p == ',') p++;
if (*p == '"') {
terminator = '"';
p++;
}
while (*p != '\0' && *p != '\r' && *p != '\n' && *p != terminator) {
if (used + 1 < capacity) output[used++] = *p;
p++;
}
while (used > 0 && output[used - 1] == ' ') used--;
output[used] = '\0';
if (*p == terminator) p++;
*text = p;
}
static void mavlink_crc_accumulate(uint8_t data, rt_uint16_t *checksum) {
uint8_t tmp = data ^ (uint8_t)(*checksum & 0xff);
tmp ^= tmp << 4;
*checksum = (*checksum >> 8) ^ ((rt_uint16_t)tmp << 8) ^
((rt_uint16_t)tmp << 3) ^ ((rt_uint16_t)tmp >> 4);
}
static void mavlink_diag_start(mavlink_diag_parser_t *parser, uint8_t magic) {
parser->magic = magic;
parser->phase = 1;
parser->position = 0;
parser->remaining = 0;
parser->checksum = 0xffff;
parser->received_checksum = 0;
parser->payload_length = 0;
parser->incompat_flags = 0;
parser->heartbeat = false;
}
static void mavlink_diag_feed(mavlink_diag_parser_t *parser,
const uint8_t *data, rt_size_t size,
rt_uint32_t *heartbeat_count) {
rt_size_t i;
for (i = 0; i < size; i++) {
uint8_t ch = data[i];
if (parser->phase == 0) {
if (ch == 0xFE || ch == 0xFD) mavlink_diag_start(parser, ch);
continue;
}
if (parser->phase == 5) {
parser->remaining--;
if (parser->remaining == 0) parser->phase = 0;
continue;
}
if (parser->phase == 2) {
mavlink_crc_accumulate(ch, &parser->checksum);
parser->remaining--;
if (parser->remaining == 0) parser->phase = 3;
continue;
}
if (parser->phase == 3) {
parser->received_checksum = ch;
parser->phase = 4;
continue;
}
if (parser->phase == 4) {
parser->received_checksum |= (rt_uint16_t)ch << 8;
mavlink_crc_accumulate(50, &parser->checksum);
if (parser->heartbeat &&
parser->checksum == parser->received_checksum) {
(*heartbeat_count)++;
}
if (parser->magic == 0xFD &&
(parser->incompat_flags & 0x01) != 0) {
parser->phase = 5;
parser->remaining = 13;
} else {
parser->phase = 0;
}
continue;
}
mavlink_crc_accumulate(ch, &parser->checksum);
if (parser->position == 0) parser->payload_length = ch;
if (parser->magic == 0xFE && parser->position == 4) {
parser->heartbeat = parser->payload_length == 9 && ch == 0;
parser->remaining = parser->payload_length;
parser->phase = parser->remaining > 0 ? 2 : 3;
} else if (parser->magic == 0xFD) {
if (parser->position == 1) parser->incompat_flags = ch;
if (parser->position == 6) parser->heartbeat = ch == 0;
if (parser->position == 7)
parser->heartbeat = parser->heartbeat && ch == 0;
if (parser->position == 8) {
parser->heartbeat = parser->payload_length == 9 &&
parser->heartbeat && ch == 0;
parser->remaining = parser->payload_length;
parser->phase = parser->remaining > 0 ? 2 : 3;
}
}
parser->position++;
}
}
void lte_diag_at_begin(const char *cmd) {
rt_size_t i;
@ -86,6 +223,42 @@ void lte_diag_fmu_rx(rt_size_t size) {
lte_diag.last_fmu_rx_tick = rt_tick_get();
}
void lte_diag_fmu_data(const uint8_t *data, rt_size_t size) {
if (data == RT_NULL || size == 0) return;
lte_diag_fmu_rx(size);
mavlink_diag_feed(&fmu_mavlink_parser, data, size, &lte_diag.fmu_heartbeats);
}
void lte_diag_server_data(const uint8_t *data, rt_size_t size) {
if (data == RT_NULL || size == 0) return;
lte_diag.server_rx_bytes += size;
lte_diag.server_rx_read_events++;
lte_diag.last_server_rx_tick = rt_tick_get();
mavlink_diag_feed(&server_mavlink_parser, data, size,
&lte_diag.server_heartbeats);
}
void lte_diag_modem_text(const uint8_t *data, rt_size_t size) {
static const char pattern[] = "pdpdeact";
rt_size_t i;
if (data == RT_NULL) return;
for (i = 0; i < size; i++) {
char ch = (char)data[i];
if (ch >= 'A' && ch <= 'Z') ch = (char)(ch - 'A' + 'a');
if (ch == pattern[pdpdeact_match_position]) {
pdpdeact_match_position++;
if (pdpdeact_match_position == sizeof(pattern) - 1) {
if (!lte_dev.socket_pdpdeact_pending) lte_diag.pdpdeact_count++;
lte_dev.socket_pdpdeact_pending = true;
pdpdeact_match_position = 0;
}
} else {
pdpdeact_match_position = ch == pattern[0] ? 1 : 0;
}
}
}
void lte_diag_fmu_tx(rt_size_t size) {
lte_diag.fmu_tx_bytes += size;
lte_diag.last_fmu_tx_tick = rt_tick_get();
@ -101,6 +274,16 @@ void lte_diag_connect_attempt(void) {
void lte_diag_connect_success(void) {
lte_diag.connect_tick = rt_tick_get();
lte_diag.last_server_rx_tick = lte_diag.connect_tick;
lte_diag.conn_fmu_rx_base = lte_diag.fmu_rx_bytes;
lte_diag.conn_fmu_tx_base = lte_diag.fmu_tx_bytes;
lte_diag.conn_server_rx_base = lte_diag.server_rx_bytes;
lte_diag.conn_server_events_base = lte_diag.server_rx_read_events;
lte_diag.conn_fmu_heartbeat_base = lte_diag.fmu_heartbeats;
lte_diag.conn_server_heartbeat_base = lte_diag.server_heartbeats;
lte_dev.socket_pdpdeact_pending = false;
pdpdeact_match_position = 0;
rt_memset(&fmu_mavlink_parser, 0, sizeof(fmu_mavlink_parser));
rt_memset(&server_mavlink_parser, 0, sizeof(server_mavlink_parser));
}
void lte_diag_module_reset(void) {
@ -151,6 +334,103 @@ void BSP_LTE_InitLogClock(void) {
}
}
static void parse_cereg_snapshot(const char *response) {
const char *p = rt_strstr(response, "+CEREG:");
int value;
if (p == RT_NULL) return;
p += rt_strlen("+CEREG:");
value = parse_decimal(&p);
if (value < 0 || *p != ',') return;
p++;
value = parse_decimal(&p);
if (value < 0) return;
lte_diag.network.cereg = (int8_t)value;
if (*p == ',') {
copy_csv_token(&p, lte_diag.network.tac,
sizeof(lte_diag.network.tac));
copy_csv_token(&p, lte_diag.network.cell,
sizeof(lte_diag.network.cell));
}
}
static void parse_cgatt_snapshot(const char *response) {
const char *p = rt_strstr(response, "+CGATT:");
int value;
if (p == RT_NULL) return;
p += rt_strlen("+CGATT:");
value = parse_decimal(&p);
if (value >= 0) lte_diag.network.cgatt = (int8_t)value;
}
static void parse_qiact_snapshot(const char *response) {
const char *p = rt_strstr(response, "+QIACT:");
int context;
int state;
if (p == RT_NULL) {
lte_diag.network.pdp = 0;
return;
}
p += rt_strlen("+QIACT:");
context = parse_decimal(&p);
if (context < 0 || *p != ',') return;
p++;
state = parse_decimal(&p);
if (context == 1 && state >= 0) lte_diag.network.pdp = (int8_t)state;
}
static void parse_qnwinfo_snapshot(const char *response) {
const char *p = rt_strstr(response, "+QNWINFO:");
char channel[12];
if (p == RT_NULL) return;
p += rt_strlen("+QNWINFO:");
copy_csv_token(&p, lte_diag.network.rat, sizeof(lte_diag.network.rat));
copy_csv_token(&p, lte_diag.network.oper, sizeof(lte_diag.network.oper));
copy_csv_token(&p, lte_diag.network.band, sizeof(lte_diag.network.band));
copy_csv_token(&p, channel, sizeof(channel));
p = channel;
{
int value = parse_decimal(&p);
if (value >= 0) lte_diag.network.channel = (rt_uint32_t)value;
}
}
void BSP_LTE_CollectNetworkSnapshot(void) {
lte_network_snapshot_t *network = &lte_diag.network;
rt_memset(network, 0, sizeof(*network));
network->cereg = -1;
network->cgatt = -1;
network->pdp = -1;
network->csq = -1;
BSP_LTE_SendCmd(AT_CEREG2, DEFAULT_EXPECT, DEFAULT_ERROR,
LTE_CMD_WAIT_NORMAL);
if (BSP_LTE_SendCmd(AT_CEREG, DEFAULT_EXPECT, DEFAULT_ERROR,
LTE_CMD_WAIT_NORMAL) == 0) {
parse_cereg_snapshot((const char *)lte_dev.at_buf);
}
BSP_LTE_SendCmd(AT_CEREG0, DEFAULT_EXPECT, DEFAULT_ERROR,
LTE_CMD_WAIT_NORMAL);
if (BSP_LTE_SendCmd(AT_CGATT, DEFAULT_EXPECT, DEFAULT_ERROR,
LTE_CMD_WAIT_NORMAL) == 0) {
parse_cgatt_snapshot((const char *)lte_dev.at_buf);
}
if (BSP_LTE_SendCmd(AT_QIACT, DEFAULT_EXPECT, DEFAULT_ERROR,
LTE_CMD_WAIT_NORMAL) == 0) {
parse_qiact_snapshot((const char *)lte_dev.at_buf);
}
if (BSP_LTE_SendCmd(AT_QNWINFO, DEFAULT_EXPECT, DEFAULT_ERROR,
LTE_CMD_WAIT_NORMAL) == 0) {
parse_qnwinfo_snapshot((const char *)lte_dev.at_buf);
}
network->csq = BSP_LTE_GetCSQ();
if (network->csq >= 0) lte_dev.csq = network->csq;
}
int16_t BSP_LTE_SendCmd(const char *cmd, const char *expect, const char *error,
uint32_t waittime) {
lte_diag_at_begin(cmd);
@ -167,6 +447,7 @@ int16_t BSP_LTE_SendCmd(const char *cmd, const char *expect, const char *error,
sizeof(lte_dev.at_buf));
if (read_len > 0) {
lte_diag_uart2_rx((rt_size_t)read_len);
lte_diag_modem_text(lte_dev.at_buf, (rt_size_t)read_len);
}
LOG_I("%s\n", lte_dev.at_buf);

32
applications/drv_ec800k.h

@ -66,7 +66,9 @@ extern "C" {
#define AT_CGREG "AT+CGREG?\r\n" // GPRS REG 2G
#define AT_CEREG "AT+CEREG?\r\n" // EPS REG 4G
#define AT_CEREG0 "AT+CEREG=0\r\n"
#define AT_CEREG2 "AT+CEREG=2\r\n"
#define AT_CSQ "AT+CSQ\r\n"
#define AT_QNWINFO "AT+QNWINFO\r\n"
#define AT_CPSI "AT+CPSI?\r\n"
#define AT_CIPMODE "AT+CIPMODE=1\r\n"
@ -227,8 +229,22 @@ typedef enum {
LTE_DISC_AT_TIMEOUT,
LTE_DISC_QIOPEN_FAILED,
LTE_DISC_MODULE_RESET,
LTE_DISC_SERVER_SILENCE,
} lte_disconnect_reason_t;
typedef struct {
int8_t cereg;
int8_t cgatt;
int8_t pdp;
int8_t csq;
char rat[12];
char oper[16];
char band[16];
char tac[9];
char cell[12];
rt_uint32_t channel;
} lte_network_snapshot_t;
typedef struct {
rt_uint32_t uart2_rx_bytes;
rt_uint32_t uart2_tx_bytes;
@ -250,6 +266,15 @@ typedef struct {
rt_uint32_t server_rx_bytes;
rt_uint32_t server_rx_read_events;
rt_uint32_t server_silence_timeout_count;
rt_uint32_t fmu_heartbeats;
rt_uint32_t server_heartbeats;
rt_uint32_t pdpdeact_count;
rt_uint32_t conn_fmu_rx_base;
rt_uint32_t conn_fmu_tx_base;
rt_uint32_t conn_server_rx_base;
rt_uint32_t conn_server_events_base;
rt_uint32_t conn_fmu_heartbeat_base;
rt_uint32_t conn_server_heartbeat_base;
rt_tick_t last_uart2_rx_tick;
rt_tick_t last_uart2_tx_tick;
rt_tick_t last_fmu_rx_tick;
@ -261,6 +286,8 @@ typedef struct {
rt_int32_t last_at_result;
char last_at_cmd[20];
lte_disconnect_reason_t last_disconnect_reason;
lte_network_snapshot_t network;
bool disconnect_report_pending;
} lte_diag_t;
extern lte_diag_t lte_diag;
@ -272,6 +299,9 @@ void lte_diag_uart2_tx(rt_size_t size);
void lte_diag_uart_error(const char *name, rt_uint32_t error_code);
void lte_diag_fmu_rx(rt_size_t size);
void lte_diag_fmu_tx(rt_size_t size);
void lte_diag_fmu_data(const uint8_t *data, rt_size_t size);
void lte_diag_server_data(const uint8_t *data, rt_size_t size);
void lte_diag_modem_text(const uint8_t *data, rt_size_t size);
void lte_diag_connect_attempt(void);
void lte_diag_connect_success(void);
void lte_diag_disconnect(lte_disconnect_reason_t reason);
@ -299,6 +329,7 @@ typedef struct {
bool reset_flag;
bool dev_init_flag;
volatile bool data_tx_paused;
volatile bool socket_pdpdeact_pending;
} CLte_dev_t;
extern CLte_dev_t lte_dev;
@ -320,6 +351,7 @@ void BSP_LTE_SetDataTxPaused(bool paused);
void BSP_LTE_Config(void);
void BSP_LTE_InitLogClock(void);
void BSP_LTE_CollectNetworkSnapshot(void);
int BSP_LTE_GetICCID(char *pICCID);

Loading…
Cancel
Save