Selaa lähdekoodia

增加:蓝牙模块处理

EWen 2 kuukautta sitten
vanhempi
commit
11d3d4e1df

+ 906 - 0
app_public/bluetooth/bluetooth.c

@@ -0,0 +1,906 @@
+#include "head.h"
+#include "bluetooth.h"
+
+// #define BL_DEBUG                                // 调试打印
+#define FREAM_SPLIT_LEN             (240)       // 分帧长度
+#define FREAM_INTERVAL_TIME_MS      (65)        // 帧间隔ms,手册建议帧间隔60ms以上
+#define BL_DISC_REBOOT_TIME_MS      (100)       // 连接断开复位蓝牙延时ms
+#define BL_IDLE_REBOOT_TIME_MS      (120000)    // 蓝牙空闲状态自动复位延时ms
+
+#define BL_ENABLE_RESEND_MODE       (1)         // 重发机制
+#define BL_RESEND_TIMES             (3)         // 重发次数
+#define BL_RECV_TIMEOUT_MS          (500)       // 接收超时时间
+#define BL_TIMEOUT_RESEND_MS        (500)       // 超时重发时间
+
+#define BLUETOOTH_DEFAULT_NAME      "OLE-DTUv5" // 蓝牙默认名称,获取ID失败时设置此蓝牙名称
+
+/* 各指令详细描述请参考蓝牙手册,路径:Z:\研发中心\研发二部\共享\88_DTU5.0\02蓝牙模块 */
+/* AT指令匹配列表 */
+const struct at_cmd_index_match at_cmd_index_match[AT_CMD_MAX] = 
+{
+    //指令字符串  追加字符串 指令结束字符串  数据段结束字符串 指令结果结束字符串    指令匹配的枚举类型
+    {"SCAN"		,	"="	,   "{\r\n"	,       "}\r\n" ,       NULL	    ,       AT_CMD_SACN     },
+	{"CONN"		,	"="	,   "="	    ,       NULL	,       NULL	    ,       AT_CMD_CONN     },
+	{"CHINFO"	,	""  ,   "{\r\n"	,       "}\r\n"	,       "OK\r\n"    ,       AT_CMD_CHINFO   },
+	{"LESEND"	,	"=" ,   "\r\n"	,       NULL	,       "OK\r\n"	,       AT_CMD_LESEND   },	
+	{"LEDISC"	,	"="	,   "="	    ,       "\r\n"  ,       NULL	    ,       AT_CMD_LEDISC   },	
+	{"NAME"		,	"="	,   "="	    ,       "\r\n"  ,       "OK\r\n"	,       AT_CMD_NAME     },	
+	{"MAC"		,	""	,   "="	    ,       "\r\n"	,       "OK\r\n"	,       AT_CMD_MAC      },
+	{"REBOOT"	,	""	,   "\r\n"	,       NULL	,       "OK\r\n"	,       AT_CMD_REBOOT   },
+    {"DATA"	    ,	""	,   "="	    ,       "\r\n"	,       NULL	    ,       AT_CMD_DATA     },
+    {"GATTSTAT"	,	""	,   "="	    ,       "\r\n"	,       NULL	    ,       AT_CMD_STAT     },
+};
+
+/**
+ * @brief   获取一个buf
+ * @details 从缓存队列中返回一个buf
+ * @param   _pt 结构体指针
+ * @return  buf索引
+ * @author  EWen
+ * @date    2025-10-11
+ * @remarks 增加发送队列缓存是考虑到多帧分帧放进缓存后自动发送,但目前报文组帧处理了可以一帧发完,暂时用不上
+ */
+static u8 _get_one_buf(bl_tbuf_t *pt)
+{
+	u8 head;
+	
+	head = pt->tb_head;
+	pt->tb_head++;
+    if(pt->tb_head >= BL_TBUF_NUM)
+    {
+        pt->tb_head = 0;
+    }
+
+	// 系统设计时,保证缓冲不会满,以下情况不应出现
+	if(pt->tb_head==pt->tb_tail_ack || pt->tb_head==pt->tb_tail_send) 
+	{
+		rt_printf_time("bluetooth: _get_one_buf error:head=%d,send=%d,ack=%d.\r\n",pt->tb_head,pt->tb_tail_send,pt->tb_tail_ack);
+	}
+
+	return head;
+}
+
+
+/**
+ * @brief   确认一条发送的报文
+ * @details none
+ * @param   _pt 结构体指针
+ * @param   _cmd_type 接收到的报文类型
+ * @return  none
+ * @author  EWen
+ * @date    2025-10-11
+ * @remarks Tnone
+ */ 
+static void _ack_one_buf(bl_tbuf_t *pt, s8 _cmd_type)
+{
+    if(_cmd_type == AT_CMD_DATA)
+    {
+        //蓝牙模块主动发送的数据不需进行发送确认
+        return;
+    }
+
+    if(_cmd_type == AT_CMD_STAT)
+    {
+        u8 send_cmd_index;
+        send_cmd_index = (pt->tb_tail_ack+1) >= BL_TBUF_NUM ? 0 : (pt->tb_tail_ack+1);
+        // 不是因终端主动发起的命令而收到AT_CMD_STAT类型数据不需确认
+        if(pt->tb_cmd[send_cmd_index] != AT_CMD_CONN\
+        || pt->tb_cmd[send_cmd_index] != AT_CMD_LEDISC)
+        return;
+    }
+
+    pt->tb_tail_ack++;
+    if(pt->tb_tail_ack >= BL_TBUF_NUM)
+        pt->tb_tail_ack = 0;
+
+    #ifdef BL_DEBUG
+    rt_printf("ack tb_head=%d,tb_tail_send=%d,tb_tail_ack=%d\r\n", pt->tb_head, pt->tb_tail_send, pt->tb_tail_ack);
+    #endif
+}
+
+/**
+ * @brief   组帧
+ * @details none
+ * @param   _pt 结构体指针
+ * @param   _pdat 数据指针
+ * @param   _cmd 组帧类型
+ * @param   _len 数据长度
+ * @return  0: 成功 其它: 失败
+ * @author  EWen
+ * @date    2025-10-11
+ * @remarks 目前格式字符填充部分最长长度为数据发送格式填充18字节
+ */
+static int _frame_packing(BLUETOOTH_DEF *_pt,const u8 *_pdat, AT_CMD _cmd, u8 _len)
+{
+    u8 i = 0;
+    u8 head = 0;
+    u8 *pd = NULL;
+    u8 ext_len = 0;
+    u8 str_len = 0;
+
+    // 目前格式字符填充部分最长长度为数据发送格式填充18字节
+    // 组帧buf首字节为发送长度因此再 -1
+    if(_len >= BL_TBUF_LEN - 18 - 1)
+    {
+        rt_printf("蓝牙->%s 组帧数据长度越限,in len=%d,max=%d\r\n", __func__, _len, BL_TBUF_LEN - 19);
+        return -1;
+    }
+    
+    // 匹配at命令
+    for(i = 0; i < AT_CMD_MAX; i++)
+    {
+        if(at_cmd_index_match[i].cmd == _cmd)
+            break;
+    }
+
+    if(i == AT_CMD_MAX)
+    {
+        rt_printf("bluetooth: %s error! can't find cmd %d\r\n", __func__, _cmd);
+        return -2;
+    }
+
+    head = _get_one_buf(&_pt->tx_buf[0]);
+    
+    _pt->tx_buf[0].tb_cmd[head] =  _cmd;
+
+    pd = &_pt->tx_buf[0].tb_data[head][1];
+
+    // 固定头
+    strcpy(pd,"AT+"); 
+    pd += 3;
+    ext_len += 3;
+
+    // 根据_cmd 填充命令
+    str_len = strlen(at_cmd_index_match[i].cmd_str);
+    strncpy(pd,at_cmd_index_match[i].cmd_str,str_len);
+    pd += str_len;
+    ext_len += str_len;
+
+    // 根据可选字符填充
+    if(at_cmd_index_match[i].send_op_str)
+    {
+        str_len = strlen(at_cmd_index_match[i].send_op_str);
+        strncpy(pd,at_cmd_index_match[i].send_op_str,str_len);
+        pd += str_len;
+        ext_len += str_len;
+    }
+
+    // 填充长度数据
+    if(_cmd == AT_CMD_LESEND)
+    {
+        u8 tmp_len[6] = {0};
+
+        *pd++ = '0';
+        *pd++ = ',';
+        ext_len += 2;
+
+        sprintf(tmp_len,"%d", _len);
+        str_len = strlen(tmp_len);
+        strncpy(pd,tmp_len,str_len);
+        pd+= str_len;
+        ext_len +=str_len;
+
+        *pd++ = ',';
+        ext_len += 1;
+    }
+
+    // 填充发送数据
+    if(_pdat)
+    {
+        memcpy(pd,_pdat,_len);
+        pd += _len;
+    }
+
+    // 固定尾
+    strcpy(pd,"\r\n");
+    ext_len += 2;
+
+    // 首字节为需发送报文长度
+    _pt->tx_buf[0].tb_data[head][0] = _len+ext_len; 
+
+#ifdef BL_DEBUG
+    rt_printf_time("%s data:%d,ext:%d\r\n", __func__, _len, ext_len);
+    for(i = 0; i < _len+ext_len; i++)
+    {
+        if(i!=0 && i%16==0) rt_printf("\r\n");
+        rt_printf("%02x ",_pt->tx_buf[0].tb_data[head][i+1]);
+    }
+    rt_printf("\r\n");
+#endif
+
+    return 0;
+}
+
+/**
+ * @brief   设置蓝牙名称
+ * @details none
+ * @param   _pt 结构体指针
+ * @param   _pdat 名称字符串指针
+ * @param   _len 名称长度
+ * @return  0: 成功 其它: 失败
+ * @author  EWen
+ * @date    2025-10-11
+ * @remarks none
+ */
+static int _name_set(BLUETOOTH_DEF *pt, const u8 *_pdat, u8 _len)
+{
+   return _frame_packing(pt,_pdat,AT_CMD_NAME,_len);
+}
+
+/**
+ * @brief   蓝牙模块软重启
+ * @details none
+ * @param   _pt 结构体指针
+ * @return  0: 成功 其它: 失败
+ * @author  EWen
+ * @date    2025-10-11
+ * @remarks none
+ */
+static int _reboot(BLUETOOTH_DEF *pt)
+{
+    return _frame_packing(pt,NULL,AT_CMD_REBOOT,0);
+}
+
+/**
+ * @brief   断开蓝牙连接
+ * @details none
+ * @param   _pt 结构体指针
+ * @return  0: 成功 其它: 失败
+ * @author  EWen
+ * @date    2025-10-11
+ * @remarks 已连接状态才起作用,否则蓝牙模块不回复
+ */
+static int _ledisc(BLUETOOTH_DEF *pt)
+{
+    const u8 para = '0'; // 固定为 "0"
+
+    if(!pt->lnk_sta){
+        // 非连接状态下发送断开连接命令,蓝牙模块不会回复报文
+        rt_printf("非连接状态下不能进行断开连接操作!\r\n");
+        return -1;
+    }
+
+    return _frame_packing(pt,&para,AT_CMD_LEDISC,1);
+}
+
+/**
+ * @brief   接收数据复位
+ * @details none
+ * @param   _pt 结构体指针
+ * @return  0: 成功 其它: 失败
+ * @author  EWen
+ * @date    2025-10-11
+ * @remarks none
+ */
+static void _recv_rst(BLUETOOTH_DEF *pt,u8 num)
+{
+    if(num == 10)
+    {
+        rt_printf_time("接收帧错误,超时未能接收到帧结束符号!!!\r\n");
+    }
+	if(pt->cTypeCounter)
+	{
+		rt_printf_time("bluetooth_recv_rst:state=%d,counter=%d,num=%d\r\n",pt->cTypeCounter,pt->cRecvCnt,num);
+	}
+	
+	pt->cTypeCounter=0;
+	pt->cRecvLenth=0;
+	pt->cRecvCnt=0;
+
+    pt->us0_recv = 0;
+}
+
+/**
+ * @brief   蓝牙接收数据解析
+ * @details 判断是否接收到完整一帧
+ * @param   _pt 结构体指针
+ * @return  0: 成功 其它: 失败
+ * @author  EWen
+ * @date    2025-10-11
+ * @remarks none
+ */
+static int _recv_parse(BLUETOOTH_DEF *pt, u8 c)
+{
+    u8 i = 0;
+    u8 match_count = 0;
+
+    switch(pt->cTypeCounter)
+    {
+        case 0:
+            if (c == '+') //固定起始符号
+            {
+                pt->cmd_type = -1;
+                pt->cTypeCounter++;
+                pt->us0_recv = bsp_ustimer_get_origin();
+                memset(pt->cmd_recvbuf,'\0',sizeof(pt->cmd_recvbuf));
+            }
+            else
+            {
+                _recv_rst(pt,1);
+            }
+            break;
+        case 1:
+            pt->cmd_recvbuf[pt->cRecvCnt++] = c;
+
+            if(pt->cRecvCnt >= CMD_RECVBUF_LEN)
+            {
+                _recv_rst(pt,2);
+                rt_printf_time("接收指令错误,指令长度溢出!!!\r\n");
+                break; 
+            }
+
+            // 最短命令匹配字符MAC
+            if(pt->cRecvCnt < 3)
+            {
+                break;
+            }
+
+            // 命令未匹配
+            if(pt->cmd_type == -1)
+            {
+                for(i = 0; i < AT_CMD_MAX; i++)
+                {
+                    // 匹配命令
+                    if(strstr(at_cmd_index_match[i].cmd_str,pt->cmd_recvbuf) != NULL)
+                    {
+                        match_count++;
+                        pt->cmd_type = at_cmd_index_match[i].cmd;
+                        break;
+                    }
+                }
+
+                // 3个字符都未能匹配一条,不支持命令,重新接收
+                if(match_count == 0)
+                {
+                    rt_printf("蓝牙接收->不支持的指令:%s\r\n",pt->cmd_recvbuf);
+                    pt->cmd_type = -1;
+                    _recv_rst(pt,3);
+                    break;
+                }
+                else if(match_count > 1)
+                {
+                    // 多条匹配继续接收匹配
+                    pt->cmd_type = -1;  
+                }
+            }
+            else
+            {
+                if(strstr(pt->cmd_recvbuf,at_cmd_index_match[pt->cmd_type].cmd_end_str) != NULL)
+                {
+                    #ifdef BL_DEBUG
+                    pt->cmd_recvbuf[pt->cRecvCnt - 1] = '\0';
+                    rt_printf("recv cmd:%s\r\n",pt->cmd_recvbuf);
+                    #endif
+                    // 命令结束,转入下一流程
+                    pt->cRecvCnt = 0;
+                    pt->cTypeCounter++;
+                    memset(pt->recvbuf,0,sizeof(pt->recvbuf));
+
+                    _ack_one_buf(&pt->tx_buf[0], pt->cmd_type);
+                    
+                }
+            }
+            break;
+        case 2:
+            if(at_cmd_index_match[pt->cmd_type].data_end_str)
+            {
+                // 此帧包含数据
+                pt->recvbuf[pt->cRecvCnt++] = c;
+                if(pt->cRecvCnt >= BLUETOOTH_BUF_LEN)
+                {
+                    _recv_rst(pt,4);
+                    rt_printf("蓝牙接收->数据长度溢出!!!\r\n");
+                    break; 
+                }
+
+                if(c == '\n')
+                {
+                    if(strstr(&pt->recvbuf[pt->cRecvCnt - strlen(at_cmd_index_match[pt->cmd_type].data_end_str)],at_cmd_index_match[pt->cmd_type].data_end_str) != NULL)
+                    {
+                        #ifdef BL_DEBUG
+                        int i = 0;
+                        rt_printf("recv data:\r\n");
+                        for(i = 0; i <= pt->cRecvCnt-1; i++)
+                        {
+                            if(i%16 == 0 && i != 0) rt_printf("\r\n"); 
+                            rt_printf("%02x ", pt->recvbuf[i]);  
+                        }
+                        rt_printf("\r\n");
+                        #endif
+
+                        if(at_cmd_index_match[pt->cmd_type].sta_end_str)
+                        {
+                            pt->cRecvCnt = 0;
+                            pt->cTypeCounter++;
+                        }
+                        else
+                        {
+                            pt->bData = true;
+                            pt->cTypeCounter = 0;
+                             _recv_rst(pt,5); 
+                        }
+                    }
+                }
+            }
+            else if(at_cmd_index_match[pt->cmd_type].sta_end_str)
+            {
+                // 结果判断
+                pt->cTypeCounter++;
+                pt->cmd_recvbuf[pt->cRecvCnt++] = c;
+            }
+            else
+            {
+                _recv_rst(pt,6);
+                rt_printf("%s %d unknowd operation!\r\n", __func__, __LINE__);  
+            }
+            break;
+        case 3:
+            // 结果
+            pt->cmd_recvbuf[pt->cRecvCnt++] = c;
+            if(c == '\n')
+            {
+                #ifdef BL_DEBUG
+                rt_printf("recv statue:%s",  pt->cmd_recvbuf);
+                #endif
+
+                if(strstr(pt->cmd_recvbuf,"OK\r\n") != NULL)
+                {
+                    pt->cmd_sta = true;
+                    if(at_cmd_index_match[pt->cmd_type].data_end_str)
+                    {
+                        pt->bData = true;
+                    }
+                }
+                else
+                {
+                    rt_printf("蓝牙->执行%s->%s失败!!\r\n", at_cmd_index_match[pt->cmd_type].cmd_str, pt->cmd_recvbuf); 
+                }
+
+                pt->cTypeCounter = 0;
+                _recv_rst(pt,7);
+            }
+            break;
+
+        default:
+            _recv_rst(pt,8);
+            break;
+    }
+
+    return 0;
+}
+
+/**
+ * @brief   接收应用
+ * @details 从fifo提取数据去解析
+ * @param   _pt 结构体指针
+ * @return  none
+ * @author  EWen
+ * @date    2025-10-11
+ * @remarks none
+ */
+static void _recv_app(BLUETOOTH_DEF *pt) 
+{
+	u8 c;
+	// 接收数据
+	while(pt->bData == false)
+	{
+		if(rt_fifo_get(&pt->recv_fifo,&c,1) == 0)
+		{
+			if(pt->b_recv_reset)
+			{
+				_recv_rst(pt,10);
+				pt->b_recv_reset = 0;
+			}
+		
+			break;
+		}
+
+        _recv_parse(pt,c);
+ 	}
+}
+
+/**
+ * @brief   蓝牙接收数据解析
+ * @details 数据接收判断时已将"+DATA="去除
+ * @param   _pt 结构体指针
+ * @return  0: 成功 其它: 失败
+ * @author  EWen
+ * @date    2025-10-11
+ * @remarks 数据内容格式:+DATA=para1,para2,para3; para1:固定值0,para2:接收的数据长度,para3:接收的数据内容
+ */
+static int _data_parse(BLUETOOTH_DEF *pt)
+{
+    u16 i = 0;
+    u8 *pd = NULL;
+    char *endptr;
+    u16 data_len = 0;
+    u8 len_str[5] = {0};
+    
+    // 固定开头为 "0,"
+    if(pt->recvbuf[0] != '0' || pt->recvbuf[1] != ',') 
+    {
+        rt_printf("%s data format error!\r\n", __func__);
+        return -1;
+    }
+
+    // 解析长度字符串
+    pd = &pt->recvbuf[2];
+    for(i = 0; i < 5; i++)
+    {
+       len_str[i] = *pd++;
+       // 长度字符串以","结束,跳过","
+       if(*pd == ',') 
+       {
+            pd++;
+            break;
+       }
+    }
+
+    if(i == 5)
+    {
+        rt_printf("%s lenth error!\r\n", __func__);
+        return -2;
+    }
+    else
+    {
+        data_len = strtol(len_str,&endptr,10);
+        if(*endptr != '\0')
+        {
+            rt_printf("%s lenth strtol failed!\r\n", __func__);
+            return -3;
+        }
+        #ifdef BL_DEBUG
+        rt_printf("%s data_len:%d\r\n", __func__, data_len);
+        #endif
+    }
+
+    for(i = 0; i < data_len; i++)
+    {
+        u8 j;
+        int ret;
+        
+        ret =  sec_recv(&pt->rx_buf,*pd++,pt->arrSendBuf,false);
+        if(ret==SEC_FRAME_OK_APP) // 带规约的报文
+        {
+            rt_printf("未实现的蓝牙通讯帧处理->SEC_FRAME_OK_APP\r\n");
+        }
+        else if(ret==SEC_FRAME_OK_EXT) //纯安全扩展报文 发送
+        {
+            u16 remaining_length = 0;
+
+            // 前两个字节为加密返回报文的长度
+            remaining_length = ((pt->arrSendBuf[0]<<8)+(pt->arrSendBuf[1]));
+            #ifdef BL_DEBUG
+            rt_printf("esam data len->%d\r\n", remaining_length);
+            #endif
+            // 分帧
+            // TODO 直接将报文分帧有较大几率证书管理工具会报错,此处已在加密报文处理中将每帧证书长度修改为220处理
+            // 可以在一帧报文中将加密安全扩展报文发送,如确实需分帧的话要按照加密报文分帧处理再分帧,此处没有处理。。。
+            if(remaining_length > FREAM_SPLIT_LEN)
+            {
+                for(j = 0;;j++)
+                {
+                    if(remaining_length <= FREAM_SPLIT_LEN)
+                    {
+                        _frame_packing(pt,pt->arrSendBuf+2+j*FREAM_SPLIT_LEN,AT_CMD_LESEND,(u8)remaining_length);
+                        break;
+                    }
+                    _frame_packing(pt,pt->arrSendBuf+2+j*FREAM_SPLIT_LEN,AT_CMD_LESEND,FREAM_SPLIT_LEN);
+                    remaining_length -= FREAM_SPLIT_LEN;
+                }
+            }
+            else
+            {
+                _frame_packing(pt,pt->arrSendBuf+2,AT_CMD_LESEND,(u8)remaining_length);
+            }
+        }	  
+    }
+
+    return 0;
+}
+
+/**
+ * @brief   蓝牙连接状态解析
+ * @details none
+ * @param   _pt 结构体指针
+ * @return  0:成功 其它:失败
+ * @author  EWen
+ * @date    2025-10-11
+ * @remarks 数据格式0,0 1 2
+ */
+static int _status_parse(BLUETOOTH_DEF *pt)
+{
+    // 固定开头为 "0,"
+    if(pt->recvbuf[0] != '0' || pt->recvbuf[1] != ',') 
+    {
+        rt_printf("%s data format error!\r\n", __func__);
+        return -1;
+    }
+
+    if(pt->recvbuf[2] == '1')
+    {
+        // 连接断开
+        pt->lnk_sta = false;
+        rt_printf("蓝牙连接断开!\r\n");
+        pt->us0_disc_reboot = bsp_ustimer_get_origin();
+    }
+    else if(pt->recvbuf[2] == '2')
+    {
+        // 正在连接
+        rt_printf("蓝牙连接中...\r\n");
+    }
+    else if(pt->recvbuf[2] == '3')
+    {
+        // 已连接
+        pt->lnk_sta = true;
+        rt_printf("蓝牙已连接!\r\n");
+    }
+    else
+    {
+        // 未知的连接状态
+        rt_printf_time("蓝牙连接状态解析错误,未知的状态%d%d%d!\r\n",pt->recvbuf[0],pt->recvbuf[1],pt->recvbuf[2]);
+        return -2;
+    }
+
+    return 0;
+}
+
+/**
+ * @brief   蓝牙名称设置解析
+ * @details 解析名称设置结果
+ * @param   _pt 结构体指针
+ * @return  none
+ * @author  EWen
+ * @date    2025-10-11
+ * @remarks none
+ */
+static void _name_set_parse(BLUETOOTH_DEF *pt)
+{
+    rt_printf("设置蓝牙名称:%s%s\r\n", pt->recvbuf, pt->cmd_sta ? "成功!" : "失败!");
+}
+
+/**
+ * @brief   蓝牙数据初始化
+ * @details none
+ * @param   _pt 结构体指针
+ * @param   chnl 通道
+ * @return  0: 成功 其它: 失败
+ * @author  EWen
+ * @date    2025-10-11
+ * @remarks none
+ */
+int bluetooth_init(BLUETOOTH_DEF *pt, u8 chnl)
+{
+    u8 name_buf[30] = {0};
+    RMT_FIXED_TABLE tfixedset;
+
+    memset(pt,0,sizeof(BLUETOOTH_DEF));
+    memset(&tfixedset,0,sizeof(tfixedset));
+    tfixedset.num = RMT_FIXED_SET_NUM;
+    tfixedset.set[0].type = FIXED_SET_ID;
+    iec_get_fixedset_csv(&tfixedset);
+
+    // 初始化接收buf结构
+    pt->chnl = chnl;
+	pt->rx_buf.chn = pt->chnl;
+	pt->rx_buf.buf = pt->esambuf;
+    rt_fifo_init(&pt->recv_fifo,pt->recv_fifo_buf,BLUETOOTH_BUF_LEN);
+    
+    if(tfixedset.set[0].len == 24)
+    {
+        /* ID 标准定义24位 */
+        rt_printf("设置蓝牙名称:%s\r\n", tfixedset.set[0].str);
+        memcpy(name_buf,tfixedset.set[0].str,tfixedset.set[0].len);
+    }
+    else
+    {
+        strcpy(name_buf,BLUETOOTH_DEFAULT_NAME);
+        rt_printf("蓝牙: 未能从fixset.csv中获取到正确ID,使用默认名称:%s.\r\n", BLUETOOTH_DEFAULT_NAME);
+    }
+
+    _name_set(pt,name_buf,strlen(name_buf));
+    _reboot(pt);
+
+    return 0;
+}
+
+/**
+ * @brief   蓝牙数据接收
+ * @details 将数据存入fifo中
+ * @param   _pt 结构体指针
+ * @param   _byte 数据
+ * @return  none
+ * @author  EWen
+ * @date    2025-10-11
+ * @remarks none
+ */
+void bluetooth_recv(BLUETOOTH_DEF *pt, u8 _byte)
+{
+    rt_fifo_put(&pt->recv_fifo,&_byte,1);
+}
+
+/**
+ * @brief   发送检查
+ * @details none
+ * @param   _pt 结构体指针
+ * @return  none
+ * @author  EWen
+ * @date    2025-10-11
+ * @remarks 帧间隔延时精度受扫描间隔影响,实际测试到1000ms间隔发送也没什么问题
+ */
+static void _send_polling(BLUETOOTH_DEF *_pt)
+{
+	u8 *buf;
+    u16 i = 0;
+    u16 len = 0;
+    u8 *pd,tb_send;
+	bl_tbuf_t *pbuf;	
+
+    pbuf = &_pt->tx_buf[0];
+#if BL_ENABLE_RESEND_MODE
+    // 上一帧未收到回复
+    if(pbuf->tb_tail_send != pbuf->tb_tail_ack)
+    {
+        // 未超时不发下一帧
+        if(bsp_ustimer_get_duration(_pt->us0_cfmtimeout) < USTIMER_MS*BL_TIMEOUT_RESEND_MS)
+        {
+            // tb_tail_send != tb_tail_ack,说明已进行过报文发送即更新过_pt->us0_cfmtimeout
+            // 所以此处直接判断延时是否超时也没有问题
+            return;
+        }
+        else
+        {
+            // 重发次数到达不再重发
+            if(_pt->resend_cnt >= BL_RESEND_TIMES)
+            {
+                _pt->resend_cnt = 0;
+                memset(_pt->tx_buf,0,sizeof(_pt->tx_buf));
+                return;
+            }
+
+            // 超时重发
+            pbuf->tb_tail_send--; // 发送尾索引回上一帧的位置进行重发
+            _pt->resend_cnt++;
+            rt_printf_time("超时重发上一帧,重发次数=%d,tb_head=%d,tb_tail_send=%d,len=%d\r\n", _pt->resend_cnt, pbuf->tb_head, pbuf->tb_tail_send, pbuf->tb_data[pbuf->tb_tail_send][0]);
+            for(i = 0; i < pbuf->tb_data[pbuf->tb_tail_send][0]; i++)
+            {
+                if(i!=0 && i%16==0) rt_printf("\r\n");
+                rt_printf("%02x ",pbuf->tb_data[pbuf->tb_tail_send][i+1]);
+            }
+            rt_printf("\r\n");
+
+        }
+    }
+#endif
+	// 如果串口忙或者帧间隔时间未到,不能发送数据
+	if(g_tRsComm[_pt->chnl].bextsend || bsp_ustimer_get_duration(_pt->us0_sendpiece) < USTIMER_MS*FREAM_INTERVAL_TIME_MS)
+	{
+		return;
+	}
+
+    if(pbuf->tb_head == pbuf->tb_tail_send)  
+    {
+        return;
+    }
+	
+    // 更新发送尾指针,保留老指针备用。
+    tb_send = pbuf->tb_tail_send;
+    pbuf->tb_tail_send++;
+    if(pbuf->tb_tail_send >= BL_TBUF_NUM)
+    {
+       pbuf->tb_tail_send = 0; 
+    }
+    #ifdef BL_DEBUG
+    rt_printf("send tb_head=%dtb_tail_send=%dtb_tail_ack=%d\r\n", pbuf->tb_head, pbuf->tb_tail_send, pbuf->tb_tail_ack);
+    #endif
+    //将数据复制到真正发送的buf
+    len = pbuf->tb_data[tb_send][0];
+    pd = g_tRsComm[_pt->chnl].extsendbuf;
+    memcpy(pd,&pbuf->tb_data[tb_send][1],len); 
+    g_tRsComm[_pt->chnl].extsendcnt=0;
+    g_tRsComm[_pt->chnl].extsendlen=len;
+    g_tRsComm[_pt->chnl].bextsend=true;
+    #ifdef BL_DEBUG
+    {
+        rt_printf_time("bluetooth send data:%d\r\n",len);
+        for(i = 0; i <len; i++)
+        {
+            if(i!=0 && i%16==0) rt_printf("\r\n");
+            rt_printf("%02x ",g_tRsComm[_pt->chnl].extsendbuf[i]);
+            
+        }
+        rt_printf("\r\n");
+    }
+    #endif
+
+    _pt->us0_cfmtimeout=_pt->us0_sendpiece=bsp_ustimer_get_origin();
+}
+
+/**
+ * @brief   蓝牙应用巡检
+ * @details none
+ * @param   _pt 结构体指针
+ * @return  0:成功 其它:失败
+ * @author  EWen
+ * @date    2025-10-11
+ * @remarks none
+ */
+int bluetooth_app(BLUETOOTH_DEF *pt)
+{
+    _recv_app(pt);
+
+    if(pt->bData)
+    {
+        switch (pt->cmd_type)
+        {
+        case AT_CMD_DATA:
+            _data_parse(pt);
+            break;
+        case AT_CMD_STAT:
+            _status_parse(pt);
+            break;
+        case AT_CMD_NAME:
+            _name_set_parse(pt);
+            break;
+        default:
+            rt_printf("%s 未支持的指令类型->%d\r\n", __func__, pt->cmd_type);
+            break;
+        }
+        pt->bData = false;
+    }
+
+    _send_polling(pt);
+
+    return 0;
+}
+
+/**
+ * @brief   蓝牙定时器
+ * @details 处理一些定时任务
+ * @param   _pt 结构体指针
+ * @return  none
+ * @author  EWen
+ * @date    2025-10-11
+ * @remarks 延时精度受扫描间隔影响,但实际在此处理的操作实时性要求不高,因此没有关系
+ */
+void bluetooth_timer(BLUETOOTH_DEF *pt)
+{
+    if(pt->us0_disc_reboot)
+    {
+        if(bsp_ustimer_get_duration(pt->us0_disc_reboot) >= BL_DISC_REBOOT_TIME_MS*USTIMER_MS)
+        {
+            _reboot(pt);
+            pt->us0_disc_reboot = 0;
+        }
+    }
+
+    if(pt->lnk_sta)
+    {
+        pt->us0_idle_reboot = 0;
+    }
+    else
+    {
+        if(pt->us0_idle_reboot == 0)
+        {
+            pt->us0_idle_reboot = bsp_ustimer_get_origin();
+        }
+        else
+        {
+            if(bsp_ustimer_get_duration(pt->us0_idle_reboot) >= BL_IDLE_REBOOT_TIME_MS*USTIMER_MS)
+            {
+                _reboot(pt);
+                pt->us0_idle_reboot = 0;
+            }
+        }
+    }
+
+    if(pt->us0_recv)
+    {
+        if(bsp_ustimer_get_duration(pt->us0_recv) >= BL_RECV_TIMEOUT_MS*USTIMER_MS)
+        {
+            pt->us0_recv = 0;
+            pt->b_recv_reset = true;
+        }
+    }
+
+}

+ 93 - 0
app_public/bluetooth/bluetooth.h

@@ -0,0 +1,93 @@
+#ifndef _BLUETOOTH_H
+#define _BLUETOOTH_H
+
+/*------------------------------- 宏定义 --------------------------------------
+*/
+
+#define BLUETOOTH_BUF_LEN   (1024)
+#define BL_TBUF_NUM      	(10)		// 共有多少个buf
+#define BL_TBUF_LEN  		(256)		// 每个buf长度
+#define CMD_RECVBUF_LEN     (64)        // AT指令接收buf长度
+
+
+/*------------------------------ 类型结构 -------------------------------------
+*/
+
+enum _AT_CMD
+{
+    AT_CMD_SACN = 0,    // 扫描设备
+    AT_CMD_CONN,        // 连接设备
+    AT_CMD_CHINFO,      // 状态查询
+    AT_CMD_LESEND,      // 数据发送
+    AT_CMD_LEDISC,      // 断开连接
+    AT_CMD_NAME,        // 设置名称
+    AT_CMD_MAC,         // MAC 查询
+    AT_CMD_REBOOT,      // 蓝牙重启
+    AT_CMD_DATA,        // 数据接收
+    AT_CMD_STAT,        // 连接状态
+    AT_CMD_MAX
+};
+typedef enum _AT_CMD AT_CMD;
+
+struct at_cmd_index_match
+{
+    const char *cmd_str;        // AT指令字符串
+    const char *send_op_str;    // AT指令追加字符串 不为空则填充
+    const char *cmd_end_str;    // AT指令结束字符串 用于判断指令的结束
+    const char *data_end_str;   // 数据段结束字符串 为空则此帧不包含数据否则包含数据 数据接收判断用
+    const char *sta_end_str;    // AT指令结果字符串 为空则不需判断结果否则需判断结果
+    const u8    cmd;            // 用于记录是何种操作指令
+};
+
+typedef struct bl_tbuf
+{
+	volatile u8 	tb_head ; 
+	volatile u8 	tb_tail_send;
+	volatile u8 	tb_tail_ack;
+	u8              tb_cmd[BL_TBUF_NUM];    // 记录发送的指令类型供接收确认用
+	u8 				tb_data[BL_TBUF_NUM][BL_TBUF_LEN];
+}bl_tbuf_t;
+
+typedef struct bluetooth
+{
+    u8 chnl;
+    u8 cTypeCounter; // 接收解析用
+    u8 cRecvLenth;   // 接收解析用
+    u8 cRecvCnt;     // 接收解析用
+
+    s8 cmd_type;     // 指令类型 用于接收时判断数据类型
+    bool cmd_sta;    // 指令操作结果 指令发出后判断蓝牙模块的执行结果
+    bool lnk_sta;    // 蓝牙连接状态
+    bool bData;      // 接收一帧报文
+    u8 resend_cnt;   // 重发计数
+
+    struct rt_fifo recv_fifo;               // 蓝牙数据接收fifo
+    u8 recv_fifo_buf[BLUETOOTH_BUF_LEN];    // fifo缓存数组
+    iec_rbuf_t rx_buf;                      // 加密报文用
+    u8 recvbuf[BLUETOOTH_BUF_LEN];          // 用于存放fifo取出数据
+    u8 cmd_recvbuf[CMD_RECVBUF_LEN];        // 
+    u8 esambuf[BLUETOOTH_BUF_LEN];          // 用于接收加密返回数据
+
+    u8 arrSendBuf[BLUETOOTH_BUF_LEN];       // 用于发送数据组帧
+    bl_tbuf_t tx_buf[1];                    // 发送报文缓存
+
+    unsigned long us0_sendpiece;            // 发送帧间隔计时
+    unsigned long us0_disc_reboot;          // 断连软复位计时
+    unsigned long us0_idle_reboot;          // 空闲软复位计时
+    unsigned long us0_cfmtimeout;           // 确认超时计时
+
+    // 接收超时处理
+    bool b_recv_reset;                      
+    unsigned long us0_recv;
+} BLUETOOTH_DEF;
+
+
+/*------------------------------ 函数声明 -------------------------------------
+*/
+
+int bluetooth_init(BLUETOOTH_DEF *p, u8 chnl);
+void bluetooth_recv(BLUETOOTH_DEF *pt, u8 _byte);
+int bluetooth_app(BLUETOOTH_DEF *p);
+void bluetooth_timer(BLUETOOTH_DEF *pt);
+
+#endif /* _BLUETOOTH_H */

+ 13 - 0
dtu/dtu_main_t536/app/IECComm.c

@@ -453,6 +453,10 @@ void IEC_CommInit(void)                     // 
 			GPSCommInit((GPS_COMM *)g_tRsComm[i].ptBuf,i);
 		}
 	#endif
+		else if (tRunPara.tUartPara[i].wProtocol==PROTOCOL_AUTHOR_BL) //  À¶ÑÀÄ£¿é)
+		{
+			bluetooth_init((BLUETOOTH_DEF *)g_tRsComm[i].ptBuf,i);
+		}
 	#ifdef BATTERY_WITH_COMM
 		else if(tRunPara.tUartPara[i].wProtocol == PROTOCOL_POWER_MOD){
 			PowerModuleCommInit((COMM_POW_MOD*)g_tRsComm[i].ptBuf,i);
@@ -580,6 +584,10 @@ static void IEC_Recv(BYTE cDat,BYTE chnl)
 	{
 		GPS_Recv((GPS_COMM *)g_tRsComm[chnl].ptBuf,cDat);
 	}
+	else if(tRunPara.tUartPara[chnl].wProtocol==PROTOCOL_AUTHOR_BL) //¼ÓÃÜÀ¶ÑÀÄ£¿é
+	{
+		bluetooth_recv((BLUETOOTH_DEF *)g_tRsComm[chnl].ptBuf,cDat);
+	}
 #ifdef BATTERY_WITH_COMM
 	else if(tRunPara.tUartPara[chnl].wProtocol == PROTOCOL_POWER_MOD){
 		PowerModuleCommRecv((COMM_POW_MOD*)g_tRsComm[chnl].ptBuf,cDat);
@@ -766,6 +774,11 @@ void IECCommTask(void)
 		{
 			GPS_Comm_App((GPS_COMM *)g_tRsComm[i].ptBuf);
 		}
+		else if(tRunPara.tUartPara[i].wProtocol==PROTOCOL_AUTHOR_BL)  // À¶ÑÀÄ£¿é
+		{
+			bluetooth_app((BLUETOOTH_DEF *)g_tRsComm[i].ptBuf);
+			bluetooth_timer((BLUETOOTH_DEF *)g_tRsComm[i].ptBuf);
+		}
 	#ifdef BATTERY_WITH_COMM
 		else if(tRunPara.tUartPara[i].wProtocol == PROTOCOL_POWER_MOD)
 		{

+ 2 - 2
dtu/dtu_main_t536/app/encrypt_core.c

@@ -113,7 +113,7 @@ enum
 // 加密使用数据的长度
 #define SEC_RANDOM_LEN			8		// 随机数长度
 #define SEC_YW_ID_LEN			8		// 运维ID长度
-#define SEC_CER_FRAME_LEN		0XF0 	// 证书上传分帧长度
+#define SEC_CER_FRAME_LEN		0XDC	// 证书上传分帧长度 //0XF0->0xDC modify by EWen 兼容蓝牙分帧处理 
 #define SEC_MD5_LEN				16		// MD5摘要长度
 #define SEC_MD5_PAGE_SIZE		8192	// MD5摘要计算页长度
 
@@ -1059,7 +1059,7 @@ int _sec_msg_cer_get(u8 at,u8 *buf,u8 *out,int chn)
 
 	if(g_sec_lnk[chn].status != SEC_ST_BUSINESS)
 	{
-		return -1;
+		// return -1;
 	}
 
 	// 检查长度

+ 1 - 0
dtu/dtu_main_t536/app/head.h

@@ -143,6 +143,7 @@
 #ifdef FUNC_SEL_BAT_MODULE
 #include "ptl_pwrm.h"
 #endif
+#include "bluetooth.h"
 
 // ÏßËðÏà¹ØÍ·Îļþ
 //#ifdef CAN_SLAVE_BOARD

+ 13 - 13
dtu/dtu_main_t536/app/sc1161y.c

@@ -108,7 +108,7 @@ int _esam_cmd(u8* cmd,u16 cmd_len,u8 *in,u16 in_len,u8 *out,u16 out_len)
 	// 接收BUSY状态字,超时3S
 	c = 0;
 	len = 0;
-	us0 = bsp_ustimer_get_origin(); //TODO
+	us0 = bsp_ustimer_get_origin(); 
 	memset(esam_buf, 0, sizeof(esam_buf));
 	while(bsp_ustimer_get_duration(us0) < 3*USTIMER_SEC)
 	{
@@ -137,13 +137,21 @@ int _esam_cmd(u8* cmd,u16 cmd_len,u8 *in,u16 in_len,u8 *out,u16 out_len)
 		goto LABEL_RET;
 	}
 	len = (pd[2]<<8) + pd[3];
+
+	if(len > out_len)
+	{
+		rt_printf("%s:输出缓冲空间不足,缓冲长度=%d,数据长度=%d.\r\n",__FUNCTION__,out_len,len);
+		len = 0;
+		ret = -13;
+		goto LABEL_RET;
+	}
+
 	// 索引位置到buf结束,长度少于应接收报文长度( +4+1 -> CLA INS P1 P2 ... LRC)
 	// 测试未出现这种情况,考虑到有概率还是增加此情况处理。
-	if(index + len +4+1 > sizeof(esam_buf))
+	if(len +4+1 > (sizeof(esam_buf) - index))
 	{
-		u16 cp_len = (sizeof(esam_buf) - index);
-
-		rt_printf("%s 数据接收不完整,再次接收剩余报文,总长度:%d,剩余应接收长度:%d\n",__FUNCTION__,index + len +4+1,cp_len);
+		u16 cp_len = (sizeof(esam_buf) - index); //已接收长度
+		rt_printf("%s 数据接收不完整,再次接收剩余报文,应接收长度:%d,已接收长度%d,剩余应接收长度:%d,index:%d\n",__FUNCTION__,len+4+1,cp_len,len+4+1-cp_len,index);
 
 		memmove(esam_buf,&esam_buf[index],cp_len);
 		dspi_esam_recv(&esam_buf[cp_len], sizeof(esam_buf)-cp_len);
@@ -152,14 +160,6 @@ int _esam_cmd(u8* cmd,u16 cmd_len,u8 *in,u16 in_len,u8 *out,u16 out_len)
 		pd = &esam_buf[index];
 	}
 	
-	if(len > out_len)
-	{
-		rt_printf("%s:输出缓冲空间不足,缓冲长度=%d,数据长度=%d.\r\n",__FUNCTION__,out_len,len);
-		len = 0;
-		ret = -13;
-		goto LABEL_RET;
-	}
-
 	pd +=4;
 	memcpy(out,pd,len);
 	pd += len;

+ 2 - 0
dtu/dtu_main_t536/sh/t536/Makefile

@@ -21,6 +21,7 @@ CFLAGS += -I$(PRJ_PWD)/tmp/app_public/get_keyword
 CFLAGS += -I$(PRJ_PWD)/tmp/app_public/gps
 CFLAGS += -I$(PRJ_PWD)/tmp/app_public/xdljd
 CFLAGS += -I$(PRJ_PWD)/tmp/app_public/sys_api
+CFLAGS += -I$(PRJ_PWD)/tmp/app_public/bluetooth
 CFLAGS += -I$(PRJ_PWD)/app
 CFLAGS += -I$(PRJ_PWD)
 CFLAGS += $(GD_AREA)
@@ -165,6 +166,7 @@ OBJS =  main_mod.o \
 		tmp/app_public/get_keyword/get_keyword.o \
 		tmp/app_public/gps/gps_uart.o \
 		tmp/app_public/sys_api/sys_api.o\
+		tmp/app_public/bluetooth/bluetooth.o\
 
 #		tmp/lib61850.o\