Files
vd_960/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/net_srv.c
T
wangfq c879ed04e2 fix(vd960DBN): 0x8F 接入 DBN 私有指令处理器 + net_srv 裸 printf + devlog 行尾
按用户 2026-09-10 四条指示:

1) 0x8F 下行的"本地处理"明确为 CH32V208GBU6 私有指令 —— 只作用在自身读写配置上,
   一般不转发。实现: 不再留空壳计数, 直接复用 BLE 侧同一个分发器
   manage_dbn_ble_default() (dbn_ble_srv.c:729)。两侧帧布局完全一致
   (pkg[1]=Addr, pkg[2]=LEN, pkg[3]=CMD, pkg[4..]=Value), 零适配。
   响应仍走 g_buf_ble_response -> BLE 通知; 不回 4G —— Air780 侧 parser 只认 0x7F,
   回 0x8F 也没人接。
   增加 OTA 门控: g_flag_counter_ota.flag != 0 时拒绝私有指令 ——
   私有指令会写自身配置(碰 flash), 与 OTA 刷写并发是自找麻烦。
   魔数宏改用 dbn_ble_srv.h 的 MAGIC_BYTE_DBN_DEFAULT, 不再硬编码 0x8F。

2) 0x7D 帧: 删除/不理会。V1.11 曾提的 DBN<->Air780 握手/配置同步构想作废,
   代码里本就没实现, 正式协议也从未收录。devlog 待办项移除, 记入"已定案"。

3) net_srv.c:125 裸 printf() -> PRINT。该文件本已用 PRINT 53 处, 无需补 include。
   DEBUG=0 时随 PRINT 一起消失, 不再出现"往未初始化的 USART1 写字节"。

4) devlog.md 行尾统一 CRLF (修复 132 个孤立 LF: 顶部 V1.13 条目原为 LF)。

验证 (host 单测, 代码从 usart_biz.c 原样抽取, gcc -Wall -Wextra -Werror 零警告):
  15 组用例全部通过, 其中新增:
  - 0x8F -> manage_dbn_ble_default 被调用 1 次, 传入 len==全帧长, 内容逐字节一致, 未转发
  - OTA 期间 0x8F -> 处理器未被调用, 但仍计数 (可观测)
  原有 13 组 (魔数分流/最大帧/坏帧回找魔数/截断帧不丢帧/LEN 非法/0x9F 忽略...) 保持通过。

待板级验证: 需 MounRiver 工具链编译 + 实机 (本机无 riscv 工具链)。
2026-09-10 16:41:09 +08:00

1683 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 800 // 2026-08-17: 1024→800 (loop_data~604B+头<800; 512仍不够勿改回) 省224B .bss
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;
PRINT("Error: 0x%02X\r\n", (u16)iError); /* 原裸 printf: DEBUG=0 时会去写未被初始化的 USART1 */
}
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);
}
if (i != WCHNET_ERR_SUCCESS) {
/* 2026-08-20: SocketCreat 失败 (0x1D ISCONN 等, 旧 socket 未清干净)
置无效并返回, 由上层退避重试 — 继续 Connect 只会等超时死循环 */
PRINT("MQTT: SocketCreat failed 0x%02X, abort connect\r\n", i);
SocketId_TCP = 0xFF;
return;
}
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
}
}
}