Files
vd_960/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/net_srv.c
T
wangfq ac3fb512d5 feat(vd960DBN): 脱机事件日志系统 (W25Q32 环形) — 解决重复上线取证
背景: 设备挂平台测试出现重复上线(现场未断电), 无本地日志无法区分
设备真复位 vs MQTT 断连重连。iot_handle_suback 每次重连都发
initialize 是重复上线的直接证据, 日志需能区分二者。

实现 (V3.6, ROADMAP P1.2 事件流先行):
- offlog.c/h: W25Q32 256KB 环形事件日志 (头扇区+63数据扇区, 8064条)
  - 32B 定长记录: magic/type/len/flags/seq/ts_ms/unix_ts/boot_seq/payload[12]
  - 8 类事件: BOOT(复位原因)/IOT_CONNECT/READY/DISCONN/RECONN/
    EVT_RETRY/GIVEUP/COIL/TIME_ANCHOR/LOG_CLEAR
  - 掉电恢复: 头扇区写指针锚点 + 上电 seq 连续性扫描
  - 编译期断言防 32B padding 回归
- 插桩 (全部主循环上下文, socket 中断内不写 SPI):
  - main(): offlog_init + RCC_RSTSCKR 复位原因采集/清除
  - iot_mqtt_poll(): MQTT 状态沿检测 (CONNECT/READY/DISCONN)
  - 重连退避/TCP超时/CONNACK拒绝: RECONN/DISCONN(4)/(3)
  - iot_evt_process/enqueue: EVT_RETRY/GIVEUP/COIL
  - net_srv.c dev_time_sync: TIME_ANCHOR 时钟同步锚点
- tests/test_offlog.c: gcc 隔离单测 6 例 (mock W25Q32 NOR 语义)

关键坑: ①中断内写SPI阻塞 ②结构体36B padding致环形错乱
③扇区级覆盖粒度count扣减语义 (均单测抓出)

待办: P1.3 导出命令(log_query/stat/clear) + 快照流 + 复位原因板上验证
2026-08-04 15:04:12 +08:00

1676 lines
56 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
******************************************************************************
* @file net_srv.c
* @author wangfq
* @version V1.0
* @date 2026-03-02
* @brief net message handle: unpack, exeute, response
*
******************************************************************************
*/
#include "CONFIG.h"
#include "net_srv.h"
#include "eth_driver.h"
#include "wchnet.h"
#include "MQTTPacket.h"
#include <string.h>
#include <stdlib.h>
#include "cmcng.h"
#include "simple_json.h"
#include "tcp_json_srv.h"
#include "iot_mqtt_srv.h"
#include "offlog.h"
uint32_t slen;
char g_dev_number_str[13] = "";
uint8_t g_flag_timestamp = 0;
#define KEEPALIVE_ENABLE 1 //Enable keep alive function
#define maxLenTemp 430
static char temp_guide[maxLenTemp] = "";
static void reset_temp_guide()
{
memset(temp_guide, 0, maxLenTemp);
}
//************************************************************************10
#define KEEPLIVE_ENABLE 1 //Enable keeplive function
Local_Net_Cfg local_net_cfg = {{0x00, 0x08, 0xdc, 0x33, 0x44, 0x55}, {192,168,1,188}, {255,255,255,0}, {192, 168,1,1}, "", 5550,NET_REPORT_INTERVAL, 5505, PORT_TCP_DEFAULT, MAX_CLEAR_COUNTER_INTERVAL};
NET_CENTER_INFO net_center_info = {{192,168,1,222}, 5505, PORT_TCP_DEFAULT, 5505, ""};
IOT_NET_INFO iot_net_info = {"", 1883, "", "", ""};
IOT_Topic g_iot_topic = {0, "", ""};
uint8_t RemoteIP[4] = {0,0,0,0};
Net_State g_net_state = {0,0, 0};
uint16_t srcport = 6000;
//UINT8 UDPDESIP[4] = {255,255,255,255}; /* ????????????????????,????????????????????????????? */
//UINT16 aport=1000; /* CH579?????????? */
uint32_t g_wdg_counter = 0;
uint8_t SocketId_TCP;
uint8_t SocketId_UDP ;
uint8_t socket[WCHNET_MAX_SOCKET_NUM]; //Save the currently connected socket
uint8_t SocketRecvBuf[WCHNET_MAX_SOCKET_NUM][RECE_BUF_LEN]; //socket receive buffer
uint8_t MyBuf[RECE_BUF_LEN];
#define MAX_TMP_BUF_LEN 64
#define MAX_MQTTBUF_LEN 1024 //512: loop_data(4通道)≈604B > 512 → 序列化失败发全零垃圾包被broker RST (2026-07-15)
char mqtt_username[64] = {0};
char mqtt_password[32] = {0};
char mqtt_clientid[64] = {0};
uint8_t mqttBuf[MAX_MQTTBUF_LEN];
uint8_t TmpBuf[MAX_TMP_BUF_LEN] = "";
MQTTPacket_connectData mqttData = MQTTPacket_connectData_initializer;
uint8_t flag_mqtt_ping_send = 0;
uint8_t flag_mqtt_ping_err = 0; //++, 0 normal, >0 send and no response
uint8_t g_mqtt_ping_counter = 0; //
void clear_mqtt_buf(void)
{
memset(mqttBuf, 0, MAX_MQTTBUF_LEN);
}
/*===========================================================================
* 设备时钟同步 (方案B, 2026-07-15)
* 设备无 RTC/SNTP。上电后本地时间 = 上电秒数。平台在收到 initialize 上线后,
* 下发 report_config 命令时于 ts 字段填当前 Unix 时间; 设备据此校准。
* 校准后所有上行 ts = 真 Unix 时间; 未校准前退回上电秒数(平台可按量级识别)。
* 接受任意下行命令的合法 ts 校准 (report_config 为约定主同步点)。
*===========================================================================*/
static uint32_t _dev_time_base_unix = 0; // 同步基准 Unix 秒, 0=未同步
static uint32_t _dev_time_base_tick = 0; // 同步时刻的 mstick()
void dev_time_sync(uint32_t unix_ts)
{
if (unix_ts < 1600000000UL) return; // 合法性门槛(>2020-09), 挡掉上电秒数/0/异常
_dev_time_base_unix = unix_ts;
_dev_time_base_tick = mstick();
offlog_time_anchor(unix_ts); // 事件日志: 时钟同步锚点 (boot_seq↔unix 回算)
PRINT("TIME: synced unix=%lu\n", (unsigned long)unix_ts);
}
uint32_t dev_time_now(void)
{
if (_dev_time_base_unix == 0) // 未同步 → 退回上电秒数(兼容)
return (uint32_t)(mstick() / 1000);
/* mstick 无符号相减天然处理 49.7 天回绕 */
return _dev_time_base_unix + (uint32_t)((mstick() - _dev_time_base_tick) / 1000);
}
/*********************************************************************
* @fn mStopIfError
*
* @brief check if error.
*
* @param iError - error constants.
*
* @return none
*/
void mStopIfError(u8 iError)
{
if (iError == WCHNET_ERR_SUCCESS) return;
printf("Error: 0x%02X\r\n", (u16)iError);
}
void mqtt_connect(void)
{
int len = 0;
mqttData.username.cstring = iot_net_info.username;
mqttData.password.cstring = iot_net_info.password;
mqttData.clientID.cstring = g_dev_number_str; //TODO: ?????????????????????
mqttData.keepAliveInterval = MQTT_KEEPALIVE_INTERVAL;
PRINT("username:%s\r\n", mqttData.username.cstring);
PRINT("password:%s\r\n", mqttData.password.cstring);
PRINT("clientID:%s\r\n", mqttData.clientID.cstring);
clear_mqtt_buf();
len = MQTTSerialize_connect(mqttBuf, sizeof(mqttBuf), &mqttData);
// Transport_SendPacket(mqttBuf, len);
WCHNET_SocketSend(SocketId_TCP, (uint8_t *)mqttBuf, &len);
}
void MQTT_Subscribe(char *topic, unsigned char msgid)
{
int len = 0, req_qos = 0;
MQTTString topicString = MQTTString_initializer;
topicString.cstring = topic;
clear_mqtt_buf();
len = MQTTSerialize_subscribe(mqttBuf, sizeof(mqttBuf), 0, msgid, 1, &topicString, &req_qos);
// Transport_SendPacket(mqttBuf, len);
WCHNET_SocketSend(SocketId_TCP, (uint8_t *)mqttBuf, &len);
}
void dg_subscribe_display_topic(void)
{
char *mBuff = (char *)malloc(256);
if(mBuff == NULL)
{
return;
}
memset(mBuff, 0, 256);
// V1.01: 双主题协议 — topic_sub 即为完整订阅主题,不再追加后缀
strcpy(mBuff, (char *)g_iot_topic.topic_sub);
{
PRINT("\nWill subscribe display_topic:\n%s\n", mBuff);
}
MQTT_Subscribe(mBuff, 1);
free(mBuff);
}
void MQTT_Pingreq()
{
uint8_t ping_buf[2];
int buf_len = sizeof(ping_buf);
int ping_len = MQTTSerialize_pingreq(ping_buf, buf_len);
// Transport_SendPacket(ping_buf, ping_len);
WCHNET_SocketSend(SocketId_TCP, (uint8_t *)ping_buf, &buf_len);
}
void mqtt_publish(char *topic, char *message, int req_qos)
{
int len = 0; // 必须有符号: MQTTSerialize_publish 缓冲不足返回 -2(BUFFER_TOO_SHORT)
clear_mqtt_buf();
{
PRINT("\nWill_publish_topid:%s, message:%s\n", topic, message);
}
MQTTString topicString = MQTTString_initializer;
int msglen = strlen(message);
topicString.cstring = topic;
static uint16_t s_mqtt_pkt_id = 0;
uint16_t pkt_id = (req_qos > 0) ? ++s_mqtt_pkt_id : 0;
len = MQTTSerialize_publish(mqttBuf, sizeof(mqttBuf), 0, req_qos, 0, pkt_id, topicString, (unsigned char *)message, msglen);
/* 守卫: 序列化失败(缓冲不足/参数错)绝不发送残缓冲。
否则 len 转 uint32 成天文数字, WCHNET 把清零的 mqttBuf + 越界相邻内存当垃圾包发出,
broker 见非法报文类型 0x00 → RST → 重连风暴 (2026-07-15 现场事故根因) */
if (len <= 0) {
PRINT("mqtt_publish: serialize FAIL rc=%d msglen=%d buf=%d (dropped)\n",
len, msglen, (int)sizeof(mqttBuf));
return;
}
uint32_t slen = (uint32_t)len;
WCHNET_SocketSend(SocketId_TCP, (uint8_t *)mqttBuf, &slen);
}
void dev_initialize_pub(void)
{
char *mBuff = (char *)malloc(512);
if(mBuff == NULL)
{
return;
}
memset(mBuff, 0, 512);
// V1.03: 上线后发布 initialize,告知服务器设备信息
// 格式: {msg_id, cmd:"initialize", ts, data:{dev_serial, model, hard_ver, soft_ver, extra_info:{code,csq,location}}}
// 首次上电尚未时钟同步 → ts=上电秒数; 平台收到本消息后经 report_config 回填真 Unix 时间
uint32_t now = dev_time_now();
char topic[64];
snprintf(topic, sizeof(topic), "dld960/%s/dev", g_dev_number_str);
sprintf((char *)mBuff,
"{\"msg_id\":%lu,\"cmd\":\"initialize\",\"ts\":%lu,"
"\"data\":{\"dev_serial\":\"%s\",\"model\":\"%s\","
"\"hard_ver\":\"%s\",\"soft_ver\":\"%s\","
"\"extra_info\":{\"code\":\"%s\",\"csq\":\"%d\","
"\"location\":\"%s\"}}}",
(unsigned long)++g_iot_msg_id, (unsigned long)now,
g_dev_number_str, PRODUCT_MODEL,
HARDWARE_VER, FIRMWARE_VER,
"0", 0, "");
PRINT("\nWill publish initialize topic=%s:\n%s\n", topic, mBuff);
mqtt_publish(topic, (char *)mBuff, 0);
free(mBuff);
}
void dev_response_heartbeat(char *dat)
{
char *mBuff = (char *)malloc(256);
if(mBuff == NULL)
{
return;
}
memset(mBuff, 0, 256);
if(dat == NULL)
{
sprintf((char *)mBuff, "{\"Method\":\"Heartbeat\", \"Data\":{\"Device_id\": \"%s\"}}", g_dev_number_str);
} else {
sprintf((char *)mBuff, "{\"Method\":\"Heartbeat\", \"Data\":{\"Device_id\": \"%s\",\"Remark\":\"%s\"}}", g_dev_number_str, dat);
}
// mqtt_publish("gtpc/display/Initialize", gbufSend, 0);
mqtt_publish((char *)(g_iot_topic.topic_pub), (char *)mBuff, 0);
free(mBuff);
}
void mqtt_deserialize_publish(char* topic, char* msg, int length)
{
// V1.01: 使用配置的 topic_sub 匹配,而非硬编码默认值
if(strstr(topic, (char *)g_iot_topic.topic_sub) != NULL)
{
manage_mqtt_recv_message(msg, length);
}
else
{
{
PRINT("\n%s, line:%d, other topic:%s, msg:%s.\n", __FUNCTION__, __LINE__, topic, msg);
}
}
}
void tcp_send_test()
{
uint8_t ping_buf[5] = {0x33, 0x32, 0x33,0x30,0x39};
int buf_len = 5;
// Transport_SendPacket(ping_buf, ping_len);
WCHNET_SocketSend(SocketId_TCP, (uint8_t *)ping_buf, &buf_len);
}
/*********************************************************************
* @fn WCHNET_CreateTcpSocket
*
* @brief Create TCP Socket
*
* @return none
*/
void WCHNET_CreateTcpSocket(void)
{
uint8_t i = 0;
uint8_t ret;
uint32_t len;
SOCK_INF TmpSocketInf;
memset((void *) &TmpSocketInf, 0, sizeof(SOCK_INF));
memcpy((void *) TmpSocketInf.IPAddr, net_center_info.lssc_ip, 4);
TmpSocketInf.DesPort = net_center_info.tcp_port;
TmpSocketInf.SourPort = srcport++; // local_net_cfg.port_dev_udp;
TmpSocketInf.ProtoType = PROTO_TYPE_TCP;
TmpSocketInf.RecvBufLen = RECE_BUF_LEN;
i = WCHNET_SocketCreat(&SocketId_TCP, &TmpSocketInf);
{
PRINT("WCHNET_SocketCreate %d,desIP:%d.%d.%d.%d, des_port:%d, srcport:%d\r\n", SocketId_TCP, net_center_info.lssc_ip[0],net_center_info.lssc_ip[1],net_center_info.lssc_ip[2],net_center_info.lssc_ip[3], TmpSocketInf.DesPort, TmpSocketInf.SourPort);
}
mStopIfError(i);
i = WCHNET_SocketConnect(SocketId_TCP); //make a TCP connection
if(i == WCHNET_ERR_SUCCESS)
{
PRINT("Tcp_Connect_Success!:%d\n", SocketId_TCP);
g_net_state.flag = 3;
// tcp_send_test();
}
mStopIfError(i);
}
void WCHNET_CreateTcpMqttSocket(void)
{
uint8_t i;
uint8_t ret;
uint32_t len;
SOCK_INF TmpSocketInf;
memset((void *) &TmpSocketInf, 0, sizeof(SOCK_INF));
memcpy((void *) TmpSocketInf.IPAddr, RemoteIP, 4);
TmpSocketInf.DesPort = iot_net_info.mqtt_port; // net_center_info.tcp_port;
TmpSocketInf.SourPort = local_net_cfg.port_dev_udp + 1;
TmpSocketInf.ProtoType = PROTO_TYPE_TCP;
TmpSocketInf.RecvBufLen = RECE_BUF_LEN;
i = WCHNET_SocketCreat(&SocketId_TCP, &TmpSocketInf);
{
PRINT("WCHNET_MQTT_SocketCreate %d,desIP:%d.%d.%d.%d, des_port:%d, srcport:%d\r\n", SocketId_TCP, RemoteIP[0],RemoteIP[1],RemoteIP[2],RemoteIP[3], iot_net_info.mqtt_port, TmpSocketInf.SourPort);
}
mStopIfError(i);
i = WCHNET_SocketConnect(SocketId_TCP); //make a TCP connection
if(i == WCHNET_ERR_SUCCESS)
{
g_net_state.flag = 3;
}
mStopIfError(i);
}
/*********************************************************************
* @fn WCHNET_UdpServerRecv
*
* @brief UDP Receive data function
*
*@param socinf - socket information.
* ipaddr - The IP address from which the data was sent
* port - source port
* buf - pointer to the data buffer
* len - received data length
* @return none
*/
void WCHNET_UdpServerRecv(struct _SOCK_INF *socinf, uint32_t ipaddr, uint16_t port, uint8_t *buf, uint32_t len)
{
uint8_t ip_addr[4], i;
// PRINT("Remote IP:");
for (i = 0; i < 4; i++) {
ip_addr[i] = ipaddr & 0xff;
// PRINT("%d ", ip_addr[i]);
ipaddr = ipaddr >> 8;
}
PRINT("srcport = %d len = %d socketid = %d,buf:\r\n%s\r\n", port, len,
socinf->SockIndex, buf);
manage_udp_message(socinf->SockIndex, ip_addr, port, buf, len);
}
/*********************************************************************
* @fn WCHNET_CreateUdpSocket
*
* @brief Create UDP Socket
*
* @return none
*/
void WCHNET_CreateUdpSocket(void)
{
uint8_t i;
SOCK_INF TmpSocketInf;
memset((void *) &TmpSocketInf, 0, sizeof(SOCK_INF));
// memcpy((void *) TmpSocketInf.IPAddr, UDPDESIP, 4);
// TmpSocketInf.DesPort = local_net_cfg.port_ssc_udp; //5500
TmpSocketInf.SourPort = local_net_cfg.port_dev_udp; //srcport;// local_net_cfg.port_dev_udp; // 4900
TmpSocketInf.ProtoType = PROTO_TYPE_UDP;
TmpSocketInf.RecvStartPoint = (uint32_t)SocketRecvBuf; //
TmpSocketInf.RecvBufLen = RECE_BUF_LEN;
TmpSocketInf.AppCallBack = WCHNET_UdpServerRecv;
i = WCHNET_SocketCreat(&SocketId_UDP, &TmpSocketInf);
PRINT("i:%d,WCHNET_SocketCreatUdp %d srcport %d\r\n", i, SocketId_UDP, TmpSocketInf.SourPort);
mStopIfError(i);
g_net_state.flag = 2;
}
void reset_net_active_timeup(void)
{
if(g_activ_counter){
g_activ_counter = 0;
}
}
/* MQTT 数据接收处理 — IoT 模式 (ref: DBN101GA) */
void mqtt_data_manage(uint8_t id)
{
uint32_t len;
static uint8_t MyBuf[RECE_BUF_LEN]; // static: 避免栈溢出
unsigned char dup;
unsigned short packetid;
int qos;
unsigned char retained;
MQTTString topicName;
unsigned char *payload;
int payloadlen;
memset(MyBuf, 0, RECE_BUF_LEN);
len = WCHNET_SocketRecvLen(id, NULL);
WCHNET_SocketRecv(id, MyBuf, &len);
PRINT("MQTT recv sock=%d len=%d type=0x%02X\n", id, (int)len, MyBuf[0]);
switch (MyBuf[0] >> 4) {
case CONNACK:
PRINT("MQTT CONNACK\n");
dg_subscribe_display_topic();
dev_initialize_pub();
reset_net_active_timeup();
g_iot_state = IOT_STATE_READY; // Sync iot_mqtt_srv state
break;
case PUBLISH:
MQTTDeserialize_publish(&dup, &qos, &retained, &packetid,
&topicName, &payload, &payloadlen, MyBuf, len);
/* V1.01: 通过 mqtt_deserialize_publish 做 topic 过滤 */
{
char TmpBuf[128] = {0};
memcpy(TmpBuf, topicName.lenstring.data, topicName.lenstring.len);
mqtt_deserialize_publish(TmpBuf, (char *)payload, payloadlen);
}
reset_net_active_timeup();
break;
case SUBACK:
PRINT("MQTT SUBACK\n");
break;
case PINGRESP:
PRINT("MQTT PINGRESP\n");
if(flag_mqtt_ping_err)
flag_mqtt_ping_err = 0;
reset_net_active_timeup();
break;
default:
break;
}
g_net_state.flag = 4;
}
/*********************************************************************
* @fn WCHNET_DataManage
*
* @brief Data loopback function.
*
* @param id - socket id.
*
* @return none
*/
void WCHNET_DataManage(uint8_t id)
{
uint32_t len;
memset(MyBuf, 0, RECE_BUF_LEN);
unsigned char dup;
unsigned short packetid;
int qos;
unsigned char retained;
MQTTString topicName;
unsigned char* payload;
int payloadlen;
unsigned char *p=payload;
len = WCHNET_SocketRecvLen(id, NULL); //query length
WCHNET_SocketRecv(id, MyBuf, &len); //Read the data of the receive buffer into MyBuf
// totallen = len;
PRINT("Receive socketid:%d, Len = %d, MyBuf__:%s\r\n", id, len, MyBuf);
if(g_sub_code_enable.iot_enable){
switch(MyBuf[0] >> 4)
{
case CONNACK:
PRINT("connack\r\n");
// g_mqtt_con_flag=1;
dg_subscribe_display_topic();
dev_initialize_pub();
reset_net_active_timeup();
break;
case PUBLISH:
// use *dup, *qos, *retained, *packetid, *topicName, *payload, * payloadlen Will not work, miss some char from raw data.
MQTTDeserialize_publish(&dup,&qos,&retained,&packetid,&topicName,&payload,&payloadlen,MyBuf,len);
memset(TmpBuf, 0, MAX_TMP_BUF_LEN);
memcpy(TmpBuf, topicName.lenstring.data, topicName.lenstring.len);
// TmpBuf[topicName.lenstring.len] = 0x0;
mqtt_deserialize_publish(TmpBuf, payload, payloadlen);
// memset(payload, 0, payloadlen);
if(g_mqtt_ping_counter< 8){
g_mqtt_ping_counter = 8;
}
reset_net_active_timeup();
//TODO: need to check if len-received is out, prevent overflow.
break;
case SUBACK:
// sub_flag=1;
break;
case PINGRESP:
// printf("RecvPing\n");
//TODO: if need this?
if(flag_mqtt_ping_err)
{
flag_mqtt_ping_err = 0;
}
reset_net_active_timeup();
break;
default:
break;
}
}
else{
manage_tcp_message(id, MyBuf, len);
reset_net_active_timeup();
}
g_net_state.flag = 4;
}
/*********************************************************************
* @fn WCHNET_HandleSockInt
*
* @brief Socket Interrupt Handle
*
* @param socketid - socket id.
* intstat - interrupt status
*
* @return none
*/
void WCHNET_HandleSockInt(uint8_t socketid, uint8_t intstat)
{
uint8_t i;
// Route JSON protocol socket events -- always active regardless of mode
if (socketid == g_json_socket_listen || socketid == (g_json_socket_listen + 1)) {
tcp_json_handle_sock_int(socketid, intstat);
return;
}
// IoT MQTT mode — delegate all socket events to iot_mqtt_srv
// (2026-07-23 修复: 旧 mqtt_connect/mqtt_data_manage 与 IoT 栈抢 socket, 致双 CONNECT → broker 踢线 → 频繁 initialize)
if (g_sub_code_enable.iot_enable) {
if (intstat & SINT_STAT_CONNECT) {
#if KEEPLIVE_ENABLE
WCHNET_SocketSetKeepLive(socketid, ENABLE);
#endif
WCHNET_ModifyRecvBuf(socketid, (uint32_t)SocketRecvBuf[socketid], RECE_BUF_LEN);
PRINT("TCP Connect Success (MQTT IoT)\n");
}
if (intstat & SINT_STAT_DISCONNECT || intstat & SINT_STAT_TIM_OUT) {
PRINT("TCP Disconnect/Timeout (MQTT IoT)\n");
}
iot_mqtt_handle_sock_int(socketid, intstat);
return;
}
// === SSC mode below ===
g_net_state.intstat = intstat;
if (intstat & SINT_STAT_RECV) //receive data
{
WCHNET_DataManage(socketid); //Data loopback
}
if (intstat & SINT_STAT_CONNECT) //connect successfully
{
#if KEEPLIVE_ENABLE
WCHNET_SocketSetKeepLive(socketid, ENABLE);
#endif
WCHNET_ModifyRecvBuf(socketid, (uint32_t) SocketRecvBuf[socketid], RECE_BUF_LEN);
{
PRINT("TCP Connect Success\r\n");
PRINT("socket id: %d\r\n", socketid);
}
}
if (intstat & SINT_STAT_DISCONNECT) //disconnect
{
{
PRINT("TCP Disconnect\r\n");
}
g_net_state.flag = 1;
}
if (intstat & SINT_STAT_TIM_OUT) //timeout disconnect
{
{
PRINT("TCP Timeout\r\n");
}
g_net_state.flag = 1;
}
}
void dbn_net_ssc_srv(void)
{
uint8_t _flag_timestamp = 0;
static uint32_t _report_counter = 0; //ϱʱ
//Check net if connect
if(g_net_state.flag < 3)
{
return;
}
if((g_net_state.intstat & SINT_STAT_RECV) || (g_net_state.intstat & SINT_STAT_CONNECT))
{
//check if update timestamp
if(!g_flag_timestamp)
{
if(mstick() - _report_counter > 2000)
{
//printf("_will_require_timestamp, _report_counter:%d, mstick:%d\n", _report_counter, mstick());
dev_get_timestamp_send();
_report_counter = mstick();
}
return;
}
//send heartbeat
if(mstick() - _report_counter > 9000)
{
_report_counter = mstick();
dev_send_heartbeat();
}
}
}
void poll_mqtt(void)
{
if(g_net_state.flag < 2)
{
return;
}
// if(g_mqtt_con_flag == 0)
// {
// return;
// }
//
/* Auto-trigger PINGREQ every MQTT_KEEPALIVE_INTERVAL seconds of inactivity */
if (g_activ_counter > (MQTT_KEEPALIVE_INTERVAL * 1000)) {
g_activ_counter = 0;
flag_mqtt_ping_send = 1;
}
if(flag_mqtt_ping_send)
{
flag_mqtt_ping_send = 0;
flag_mqtt_ping_err++;
{
PRINT("send_mqtt_ping:%d\n", flag_mqtt_ping_err);
}
MQTT_Pingreq();
}
}
/*******************************************************************************
* Function Name : GetMacAddr
* Description : ϵͳȡMACַ
* Input : pMAC:ָ洢MacַĻ
* Output : None
* Return : None
*******************************************************************************/
void GetMacAddr(unsigned char *pMAC)
{
uint8_t transbuf[6],i;
FLASH_GetMACAddress(transbuf);
for(i=0;i<6;i++)
{
pMAC[5-i]=transbuf[i];
}
}
// IPv4ַַתΪ4ֽڵuint8_tϸĴ
int get_ipstr_to_array(char *src, uint8_t *dst) {
if (src == NULL || dst == NULL) {
return -1;
}
int part_count = 0;
char *token = NULL;
char *saveptr = NULL;
const char *delim = ".";
char src_copy[16];
strncpy(src_copy, src, sizeof(src_copy));
src_copy[15] = '\0';
token = strtok_r(src_copy, delim, &saveptr);
while (token != NULL && part_count < 4) {
char *endptr = NULL;
long val = strtol(token, &endptr, 10);
if (*endptr != '\0' || val < 0 || val > 255) {
return -2;
}
dst[part_count++] = (uint8_t)val;
token = strtok_r(NULL, delim, &saveptr);
}
if (part_count != 4) {
return -3;
}
if (token != NULL || (saveptr != NULL && *saveptr != '\0')) {
return -4;
}
return 0;
}
void unpack_ssc_count_off(uint8_t socket,uint8_t count_mode, uint8_t *ip, uint16_t port, uint8_t *buf, uint32_t len)
{
uint16_t i,j;
uint16_t tmplen = 0;
int serPort = 0;
char *p = (char *)buf;
char *mBuff = (char *)malloc(400);
if(mBuff == NULL)
{
// PRINT("__unpack_net_udp_err, malloc_failed.\n");
return;
}
if(count_mode == 0)
{
memset(mBuff, 0, 400);
simple_parse_json(p, DPG_API_KEY_PARAMS, mBuff);
tmplen = strlen(mBuff);
if(tmplen == 0)
{
free(mBuff);
return;
}
p = mBuff;
reset_temp_guide();
simple_parse_json(p, DPG_API_KEY_PORT, temp_guide);
for(i = 0; i < strlen(temp_guide); i++)
{
if((serPort > 0x39) || (serPort < 0x30))
{
break;
}
serPort *= 10;
serPort += temp_guide[i] - 0x30;
}
}
uint8_t qw = 1;
uint8_t ds = 1;
uint8_t mode = 0;
mode |= 1;
memset(mBuff, 0, 400);
sprintf(mBuff,"{"
"\"Method\": \"%s\","
"\"Code\":0,"
"\"Message\":\"\","
"\"Data\":{"
"\"Ip\": \"%d.%d.%d.%d\","
"\"Port\": %d,"
"\"Mac\": \"%02X-%02X-%02X-%02X-%02X-%02X\","
"\"SubnetMask\": \"%d.%d.%d.%d\","
"\"Server_Ip\": \"%d.%d.%d.%d\","
"\"Gateway\": \"%d.%d.%d.%d\","
"\"Iot_Host\":\"%s\","
"\"Iot_Port\":%d,"
"\"UserName\":\"%s\","
"\"Device_id\":\"%s\","
"\"Device_type\":\"%d\","
"\"Area_amount\": %d,"
"\"Dev_amount\": %d,"
"\"Dev_mode\":%d,"
"\"Version\":\"%s,H%s,S%s\""
"}}",
SSC_Code_Count_Off,
local_net_cfg.lip[0],local_net_cfg.lip[1],local_net_cfg.lip[2],local_net_cfg.lip[3],
serPort,
local_net_cfg.mac[0], local_net_cfg.mac[1], local_net_cfg.mac[2], local_net_cfg.mac[3], local_net_cfg.mac[4], local_net_cfg.mac[5],
local_net_cfg.sub[0], local_net_cfg.sub[1], local_net_cfg.sub[2], local_net_cfg.sub[3],
//net_center_info.lssc_ip[0], net_center_info.lssc_ip[1], net_center_info.lssc_ip[2], net_center_info.lssc_ip[3],
net_center_info.lssc_ip[0], net_center_info.lssc_ip[1], net_center_info.lssc_ip[2], net_center_info.lssc_ip[3],
local_net_cfg.gw[0], local_net_cfg.gw[1], local_net_cfg.gw[2], local_net_cfg.gw[3],
iot_net_info.remote_addr, iot_net_info.mqtt_port, iot_net_info.username,
g_dev_number_str,
g_dg_sub_dev_type, //g_dg_device_type,
qw, ds, mode,
PRODUCT_MODEL, HARDWARE_VER,FIRMWARE_VER);
slen = strlen(mBuff);
if(count_mode == 0)
{
WCHNET_SocketUdpSendTo(socket, (uint8_t *)mBuff, &slen, ip, COM_LSSC_MESSAGE_UDP_PORT);
}
else
{
WCHNET_SocketUdpSendTo(SocketId_UDP, (uint8_t *)mBuff, &slen, net_center_info.lssc_ip, COM_LSSC_MESSAGE_UDP_PORT);
}
free(mBuff);
}
void unpack_ssc_device_reset(uint8_t socket, uint8_t *ip, uint16_t port, uint8_t *buf, uint32_t len)
{
// λ
uint16_t tmplen = 0;
char *p = (char *)buf;
char *mBuff = (char *)malloc(512);
if(mBuff == NULL)
{
PRINT("__unpack_ssc_device_net_set_err, malloc_failed.\n");
return;
}
//printf("Recv_net_set:%s\n", buf);
memset(mBuff, 0, 512);
simple_parse_json(p, DPG_API_KEY_PARAMS, mBuff);
tmplen = strlen(mBuff);
if(tmplen == 0)
{
free(mBuff);
return;
}
p = mBuff;
reset_temp_guide();
simple_parse_json(p, DPG_API_KEY_DEVICE_ID, temp_guide);
if(strcmp(temp_guide, g_dev_number_str) != 0)
{
free(mBuff);
return;
}
memset(mBuff, 0, 512);
sprintf(mBuff,"{"
"\"Method\": \"%s\","
"\"Code\":0,"
"\"Message\":\"Success\","
"\"Data\":{"
"\"Device_id\":\"%s\""
"}}", SSC_Code_Dev_Reset, g_dev_number_str);
slen = strlen(mBuff);
WCHNET_SocketSend(socket, (uint8_t *)mBuff, &slen);
free(mBuff);
Delay_Ms(100);
NVIC_SystemReset();
}
void unpack_ssc_tran_sub(uint8_t socket, uint8_t *ip, uint16_t port, uint8_t *buf, uint32_t len)
{
uint16_t i, j;
uint16_t tmplen = 0;
char *p = (char *)buf;
char *mBuff = (char *)malloc(512);
if(mBuff == NULL)
{
return;
}
memset(mBuff, 0, 512);
simple_parse_json(p, DPG_API_KEY_PARAMS, mBuff);
tmplen = strlen(mBuff);
if(tmplen == 0)
{
free(mBuff);
return;
}
p = mBuff;
reset_temp_guide();
simple_parse_json(p, DPG_API_KEY_DEVICE_ID, temp_guide);
if(strcmp(temp_guide, g_dev_number_str) != 0)
{
free(mBuff);
return;
}
reset_temp_guide();
uint8_t _dev_type = 0;
simple_parse_json(p, SSC_Code_Dev_Type, temp_guide);
// printf("get_dev_type_str:%s\n", temp_guide);
for(i = 0; i < strlen(temp_guide); i++)
{
if((temp_guide[i] >= 0x30) && (temp_guide[i] <= 0x39))
{
_dev_type *= 10;
_dev_type += temp_guide[i] - 0x30;
}
}
free(mBuff);
}
void unpack_ssc_timestamp(uint8_t *buf, uint32_t len)
{
uint16_t tmplen = 0;
static uint8_t _first = 0;
char *p = (char *)buf;
char *mBuff = (char *)malloc(150);
if(mBuff == NULL)
{
// PRINT("__unpack_ssc_collect_cjq_acs_response_err, malloc_failed.\n");
return;
}
//printf("Recv_net_timestamp_response:%s\n", buf);
memset(mBuff, 0, 150);
simple_parse_json(p, DPG_API_KEY_DATA, mBuff);
if(strlen(mBuff) == 0)
{
free(mBuff);
return;
}
p = mBuff;
reset_temp_guide();
simple_parse_json(p, DPG_API_KEY_DEVICE_ID, temp_guide);
tmplen = strlen(temp_guide);
if(tmplen == 0)
{
free(mBuff);
return;
}
// PRINT("\n%s, line:%d, temp:%s, device_id:%s\n", __FUNCTION__, __LINE__, mBuff, g_dev_number_str);
if(strstr(temp_guide, g_dev_number_str) == NULL)
{
free(mBuff);
return;
}
g_activ_counter = 0; // mstick(); // reset active_counter
uint32_t _counter = 0;
uint16_t i = 0;
reset_temp_guide();
simple_parse_json(p, KEY_CODE_Time_Counter, temp_guide);
//printf("timestampStr:%s, p:%s\n", temp_guide, p);
for(i = 0; i < strlen(temp_guide); i++)
{
if((temp_guide[i] > 0x39) || (temp_guide[i] < 0x30))
{
break;
}
_counter *= 10;
_counter += temp_guide[i] - 0x30;
}
free(mBuff);
// uint32_t _c_counter = get_rtc_counter();
if(_first == 0)
{
//printf("before_settime,rtc_counter:%d\n", get_rtc_counter());
_first = 1;
uint16_t py,pmon,pday, phour, pmin, psec ;
// RTC_GetTime(&py,&pmon, &pday, &phour, &pmin, &psec);
// printf("\nGet_time %d-%d-%d %d:%d:%d\n", py, pmon, pday, phour, pmin, psec);
// set_rtc_from_timecount(_counter);
// RTC_GetTime(&py,&pmon, &pday, &phour, &pmin, &psec);
// printf("\nafter_settime_Get_time %d-%d-%d %d:%d:%d\n", py, pmon, pday, phour, pmin, psec);
// printf("after_settime, rtc_counter:%d\n", get_rtc_counter());
}
if(g_flag_timestamp == 0)
{
g_flag_timestamp = 1;
unpack_ssc_count_off(SocketId_UDP, 1, NULL, 0, NULL, 0);
}
else
{
// rcv_acs_dus_report_reponse();
}
}
void manage_tcp_message(uint8_t socket, uint8_t *buf, uint32_t len)
{
uint16_t tmplen = 0;
char *p = (char *)buf;
char *mMethod = (char *)malloc(20);
if(mMethod == NULL)
{
// PRINT("__unpack_net_udp0_err, malloc_failed.\n");
return;
}
memset(mMethod, 0, 20);
simple_parse_json(p, DPG_API_KEY_METHOD, mMethod);
if(strstr(mMethod, SSC_Code_TimeStamp) != NULL)
{
unpack_ssc_timestamp(buf, len);
}
free(mMethod);
}
void manage_udp_message(uint8_t socket, uint8_t *ip, uint16_t port, uint8_t *buf, uint32_t len)
{
uint16_t tmplen = 0;
char *p = (char *)buf;
char *mMethod = (char *)malloc(20);
if(mMethod == NULL)
{
// PRINT("__unpack_net_udp0_err, malloc_failed.\n");
return;
}
memset(mMethod, 0, 20);
simple_parse_json(p, DPG_API_KEY_METHOD, mMethod);
if(strstr(mMethod, SSC_Code_Count_Off) != NULL)
{
unpack_ssc_count_off(socket, 0, ip, port, buf, len);
}
else if(strstr(mMethod, SSC_Code_Dev_Reset) != NULL)
{
unpack_ssc_device_reset(socket, ip, port, buf, len);
}
// else if(strstr(mMethod, SSC_Code_Device_Net_Set) != NULL)
// {
// unpack_ssc_device_net_set(socket, ip, port, buf, len);
// }
else if(strstr(mMethod, SSC_Code_Tran_Sub) != NULL)
{
unpack_ssc_tran_sub(socket, ip, port, buf, len);
}
// else if(strstr(mMethod, SSC_Code_Radar_Reset) != NULL)
// {
// unpack_ssc_radar_reset(socket, ip, port, buf, len);
// }
free(mMethod);
}
void manage_mqtt_recv_message(char * msg, int length)
{
uint8_t i = 0;
uint16_t tmplen = 0;
// Validate input parameters
if(msg == NULL || length <= 0) {
PRINT("Invalid MQTT message parameters\n");
return;
}
reset_temp_guide();
// V1.01: 优先解析新协议 cmd 字段,兼容旧 Method 字段
simple_parse_json(msg, "\"cmd\"", temp_guide);
if(strlen(temp_guide) == 0) {
simple_parse_json(msg, DPG_API_KEY_METHOD, temp_guide);
}
if(strlen(temp_guide) == 0)
{
PRINT("\nmethod is none..\n");
return;
}
PRINT("Rcv_Dis_LED_m:%s\n", temp_guide);
// 旧协议: Method = Heartbeat → 回复心跳
if(strstr(temp_guide, "Heartbeat") != NULL)
{
dev_response_heartbeat(NULL);
return;
}
// === V1.01 新协议: cmd 命令分发 ===
// 解析 msg_id
char tmp[32] = {0};
uint32_t msg_id = 0;
simple_parse_json(msg, "\"msg_id\"", tmp);
if(strlen(tmp) > 0) msg_id = (uint32_t)strtoul(tmp, NULL, 10);
// 方案B: 由下行命令 ts 校准本地时钟。平台在 initialize 上线后经 report_config
// 下发真 Unix 时间; dev_time_sync 内部有合法性门槛, 非法/上电秒数会被忽略。
// report_config 为约定主同步点, 此处对任意携带合法 ts 的下行命令均校准。
{
char ts_str[16] = {0};
simple_parse_json(msg, "\"ts\"", ts_str);
if(strlen(ts_str) > 0) dev_time_sync((uint32_t)strtoul(ts_str, NULL, 10));
}
// 去掉 temp_guide 里的引号
char *cmd_str = temp_guide;
if(cmd_str[0] == '"') cmd_str++;
int cmd_len = strlen(cmd_str);
if(cmd_len > 0 && cmd_str[cmd_len - 1] == '"') cmd_str[cmd_len - 1] = '\0';
// 响应 topic: g_iot_topic.topic_pub (= dld960/{sn}/dev)
char *resp_topic = (char *)g_iot_topic.topic_pub;
// --- dev_info_query ---
if(strcmp(cmd_str, "dev_info_query") == 0) {
char resp[600];
snprintf(resp, sizeof(resp),
"{\"msg_id\":%lu,\"cmd\":\"dev_info_query\","
"\"ts\":%lu,\"code\":0,\"msg\":\"success\","
"\"data\":{"
"\"dev_serial\":\"%s\",\"hard_ver\":\"%s\",\"soft_ver\":\"%s\","
"\"model\":\"%s\",\"product_code\":\"960001\","
"\"sub_code\":{\"net\":%s,\"iot\":%s},"
"\"bus\":{\"bus1\":0,\"bus2\":0,\"bus3\":0,\"bus4\":0}}}",
msg_id, dev_time_now(),
g_dev_number_str, HARDWARE_VER, FIRMWARE_VER, PRODUCT_MODEL,
g_sub_code_enable.net_enable ? "true" : "false",
g_sub_code_enable.iot_enable ? "true" : "false");
mqtt_publish(resp_topic, resp, 1);
PRINT("IOT: dev_info_query → response\n");
return;
}
// --- pwd_verify ---
if(strcmp(cmd_str, "pwd_verify") == 0) {
char *data_buf = (char *)malloc(256);
char password[16] = {0};
if(data_buf) {
memset(data_buf, 0, 256);
simple_parse_json(msg, "\"data\"", data_buf);
if(strlen(data_buf) > 0) {
memset(tmp, 0, sizeof(tmp));
simple_parse_json(data_buf, "\"password\"", tmp);
char *pwd = tmp;
if(pwd[0] == '"') pwd++;
int plen = strlen(pwd);
if(plen > 0 && pwd[plen - 1] == '"') pwd[plen - 1] = '\0';
strncpy(password, pwd, 15);
}
free(data_buf);
}
if(strlen(password) == 6 && memcmp(password, g_dev_password, 6) == 0) {
char resp[256];
snprintf(resp, sizeof(resp),
"{\"msg_id\":%lu,\"cmd\":\"pwd_verify\","
"\"ts\":%lu,\"code\":0,\"msg\":\"success\"}",
msg_id, dev_time_now());
mqtt_publish(resp_topic, resp, 1);
PRINT("IOT: pwd_verify OK\n");
} else {
char resp[256];
snprintf(resp, sizeof(resp),
"{\"msg_id\":%lu,\"cmd\":\"pwd_verify\","
"\"ts\":%lu,\"code\":2,\"msg\":\"password incorrect\"}",
msg_id, dev_time_now());
mqtt_publish(resp_topic, resp, 1);
}
return;
}
// --- dev_serial_set ---
if(strcmp(cmd_str, "dev_serial_set") == 0) {
// TODO: 实现序列号修改
char resp[256];
snprintf(resp, sizeof(resp),
"{\"msg_id\":%lu,\"cmd\":\"dev_serial_set\","
"\"ts\":%lu,\"code\":4,\"msg\":\"not implemented yet\"}",
msg_id, dev_time_now());
mqtt_publish(resp_topic, resp, 1);
return;
}
// --- ssc_net_query ---
if(strcmp(cmd_str, "ssc_net_query") == 0) {
char resp[512];
snprintf(resp, sizeof(resp),
"{\"msg_id\":%lu,\"cmd\":\"ssc_net_query\","
"\"ts\":%lu,\"code\":0,\"msg\":\"success\","
"\"data\":{"
"\"dev_ip\":\"%d.%d.%d.%d\","
"\"subnet_mask\":\"%d.%d.%d.%d\","
"\"route_ip\":\"%d.%d.%d.%d\","
"\"lssc_ip\":\"%d.%d.%d.%d\","
"\"dns\":\"%d.%d.%d.%d\","
"\"port\":%d}}",
msg_id, dev_time_now(),
local_net_cfg.lip[0], local_net_cfg.lip[1], local_net_cfg.lip[2], local_net_cfg.lip[3],
local_net_cfg.sub[0], local_net_cfg.sub[1], local_net_cfg.sub[2], local_net_cfg.sub[3],
local_net_cfg.gw[0], local_net_cfg.gw[1], local_net_cfg.gw[2], local_net_cfg.gw[3],
net_center_info.lssc_ip[0], net_center_info.lssc_ip[1], net_center_info.lssc_ip[2], net_center_info.lssc_ip[3],
local_net_cfg.dns[0], local_net_cfg.dns[1], local_net_cfg.dns[2], local_net_cfg.dns[3],
local_net_cfg.port_ssc_tcp);
mqtt_publish(resp_topic, resp, 1);
return;
}
// --- ssc_net_set ---
if(strcmp(cmd_str, "ssc_net_set") == 0) {
Local_Net_Cfg lcfg = local_net_cfg;
NET_CENTER_INFO ccfg = net_center_info;
char *data_buf = (char *)malloc(256);
if(data_buf) {
memset(data_buf, 0, 256);
simple_parse_json(msg, "\"data\"", data_buf);
if(strlen(data_buf) > 0) {
char ip_str[32];
int plen;
// dev_ip
memset(ip_str, 0, sizeof(ip_str));
simple_parse_json(data_buf, "\"dev_ip\"", ip_str);
if(strlen(ip_str) > 0) {
char *s = ip_str; if(s[0]=='"') s++; plen=strlen(s); if(plen>0&&s[plen-1]=='"') s[plen-1]=0;
get_ipstr_to_array(s, lcfg.lip);
}
// subnet_mask
memset(ip_str, 0, sizeof(ip_str));
simple_parse_json(data_buf, "\"subnet_mask\"", ip_str);
if(strlen(ip_str) > 0) {
char *s = ip_str; if(s[0]=='"') s++; plen=strlen(s); if(plen>0&&s[plen-1]=='"') s[plen-1]=0;
get_ipstr_to_array(s, lcfg.sub);
}
// route_ip
memset(ip_str, 0, sizeof(ip_str));
simple_parse_json(data_buf, "\"route_ip\"", ip_str);
if(strlen(ip_str) > 0) {
char *s = ip_str; if(s[0]=='"') s++; plen=strlen(s); if(plen>0&&s[plen-1]=='"') s[plen-1]=0;
get_ipstr_to_array(s, lcfg.gw);
}
// lssc_ip
memset(ip_str, 0, sizeof(ip_str));
simple_parse_json(data_buf, "\"lssc_ip\"", ip_str);
if(strlen(ip_str) > 0) {
char *s = ip_str; if(s[0]=='"') s++; plen=strlen(s); if(plen>0&&s[plen-1]=='"') s[plen-1]=0;
get_ipstr_to_array(s, ccfg.lssc_ip);
}
// dns
memset(ip_str, 0, sizeof(ip_str));
simple_parse_json(data_buf, "\"dns\"", ip_str);
if(strlen(ip_str) > 0) {
char *s = ip_str; if(s[0]=='"') s++; plen=strlen(s); if(plen>0&&s[plen-1]=='"') s[plen-1]=0;
get_ipstr_to_array(s, lcfg.dns);
}
// port
memset(tmp, 0, sizeof(tmp));
simple_parse_json(data_buf, "\"port\"", tmp);
if(strlen(tmp) > 0) {
uint32_t p = strtoul(tmp, NULL, 10);
if(p > 0 && p <= 65535) ccfg.tcp_port = (uint16_t)p;
}
}
free(data_buf);
}
write_net_config(&lcfg, &ccfg, &iot_net_info, &g_iot_topic);
local_net_cfg = lcfg;
net_center_info = ccfg;
char resp[256];
snprintf(resp, sizeof(resp),
"{\"msg_id\":%lu,\"cmd\":\"ssc_net_set\","
"\"ts\":%lu,\"code\":0,\"msg\":\"success\"}",
msg_id, dev_time_now());
mqtt_publish(resp_topic, resp, 1);
PRINT("IOT: ssc_net_set done\n");
return;
}
// --- iot_net_query ---
if(strcmp(cmd_str, "iot_net_query") == 0) {
char resp[512];
snprintf(resp, sizeof(resp),
"{\"msg_id\":%lu,\"cmd\":\"iot_net_query\","
"\"ts\":%lu,\"code\":0,\"msg\":\"success\","
"\"data\":{"
"\"host\":\"%s\",\"port\":%d,"
"\"client_id\":\"%s\",\"username\":\"%s\",\"password\":\"%s\"}}",
msg_id, dev_time_now(),
iot_net_info.remote_addr, iot_net_info.mqtt_port,
iot_net_info.client_id, iot_net_info.username, iot_net_info.password);
mqtt_publish(resp_topic, resp, 1);
return;
}
// --- iot_net_set ---
if(strcmp(cmd_str, "iot_net_set") == 0) {
IOT_NET_INFO icfg = iot_net_info;
char *data_buf = (char *)malloc(256);
if(data_buf) {
memset(data_buf, 0, 256);
simple_parse_json(msg, "\"data\"", data_buf);
if(strlen(data_buf) > 0) {
char fld[64];
int plen;
// host
memset(fld, 0, sizeof(fld));
simple_parse_json(data_buf, "\"host\"", fld);
if(strlen(fld) > 0) {
char *s = fld; if(s[0]=='"') s++; plen=strlen(s); if(plen>0&&s[plen-1]=='"') s[plen-1]=0;
strncpy((char *)icfg.remote_addr, s, 63);
}
// port
memset(tmp, 0, sizeof(tmp));
simple_parse_json(data_buf, "\"port\"", tmp);
if(strlen(tmp) > 0) {
uint32_t p = strtoul(tmp, NULL, 10);
if(p > 0 && p <= 65535) icfg.mqtt_port = (uint16_t)p;
}
// client_id
memset(fld, 0, sizeof(fld));
simple_parse_json(data_buf, "\"client_id\"", fld);
if(strlen(fld) > 0) {
char *s = fld; if(s[0]=='"') s++; plen=strlen(s); if(plen>0&&s[plen-1]=='"') s[plen-1]=0;
strncpy((char *)icfg.client_id, s, 63);
}
// username
memset(fld, 0, sizeof(fld));
simple_parse_json(data_buf, "\"username\"", fld);
if(strlen(fld) > 0) {
char *s = fld; if(s[0]=='"') s++; plen=strlen(s); if(plen>0&&s[plen-1]=='"') s[plen-1]=0;
strncpy((char *)icfg.username, s, 63);
}
// password
memset(fld, 0, sizeof(fld));
simple_parse_json(data_buf, "\"password\"", fld);
if(strlen(fld) > 0) {
char *s = fld; if(s[0]=='"') s++; plen=strlen(s); if(plen>0&&s[plen-1]=='"') s[plen-1]=0;
strncpy((char *)icfg.password, s, 31);
}
}
free(data_buf);
}
write_net_config(&local_net_cfg, &net_center_info, &icfg, &g_iot_topic);
iot_net_info = icfg;
char resp[256];
snprintf(resp, sizeof(resp),
"{\"msg_id\":%lu,\"cmd\":\"iot_net_set\","
"\"ts\":%lu,\"code\":0,\"msg\":\"success\"}",
msg_id, dev_time_now());
mqtt_publish(resp_topic, resp, 1);
PRINT("IOT: iot_net_set done\n");
return;
}
// --- iot_topic_query ---
if(strcmp(cmd_str, "iot_topic_query") == 0) {
char resp[512];
snprintf(resp, sizeof(resp),
"{\"msg_id\":%lu,\"cmd\":\"iot_topic_query\","
"\"ts\":%lu,\"code\":0,\"msg\":\"success\","
"\"data\":{"
"\"client_id_enable\":%s,"
"\"topic_pub\":\"%s\",\"topic_sub\":\"%s\"}}",
msg_id, dev_time_now(),
g_iot_topic.clientid_enable ? "true" : "false",
g_iot_topic.topic_pub, g_iot_topic.topic_sub);
mqtt_publish(resp_topic, resp, 1);
return;
}
// --- iot_topic_set ---
if(strcmp(cmd_str, "iot_topic_set") == 0) {
IOT_Topic topic = g_iot_topic;
char *data_buf = (char *)malloc(256);
if(data_buf) {
memset(data_buf, 0, 256);
simple_parse_json(msg, "\"data\"", data_buf);
if(strlen(data_buf) > 0) {
char fld[64];
int plen;
// client_id_enable (bool)
memset(tmp, 0, sizeof(tmp));
simple_parse_json(data_buf, "\"client_id_enable\"", tmp);
if(strlen(tmp) > 0) topic.clientid_enable = (uint8_t)(strstr(tmp, "true") ? 1 : 0);
// topic_pub
memset(fld, 0, sizeof(fld));
simple_parse_json(data_buf, "\"topic_pub\"", fld);
if(strlen(fld) > 0) {
char *s = fld; if(s[0]=='"') s++; plen=strlen(s); if(plen>0&&s[plen-1]=='"') s[plen-1]=0;
strncpy((char *)topic.topic_pub, s, 63);
}
// topic_sub
memset(fld, 0, sizeof(fld));
simple_parse_json(data_buf, "\"topic_sub\"", fld);
if(strlen(fld) > 0) {
char *s = fld; if(s[0]=='"') s++; plen=strlen(s); if(plen>0&&s[plen-1]=='"') s[plen-1]=0;
strncpy((char *)topic.topic_sub, s, 63);
}
}
free(data_buf);
}
write_net_config(&local_net_cfg, &net_center_info, &iot_net_info, &topic);
g_iot_topic = topic;
char resp[256];
snprintf(resp, sizeof(resp),
"{\"msg_id\":%lu,\"cmd\":\"iot_topic_set\","
"\"ts\":%lu,\"code\":0,\"msg\":\"success\"}",
msg_id, dev_time_now());
mqtt_publish(resp_topic, resp, 1);
PRINT("IOT: iot_topic_set done\n");
return;
}
// --- pwd_set ---
if(strcmp(cmd_str, "pwd_set") == 0) {
char resp[256];
snprintf(resp, sizeof(resp),
"{\"msg_id\":%lu,\"cmd\":\"pwd_set\","
"\"ts\":%lu,\"code\":4,\"msg\":\"not implemented yet\"}",
msg_id, dev_time_now());
mqtt_publish(resp_topic, resp, 1);
return;
}
// --- factory_reset ---
if(strcmp(cmd_str, "factory_reset") == 0) {
char resp[256];
snprintf(resp, sizeof(resp),
"{\"msg_id\":%lu,\"cmd\":\"factory_reset\","
"\"ts\":%lu,\"code\":0,\"msg\":\"success\"}",
msg_id, dev_time_now());
mqtt_publish(resp_topic, resp, 1);
PRINT("IOT: factory_reset — resetting...\n");
Delay_Ms(200);
factory_dev_info();
return;
}
// --- device_reset (无响应,复位后断开) ---
if(strcmp(cmd_str, "device_reset") == 0) {
PRINT("IOT: device_reset — rebooting...\n");
NVIC_SystemReset();
return;
}
// --- report_config ---
if(strcmp(cmd_str, "report_config") == 0) {
char *data_buf = (char *)malloc(512);
if(data_buf) {
memset(data_buf, 0, 512);
simple_parse_json(msg, "\"data\"", data_buf);
if(strlen(data_buf) > 0) {
// sensor_type (int)
memset(tmp, 0, sizeof(tmp));
simple_parse_json(data_buf, "\"sensor_type\"", tmp);
if(strlen(tmp) > 0) g_report_cfg.sensor_type = (uint8_t)strtoul(tmp, NULL, 10);
// enable (bool)
memset(tmp, 0, sizeof(tmp));
simple_parse_json(data_buf, "\"enable\"", tmp);
if(strlen(tmp) > 0) g_report_cfg.enable = (uint8_t)(strstr(tmp, "true") ? 1 : 0);
// once (bool)
memset(tmp, 0, sizeof(tmp));
simple_parse_json(data_buf, "\"once\"", tmp);
if(strlen(tmp) > 0) g_report_cfg.once = (uint8_t)(strstr(tmp, "true") ? 1 : 0);
// env_eval (bool)
memset(tmp, 0, sizeof(tmp));
simple_parse_json(data_buf, "\"env_eval\"", tmp);
if(strlen(tmp) > 0) g_report_cfg.env_eval = (uint8_t)(strstr(tmp, "true") ? 1 : 0);
// interval (int)
memset(tmp, 0, sizeof(tmp));
simple_parse_json(data_buf, "\"interval\"", tmp);
if(strlen(tmp) > 0) g_report_cfg.interval = (uint16_t)strtoul(tmp, NULL, 10);
// ack_required (bool)
memset(tmp, 0, sizeof(tmp));
simple_parse_json(data_buf, "\"ack_required\"", tmp);
if(strlen(tmp) > 0) g_report_cfg.ack_required = (uint8_t)(strstr(tmp, "true") ? 1 : 0);
// timeout (int)
memset(tmp, 0, sizeof(tmp));
simple_parse_json(data_buf, "\"timeout\"", tmp);
if(strlen(tmp) > 0) g_report_cfg.timeout = (uint16_t)strtoul(tmp, NULL, 10);
}
free(data_buf);
}
char resp[400];
snprintf(resp, sizeof(resp),
"{\"msg_id\":%lu,\"cmd\":\"report_config\","
"\"ts\":%lu,\"code\":0,\"msg\":\"success\","
"\"data\":{"
"\"sensor_type\":%d,\"enable\":%s,\"once\":%s,\"env_eval\":%s,"
"\"interval\":%u,\"ack_required\":%s,\"timeout\":%u}}",
msg_id, dev_time_now(),
g_report_cfg.sensor_type,
g_report_cfg.enable ? "true" : "false",
g_report_cfg.once ? "true" : "false",
g_report_cfg.env_eval ? "true" : "false",
g_report_cfg.interval,
g_report_cfg.ack_required ? "true" : "false",
g_report_cfg.timeout);
mqtt_publish(resp_topic, resp, 1);
PRINT("IOT: report_config enable=%d interval=%u sensor=%d\n",
g_report_cfg.enable, g_report_cfg.interval, g_report_cfg.sensor_type);
return;
}
// --- event_report 平台应答 (V1.04): 回显帧, 确认后出队, 不再回复 ---
if(strcmp(cmd_str, "event_report") == 0) {
int code = -1;
memset(tmp, 0, sizeof(tmp));
simple_parse_json(msg, "\"code\"", tmp);
if(strlen(tmp) > 0) code = (int)strtol(tmp, NULL, 10);
iot_evt_handle_ack(msg_id, code);
return; // 应答帧终止于此, 严禁再回 unsupported (否则与平台互相打乒乓)
}
// --- 未支持的命令 ---
{
char resp[256];
snprintf(resp, sizeof(resp),
"{\"msg_id\":%lu,\"cmd\":\"%s\","
"\"ts\":%lu,\"code\":4,\"msg\":\"unsupported command\"}",
msg_id, cmd_str, dev_time_now());
mqtt_publish(resp_topic, resp, 1);
PRINT("IOT: unsupported cmd=%s\n", cmd_str);
}
}
/*********************************************************************
* @fn WCHNET_HandleGlobalInt
*
* @brief Global Interrupt Handle
*
* @return none
*/
void WCHNET_HandleGlobalInt(void)
{
uint8_t intstat;
uint16_t i;
uint8_t socketint;
intstat = WCHNET_GetGlobalInt(); //get global interrupt flag
if (intstat & GINT_STAT_UNREACH ) //Unreachable interrupt
{
PRINT("GINT_STAT_UNREACH\r\n");
}
if (intstat & GINT_STAT_IP_CONFLI) //IP conflict
{
PRINT("GINT_STAT_IP_CONFLI\r\n");
}
if (intstat & GINT_STAT_PHY_CHANGE) //PHY status change
{
i = WCHNET_GetPHYStatus();
if (i & PHY_Linked_Status)
PRINT("PHY Link Success\r\n");
}
if (intstat & GINT_STAT_SOCKET) //socket related interrupt
{
for (i = 0; i < WCHNET_MAX_SOCKET_NUM; i++) {
socketint = WCHNET_GetSocketInt(i);
if (socketint) {
PRINT("SockInt: sock=%d stat=0x%02X\n", i, socketint);
WCHNET_HandleSockInt(i, socketint);
}
}
}
}
void net_srv_init(void)
{
uint8_t i;
if(g_net_state.flag == 0)
{
i = ETH_LibInit(local_net_cfg.lip, local_net_cfg.gw, local_net_cfg.sub, local_net_cfg.mac); //Ethernet library initialize
mStopIfError(i);
if (i == WCHNET_ERR_SUCCESS)
{
PRINT("WCHNET_LibInit Success\r\n");
g_net_state.flag = 1;
#if KEEPLIVE_ENABLE //Configure keeplive parameters
{
struct _KEEP_CFG cfg;
cfg.KLIdle = 20000;
cfg.KLIntvl = 15000;
cfg.KLCount = 9;
WCHNET_ConfigKeepLive(&cfg);
}
#endif
memset(socket, 0xff, WCHNET_MAX_SOCKET_NUM);
}
}
if(g_net_state.flag == 1)
{
if (g_sub_code_enable.iot_enable) {
/* IoT MQTT mode -- init MQTT client, skip UDP */
iot_mqtt_init(); // Init IoT MQTT client (connect to broker)
g_net_state.flag = 2; // Skip SSC init, advance state directly
} else {
/* SSC mode -- create UDP socket + JSON server */
WCHNET_CreateUdpSocket();
tcp_json_srv_init(); // Start JSON protocol TCP listener on port 5960
}
}
}