BLE_TYQ_BJQ_CH32V303/bsp/src/bsp_bt.c

592 lines
17 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.

/*
* @Author: mbw
* @Date: 2024-12-03 10:31:45
* @LastEditors: mbw && 1600520629@qq.com
* @LastEditTime: 2025-05-09 16:48:18
* @FilePath: \ble_bjq_ch303rct6_ml307\bsp\src\bsp_bt.c
* @Description:
*
* Copyright (c) 2025 by ${git_name_email}, All Rights Reserved.
*/
#include "bsp_bt.h"
#include "bsp_ml307.h"
#include "bsp_flash.h"
#include "rtdef.h"
#include "lwrb.h"
#include "finsh.h"
#include "user_sys.h"
#define LOG_TAG "bsp_bt"
#define LOG_LVL LOG_LVL_DBG
#include <ulog.h>
#define BT_UART "uart5"
static rt_device_t rt_bt_device;
static struct rt_semaphore bt_rx_sem; //
struct rt_semaphore bt_ctr_sem; // 控制阀门信号量
struct rt_semaphore bt_reg_sem; // 注册阀门信号量
struct rt_semaphore bt_rem_sem; // 移除阀门信号量
struct rt_semaphore bt_rep_sem; // 更换阀门信号量
#define BT_THREAD_TIMESLICE (20)
#define BT_THREAD_PRIORITY (10)
#define BT_THREAD_STACK_SIZE (2048)
ALIGN (RT_ALIGN_SIZE)
static rt_uint8_t bt_thread_stack[BT_THREAD_STACK_SIZE] = {0};
static struct rt_thread bt_thread = {0};
lwrb_t bt_lwrb_rx;
static char bt_rx_buffer[1024] = {0};
BTFrameData bt_frame = {0};
valve_data valve[MAX_VALVE_NUM] = {0};
rt_uint8_t to_sever_send_bt_connect_flag = 0;
rt_size_t BSP_Bt_Send_Data (uint8_t *data, size_t size)
{
return rt_device_write (rt_bt_device, 0, data, size);
}
rt_size_t BSP_Bt_Recv_Data (uint8_t *data, size_t size)
{
return lwrb_read (&bt_lwrb_rx, data, size);
}
static rt_err_t bt_getchar (char *ch, rt_int32_t timeout)
{
rt_err_t result = RT_EOK;
while (rt_device_read (rt_bt_device, 0, ch, 1) == 0)
{
result = rt_sem_take (&bt_rx_sem, rt_tick_from_millisecond (timeout));
if (result != RT_EOK)
{
return result;
}
}
return RT_EOK;
}
static int bt_recv_readline (void)
{
rt_size_t read_len = 0;
char ch = 0, last_ch = 0;
rt_bool_t is_full = RT_FALSE;
while (1)
{
bt_getchar (&ch, RT_WAITING_FOREVER);
if (read_len < lwrb_get_free (&bt_lwrb_rx))
{
lwrb_write (&bt_lwrb_rx, &ch, 1);
}
else
{
is_full = RT_TRUE;
}
if (ch == '\n' && last_ch == '\r')
{
if (is_full)
{
LOG_E ("read line failed. The line data length is out of buffer size(%d)!", lwrb_get_free (&bt_lwrb_rx));
return -RT_EFULL;
}
break;
}
last_ch = ch;
}
return lwrb_get_full (&bt_lwrb_rx);
}
/*发送数据帧处理*/
rt_uint8_t BT_GenerateRawFrame (BTFrameData *pRawData, const rt_uint8_t *p_src, rt_uint8_t src_len)
{
pRawData->len = src_len + 4;
rt_memset (pRawData->buf, 0, sizeof (pRawData->buf));
pRawData->buf[0] = BT_FRAME_HEAD_DATA;
pRawData->buf[1] = src_len;
rt_memmove (&pRawData->buf[2], p_src, src_len);
// 从帧起始符开始到校验码之前所有字节的和的模256
// 即各字节不计超过255的溢出值的二进制算术和。
pRawData->buf[pRawData->len - 2] = XOR_CheckSum (&pRawData->buf[0], pRawData->len - 2);
pRawData->buf[pRawData->len - 1] = BT_FRAME_TAIL_DATA;
LOG_HEX ("BTFrameData", 16, &pRawData->buf[0], pRawData->len);
return RT_EOK;
}
/*用于控制阀门的状态
* id: 1-8
* mac_addr: 6字节
* status: 0-关闭 1-打开
*/
int BSP_Bt_Valve_Ctr (rt_uint8_t id, rt_uint8_t *mac_addr, WireLessState status)
{
rt_uint8_t ret = 0;
BtData_t *ptr = (BtData_t *)rt_malloc (sizeof (BtData_t) + 8);
ptr->cmd = kValveCmdCtr;
ptr->buf[0] = id;
rt_memcpy (&ptr->buf[1], mac_addr, 6);
ptr->buf[7] = status;
BT_GenerateRawFrame (&bt_frame, (rt_uint8_t *)ptr, 9);
rt_free (ptr);
ret = BSP_Bt_Send_Data ((rt_uint8_t *)&bt_frame.buf[0], bt_frame.len);
if (ret == bt_frame.len)
{
return RT_EOK;
}
return RT_ERROR;
}
/*注册阀门信息*/
int BSP_Bt_Register_Valve (rt_uint8_t id, rt_uint8_t *mac_addr)
{
rt_uint8_t ret = 0;
BtData_t *ptr = (BtData_t *)rt_malloc (sizeof (BtData_t) + 7);
ptr->cmd = kValveCmdReg;
ptr->buf[0] = id;
rt_memcpy (&ptr->buf[1], mac_addr, 6);
BT_GenerateRawFrame (&bt_frame, (rt_uint8_t *)ptr, 8);
rt_free (ptr);
ret = BSP_Bt_Send_Data ((rt_uint8_t *)&bt_frame.buf[0], bt_frame.len);
if (ret == bt_frame.len)
{
return RT_EOK;
}
return RT_ERROR;
}
/*移除阀门信息*/
int BSP_Bt_Remove_Valve (rt_uint8_t id, rt_uint8_t *mac_addr)
{
rt_uint8_t ret = 0;
BtData_t *ptr = (BtData_t *)rt_malloc (sizeof (BtData_t) + 7);
ptr->cmd = kValveCmdRem;
ptr->buf[0] = id;
rt_memcpy (&ptr->buf[1], mac_addr, 6);
BT_GenerateRawFrame (&bt_frame, (rt_uint8_t *)ptr, 8);
rt_free (ptr);
ret = BSP_Bt_Send_Data ((rt_uint8_t *)&bt_frame.buf[0], bt_frame.len);
if (ret == bt_frame.len)
{
return RT_EOK;
}
return RT_ERROR;
}
/*移除所有阀门信息*/
int BSP_Bt_Remove_All_Valve (void)
{
rt_uint8_t ret = 0;
BtData_t *ptr = (BtData_t *)rt_malloc (sizeof (BtData_t) + 7);
ptr->cmd = kValveCmdRemAll;
ptr->buf[0] = 0;
BT_GenerateRawFrame (&bt_frame, (rt_uint8_t *)ptr, 2);
rt_free (ptr);
ret = BSP_Bt_Send_Data ((rt_uint8_t *)&bt_frame.buf[0], bt_frame.len);
if (ret == bt_frame.len)
{
return RT_EOK;
}
return RT_ERROR;
}
/*更换阀门信息*/
int BSP_Bt_Replace_Valve (rt_uint8_t id, rt_uint8_t *mac_addr, rt_uint8_t *new_mac_addr)
{
rt_uint8_t ret = 0;
BtData_t *ptr = (BtData_t *)rt_malloc (sizeof (BtData_t) + 14);
ptr->cmd = kValveCmdRep;
ptr->buf[0] = id;
rt_memcpy (&ptr->buf[1], mac_addr, 6);
rt_memcpy (&ptr->buf[7], new_mac_addr, 6);
BT_GenerateRawFrame (&bt_frame, (rt_uint8_t *)ptr, (sizeof (BtData_t) + 14));
rt_free (ptr);
ret = BSP_Bt_Send_Data ((rt_uint8_t *)&bt_frame.buf[0], bt_frame.len);
if (ret == bt_frame.len)
{
return RT_EOK;
}
return RT_ERROR;
}
int Bt_Valve_Handler (ValveCmdType type, rt_uint8_t id, rt_uint8_t *data)
{
int ret = RT_EOK;
switch (type)
{
case kValveCmdCtr: // 阀门控制
ret = BSP_Bt_Valve_Ctr (id, &data[0], WirelessValveClose); // 关阀门
break;
case kValveCmdReg: // 阀门注册
ret = BSP_Bt_Register_Valve (id, &data[0]);
break;
case kValveCmdRem: // 阀门移除
ret = BSP_Bt_Remove_Valve (id, &data[0]);
break;
case kValveCmdRep: // 阀门更换
ret = BSP_Bt_Replace_Valve (id, &data[0], &data[6]);
break;
case kValveCmdRemAll: // 阀门更换
ret = BSP_Bt_Remove_All_Valve();
break;
default:
ret = -RT_ERROR;
LOG_E ("unknown valve command type");
break;
}
return ret;
}
int BSP_Bt_Process (uint8_t *data, uint16_t len)
{
int ret = 0;
uint16_t index = 0;
rt_uint8_t end_index = 0;
uint8_t data_buf[256] = {0};
// 解析接收到的数据帧先寻找AA开头然后再找AA下一个字节其代表了数据长度然后找到代表长度的值的长度的下一位其为校验码校验码后为结束码0x55
// 如果数据正确,则提取数据,不正确,则不处理
LOG_HEX ("BT_RX_DATA", 16, data, len);
LOG_D ("len = %d", len);
if (len < 4)
{ // 至少需要 4 个字节:起始码、长度、校验码、结束码
LOG_E ("长度不对 [1]");
;
return 1;
}
while (index < len && data[index] != 0xAA) // 寻找起始码 0xAA
{
index++;
}
for (size_t i = 0; i < (len - 3); i++) // 发现了一种情况会出现两个AA用这种方法排除一下
{
if (data[index + i + 1] == 0XAA)
{
index++;
}
else
{
break;
}
}
while (end_index < len && data[end_index] != 0x55) // 寻找起始码 0xAA
{
end_index++;
}
uint16_t datalength = data[index + 1]; // 读取数据长度
LOG_D ("datalength = %d", datalength);
uint8_t rx_sum = data[index + 2 + datalength]; // 读取校验码
uint8_t calculated_sum = XOR_CheckSum (&data[index], datalength + 2); // 计算校验码
if (rx_sum != calculated_sum)
{
LOG_E ("校验和不对 rx_sum[%02X] != calculated_sum[%02X]", rx_sum, calculated_sum);
LOG_HEX ("bt_rx_data:", 16, data, len);
lwrb_reset (&bt_lwrb_rx);
return 4;
}
if (data[index + 1 + datalength + 2] != data[end_index]) // 检查结束码
{
LOG_E ("结束码位置错误");
LOG_HEX ("bt_rx_data:", 16, data, len);
lwrb_reset (&bt_lwrb_rx);
return 5;
}
rt_uint8_t fram_len = datalength + 4;
// 当程序走到这里时,就说明接收到了正确的数据帧,开始解析响应
rt_memcpy (data_buf, &data[index], fram_len);
switch (data[index + 2])
{
case kValveEventCtr:
LOG_D ("valve control event");
if (data_buf[fram_len - 3] == WirelessValveClose) // 关闭成功
{
rt_sem_release (&bt_ctr_sem);
}
break;
case kValveEventReg:
if (data_buf[fram_len - 3] == RT_TRUE) // 注册成功)
{
LOG_I ("接收到阀门注册响应:");
LOG_HEX ("bt_rx_data:", 16, data_buf, fram_len);
rt_sem_release (&bt_reg_sem);
}
break;
case kValveEventRem:
if (data_buf[fram_len - 3] == RT_TRUE) // 移除成功
{
LOG_D ("移除阀门响应成功");
rt_sem_release (&bt_rem_sem);
}
break;
case kValveEventRep:
if (data_buf[fram_len - 3] == RT_TRUE) // 更换成功
{
LOG_D ("阀门更换响应成功");
rt_sem_release (&bt_rep_sem);
}
else
{
LOG_E ("阀门更换失败");
}
break;
case kValveEventRemAll:
LOG_I ("接收到移除所有阀门信息回应");
LOG_HEX ("bt_rx_data:", 16, data_buf, fram_len);
if (data_buf[fram_len - 3] == RT_TRUE) // 移除成功
{
LOG_D ("移除阀门响应成功");
rt_sem_release (&bt_rem_sem);
}
break;
case kValveEventStatus:
LOG_I ("接收到阀门心跳数据:");
LOG_HEX ("bt_rx_data:", 16, data_buf, fram_len);
// TODO:添加阀门数据处理函数
rt_memcpy (&valve[data_buf[3] - 1], &data_buf[3], sizeof (struct valve_t));
LOG_HEX ("valve_data:", 16, (rt_uint8_t *)&valve[data_buf[3] - 1], sizeof (struct valve_t));
if (!to_sever_send_bt_connect_flag)
{
while (!power_on_send_flag)
{
rt_thread_mdelay (100);
}
to_sever_send_bt_connect_flag = 1;
Ml307_Send_Event (kMl307ValveConnectEvent);
}
break;
case kValveEventConnect:
LOG_I ("接收到阀门连接状态数据");
LOG_HEX ("bt_rx_data:", 16, data_buf, fram_len);
rt_memcpy (&valve[data_buf[3] - 1], &data_buf[3], sizeof (struct valve_t) - 14); // 只要前面的一部分数据,后面的不要
LOG_HEX ("valve_data:", 16, (rt_uint8_t *)&valve[data_buf[3] - 1], sizeof (struct valve_t));
if (valve[data_buf[3] - 1].valve_connct_status == 1)
{
LOG_D ("阀门连接");
while (!power_on_send_flag)
{
rt_thread_mdelay (100);
}
to_sever_send_bt_connect_flag = 1;
Ml307_Send_Event (kMl307ValveConnectEvent);
}
else
{
LOG_D ("阀门断开");
while (!power_on_send_flag)
{
rt_thread_mdelay (100);
}
if (to_sever_send_bt_connect_flag)//有了连接后再断开,否则不发送
{
to_sever_send_bt_connect_flag = 0;
Ml307_Send_Event (KMl307ValveDisconnectEvent);
}
}
break;
default:
LOG_W ("unknow cmd: %02X", data[index + 2]);
break;
}
return ret;
}
static void BSP_Bt_Parse_Data (void)
{
rt_size_t len = lwrb_get_full (&bt_lwrb_rx);
char *rx_ptr = rt_malloc (len + 1);
// rt_uint8_t bt_rx_buf[256] = {0};
BSP_Bt_Recv_Data ((uint8_t *)rx_ptr, len);
// 发送过来的数据格式为:帧头 + 数据长度 + 事件类型 + 数据 + 校验码 + 帧尾
BSP_Bt_Process ((uint8_t *)rx_ptr, len);
rt_free (rx_ptr);
}
void BSP_Bt_Valve_Updata (void)
{
uint8_t cnt = 0;
uint8_t mac[6] = {0};
uint8_t num = Flash_Get_Valve_Num();
LOG_D ("BSP_Bt_Valve_Updata num: %d ", num);
if (num == 0)
{
return;
}
rt_memset (&valve[0], 0, sizeof (valve_data));
for (int i = 1; i <= MAX_VALVE_NUM; i++) // 这个循环是为了将数据拷贝到valve_list中 并且保证id号和flash对应起来
{
if (Flash_Get_Mac_Addr (mac, i) == RT_EOK) // 说明有MAC数据
{
rt_memcpy (valve[cnt].valve_mac, mac, 6); // 这样做的目的就是读取方便只需要根据flash中读取到的数量进行读取前N个值
valve[cnt].valve_id = i;
LOG_D ("updata valve_id: %d, valve_mac: %02X %02X %02X %02X %02X %02X",
valve[cnt].valve_id,
valve[cnt].valve_mac[0],
valve[cnt].valve_mac[1],
valve[cnt].valve_mac[2],
valve[cnt].valve_mac[3],
valve[cnt].valve_mac[4],
valve[cnt].valve_mac[5]);
cnt++;
break;
}
else
{
LOG_D ("BSP_Bt_Valve_Updata: flash read error");
break;
}
}
Flash_Set_Valve_Num (cnt);
}
static void Bt_Thread_Entry (void *parameter)
{
#if 0
// 初始化阀门信息 测试用
valve[0].valve_id = 1;
valve[0].valve_mac[0] = 0X93;
valve[0].valve_mac[1] = 0xB4;
valve[0].valve_mac[2] = 0x8F;
valve[0].valve_mac[3] = 0x10;
valve[0].valve_mac[4] = 0x53;
valve[0].valve_mac[5] = 0x5C;
Flash_Set_Mac_Addr(valve[0].valve_mac, 0);
Flash_Set_Valve_Num(1);
#endif // 0
BSP_Bt_Valve_Updata();
lwrb_init (&bt_lwrb_rx, bt_rx_buffer, sizeof (bt_rx_buffer));
lwrb_reset (&bt_lwrb_rx);
LOG_D ("Bt_Thread_Entry");
while (1)
{
if (bt_recv_readline())
{
BSP_Bt_Parse_Data();
}
}
}
/* 接收数据回调函数 */
static rt_err_t Bt_Rcv_Cb (rt_device_t dev, rt_size_t size)
{
rt_sem_release (&bt_rx_sem);
return RT_EOK;
}
int BSP_Bt_Init (void)
{
rt_err_t ret = RT_EOK;
rt_sem_init (&bt_rx_sem, "bt_rx_sem", 0, RT_IPC_FLAG_PRIO); /* 接收来自蓝牙主机的信号量 */
rt_sem_init (&bt_ctr_sem, "bt_ctr_sem", 0, RT_IPC_FLAG_PRIO);
rt_sem_init (&bt_reg_sem, "bt_reg_sem", 0, RT_IPC_FLAG_PRIO);
rt_sem_init (&bt_rem_sem, "bt_rem_sem", 0, RT_IPC_FLAG_PRIO);
rt_sem_init (&bt_rep_sem, "bt_rep_sem", 0, RT_IPC_FLAG_PRIO);
/* 查找系统中的串口设备 */
rt_bt_device = rt_device_find (BT_UART);
if (!rt_bt_device)
{
LOG_E ("find %s failed!\n", BT_UART);
return RT_ERROR;
}
/* 以中断接收模式打开串口设备 */
if (rt_device_open (rt_bt_device, RT_DEVICE_FLAG_INT_RX) != RT_EOK)
{
LOG_E ("rt_device_open failed!\n");
return RT_ERROR;
}
/* 设置接收回调函数 */
if (rt_device_set_rx_indicate (rt_bt_device, Bt_Rcv_Cb) != RT_EOK)
{
LOG_E ("rt_device_set_rx_indicate failed!\n");
return RT_ERROR;
}
/* 静态初始化线程 1*/
ret = rt_thread_init (&bt_thread, // 该线程用于数据解析
"bt_thread",
Bt_Thread_Entry,
RT_NULL,
&bt_thread_stack[0],
sizeof (bt_thread_stack),
BT_THREAD_PRIORITY,
BT_THREAD_TIMESLICE);
/* 创建成功则启动线程 */
rt_thread_startup (&bt_thread);
return ret;
}
// INIT_COMPONENT_EXPORT(BSP_Bt_Init);
#ifdef TEST_ENABLE
static void TEST_BT_Send_Data (int argc, char **argv)
{
if (argc == 3)
{
int mode = atoi (argv[1]);
int id = atoi (argv[2]) - 1;
switch (mode)
{
case 1:
Bt_Valve_Handler (kValveCmdCtr, id, RT_NULL);
break;
case 2:
Flash_Set_Valve_Num (1);
Bt_Valve_Handler (kValveCmdReg, id, RT_NULL);
break;
case 3:
Bt_Valve_Handler (kValveCmdRem, id, RT_NULL);
rt_memset (valve[0].valve_mac, 0, sizeof (struct valve_t));
Flash_Set_Mac_Addr (valve[0].valve_mac, 0);
Flash_Set_Valve_Num (0);
break;
case 4:
Bt_Valve_Handler (kValveCmdRep, id, RT_NULL);
break;
default:
break;
}
}
}
MSH_CMD_EXPORT (TEST_BT_Send_Data, "TEST_BT_Send_Data");
#endif