Files
player/Project/Src/MyApp/ble_demo.c
2025-07-05 19:47:28 +08:00

925 lines
16 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.

#include <stdio.h>
#include "at_host.h"
#include "string.h"
#include "stdlib.h"
#include "rtthread.h"
#include "ble_demo.h"
//在同一个线程中调用则不需要加临界区
#if 1
#include "rthw.h"
#define IRQ_DISABLE() rt_enter_critical()
#define IRQ_ENABLE() rt_exit_critical()
#else
#define IRQ_DISABLE() { }
#define IRQ_ENABLE() { }
#endif
/*------------------------buff相关操作函数---------------------------*/
//清空buff
static int buff_clear(ble_buff *buff);
//初始化buff
static void buff_init(ble_buff *buff)
{
buff->buff_len=BLE_BUFF_LEN;
buff_clear(buff);
}
//写入一个字节
static int buff_save_byte(ble_buff *buff,uint8_t data)
{
IRQ_DISABLE();
if (buff->buff_used<buff->buff_len)
{
buff->buff[buff->save_ptr]=data;
buff->buff_used++;
buff->save_ptr++;
if (buff->save_ptr>=buff->buff_len)
buff->save_ptr=0;
IRQ_ENABLE();
return 1;
}
IRQ_ENABLE();
return 0;
}
//读取一个字节
static int buff_read_byte(ble_buff *buff,uint8_t *data)
{
IRQ_DISABLE();
if (buff->buff_used)
{
*data=buff->buff[buff->read_ptr];
buff->buff_used--;
buff->read_ptr++;
if (buff->read_ptr>=buff->buff_len)
buff->read_ptr=0;
IRQ_ENABLE();
return 1;
}
IRQ_ENABLE();
return 0;
}
//查找buff中是否有指定字符
static int buff_find_char(ble_buff *buff,uint8_t data)
{
int ptr=buff->read_ptr;
int len=buff->buff_used;
while(len--)
{
if(data==buff->buff[ptr])
return 1;
ptr++;
if (ptr>=buff->buff_len)
ptr=0;
}
return 0;
}
//清空buff
static int buff_clear(ble_buff *buff)
{
IRQ_DISABLE();
buff->buff_used=0;
buff->read_ptr=0;
buff->save_ptr=0;
IRQ_ENABLE();
return 0;
}
/*------------------------buff相关操作函数End---------------------------*/
/*------------------------device相关操作函数---------------------------*/
//初始化蓝牙设备
int device_init(ble_device *device)
{
device->conn_handle=0;
device->linked=0;
memset(device->mac,0,6);
buff_init(&device->buff_recv);
return 1;
}
//设置此设备的mac地址
int device_set_mac(ble_device *device,uint8_t mac[6])
{
memcpy(device->mac,mac,6);
return 1;
}
//设置此设备的conn_handle
int device_set_handle(ble_device *device,uint16_t handle)
{
device->conn_handle=handle;
return 1;
}
//把数据存入设备缓冲
int device_save_buff(ble_device *device,uint8_t *buff,int size)
{
int ret=0;
while(size--)
{
if (buff_save_byte(&device->buff_recv,buff[ret])==0)
return ret;
ret++;
}
return ret;
}
//读取设备缓冲,直到遇到界定符
int device_read_buff(ble_device *device,uint8_t *buff,int buff_size,uint8_t end_par)
{
if(buff_find_char(&device->buff_recv,end_par)==0)
return 0;
int ret=0;
uint8_t t=0;
while(1)
{
if(buff_read_byte(&device->buff_recv,&t)==0)
return ret;
if(buff_size)
{
buff[ret]=t;
buff_size--;
ret++;
}
if(t==end_par)
return ret;
}
}
//读取设备缓冲,指定长度
int device_read_buff_by_len(ble_device *device,uint8_t *buff,int read_len)
{
int ret=0;
uint8_t t=0;
while(1)
{
if(buff_read_byte(&device->buff_recv,&t)==0)
return ret;
if(read_len)
{
buff[ret]=t;
read_len--;
ret++;
}
else
return ret;
}
}
/*------------------------device相关操作函数End---------------------------*/
static void ble_print_data(uint8_t *data,int len)
{
for(int i=0;i<len;i++)
{
printf("%02X ",data[i]);
}
printf("\r\n");
}
/*--------------------------ble相关操作函数----------------------------*/
//添加通知消息
int ble_add_notice(ble_struct *ble,uint8_t *obj,int obj_size,uint8_t op,uint8_t *par,int par_size);
//连接事务改变
int ble_linked_change(ble_struct *ble,uint16_t handle,uint16_t state);
//收到数据
int ble_save_data(ble_struct *ble,uint16_t handle,uint8_t *data,int len);
//返回指定句柄的设备
ble_device *ble_find_device(ble_struct *ble,uint16_t handle);
//添加设备
int ble_add_device(ble_struct *ble,uint16_t handle);
//删除设备
int ble_sub_device(ble_struct *ble,uint16_t handle);
static int ble_service_on(void *t);
static int ble_service_off(void);
//ble初始化
void ble_init(ble_struct *ble)
{
if(ble==0) return;
memset(ble,0,sizeof(ble_struct));
at_init();
ble->mode='i';
ble->linked=0;
for(int i=0;i<BLE_MAX_LINKED;i++)
{
device_init(&ble->device[i]);
}
at_clear_buff();
ble->ret_event=rt_event_create("ble_ret", RT_IPC_FLAG_FIFO);
ble->kno_event=rt_event_create("ble_kno", RT_IPC_FLAG_FIFO);
rt_event_send(ble->kno_event,2);
ble_service_on(ble);
ble_reboot(ble);
}
//ble去初始化
void ble_deinit(ble_struct *ble)
{
if(ble==0) return ;
ble_reboot(ble);
ble_service_off();
at_deinit();
if(ble->ret_event)
rt_event_delete(ble->ret_event);
if(ble->kno_event)
rt_event_delete(ble->kno_event);
}
// 设置回调函数
int ble_set_callback_linked_change(ble_struct *ble,void (*linked_change)(uint16_t handle,uint16_t state))
{
ble->linked_change=linked_change;
return 1;
}
int ble_set_callback_recv_data(ble_struct *ble,void (*recv_data)(uint16_t handle,uint8_t *data,int len))
{
ble->recv_data=recv_data;
return 1;
}
int ble_set_callback_user_irq(ble_struct *ble,void (*user_irq)(uint8_t *data,int len))
{
ble->user_irq=user_irq;
return 1;
}
//处理通知消息
int ble_deal_notice(ble_struct *ble)
{
if(ble==0) return 0;
int len=0;
uint8_t *data=ble->return_line;
len=at_get_return_line(data);
if(len==-1) {
return 0;
}
uint8_t *par=0;
int par_size=0;
uint8_t *obj=0;
int obj_size=0;
uint8_t op=0;
if(at_decode_line(data,len,&obj,&obj_size,&op,&par,&par_size)==-1)
{
return 0;
}
if(op==CMDAT_CMD_RET)
{
//命令返回消息,存储到通知缓冲区
ble_add_notice(ble,obj,obj_size,op,par,par_size);
}
else if(op==CMDAT_CMD_ACT)
{
//通知消息,进一步区分
if(obj[0]==0x01)
{
//连接事务改变
ble_linked_change(ble,*(uint16_t *)par,*(uint16_t *)(par+2));
}
else if(obj[0]==0x02)
{
//收到新数据
if(ble->recv_data==0)
ble_save_data(ble,*(uint16_t *)par,par+2,par_size-2);
else
ble->recv_data(*(uint16_t *)par,par+2,par_size-2);
}
else if(obj[0]==0xff)
{
// 用户中断
if(ble->user_irq) ble->user_irq(par,par_size);
}
}
return 1;
}
//添加通知消息
int ble_add_notice(ble_struct *ble,uint8_t *obj,int obj_size,uint8_t op,uint8_t *par,int par_size)
{
notice_t *n=&ble->notice;
if(ble->kno_event)
{
// 等待接收方查看通知
rt_uint32_t ev;
rt_event_recv(ble->kno_event,0xffffffff,RT_EVENT_FLAG_OR|RT_EVENT_FLAG_CLEAR,1000,&ev);
}
//ble_print_data(par,par_size);
IRQ_DISABLE();
memcpy(n->obj,obj,obj_size);
memcpy(n->par,par,par_size);
n->obj_size=obj_size;
n->par_size=par_size;
IRQ_ENABLE();
if(ble->ret_event)
{
// 发送通知提醒接收方查看
rt_event_send(ble->ret_event,1);
}
return 1;
}
//获取通知消息,返回0失败
int ble_get_notice(ble_struct *ble,uint8_t *obj,int *obj_size,uint8_t *op,uint8_t *par,int *par_size)
{
rt_uint32_t ev;
if(ble->ret_event)
{
if(rt_event_recv(ble->ret_event,0xffffffff,RT_EVENT_FLAG_OR|RT_EVENT_FLAG_CLEAR,1000,&ev)==RT_EOK)
{
IRQ_DISABLE();
notice_t *n=&ble->notice;
if(obj) memcpy(obj,n->obj,n->obj_size);
if(obj_size) *obj_size=n->obj_size;
if(par) memcpy(par,n->par,n->par_size);
if(par_size) *par_size=n->par_size;
n->obj_size=0;
n->par_size=0;
IRQ_ENABLE();
if(ble->kno_event)
{
// 通知已查看
rt_event_send(ble->kno_event,1);
}
return 1;
}
}
return 0;
}
//连接事务改变
int ble_linked_change(ble_struct *ble,uint16_t handle,uint16_t state)
{
if(state==1)
{
//添加连接设备
ble_add_device(ble,handle);
}
else if(state==0)
{
//删除连接设备
ble_sub_device(ble,handle);
}
else
{
return 0;
}
// 调用用户回调函数
if(ble->linked_change) ble->linked_change(handle,state);
return 1;
}
//收到数据
int ble_save_data(ble_struct *ble,uint16_t handle,uint8_t *data,int len)
{
ble_device *device=ble_find_device(ble,handle);
if(device)
{
//printf("%s:recved %d\r\n",__func__,len);
return device_save_buff(device,data,len);
}
return 0;
}
//返回指定句柄的设备
ble_device *ble_find_device(ble_struct *ble,uint16_t handle)
{
if(handle==0) return 0;
for(int i=0;i<BLE_MAX_LINKED;i++)
{
if(ble->device[i].conn_handle==handle)
return &ble->device[i];
}
return 0;
}
//返回指定索引的蓝牙设备
ble_device *ble_find_device_by_index(ble_struct *ble,int index)
{
if(ble==0) return 0;
if(index<BLE_MAX_LINKED)
{
if(ble->device[index].conn_handle)
return &ble->device[index];
}
return 0;
}
//添加设备
int ble_add_device(ble_struct *ble,uint16_t handle)
{
if(handle==0) return 0;
IRQ_DISABLE();
for(int i=0;i<BLE_MAX_LINKED;i++)
{
ble_device *device=&ble->device[i];
if(device->conn_handle==0)
{
memcpy(device->mac,ble->conn_mac,6);
device->conn_handle=handle;
device->linked=1;
ble->linked++;
IRQ_ENABLE();
return 1;
}
}
IRQ_ENABLE();
return 0;
}
//删除设备
int ble_sub_device(ble_struct *ble,uint16_t handle)
{
if(handle==0) return 0;
IRQ_DISABLE();
for(int i=0;i<BLE_MAX_LINKED;i++)
{
ble_device *device=&ble->device[i];
if(device->conn_handle==handle)
{
device->conn_handle=0;
device->linked=0;
memset(device->mac,0,6);
buff_clear(&device->buff_recv);
ble->linked--;
IRQ_ENABLE();
return 1;
}
}
IRQ_ENABLE();
return 0;
}
//读取数据直到出现界定符
int ble_get_recv_data_by_end(ble_struct *ble,uint16_t handle,uint8_t *buff,int buff_size,uint8_t end_par)
{
if(ble==0) return 0;
ble_device *device=ble_find_device(ble,handle);
if (device)
{
return device_read_buff(device,buff,buff_size,end_par);
}
return 0;
}
//读取指定长度的数据
int ble_get_recv_data(ble_struct *ble,uint16_t handle,uint8_t *buff,int read_len)
{
if(ble==0) return 0;
ble_device *device=ble_find_device(ble,handle);
if (device)
{
return device_read_buff_by_len(device,buff,read_len);
}
return 0;
}
//获取命令返回
int ble_get_cmd_return(ble_struct *ble,uint8_t *buff,int *buff_size)
{
int ret=0;
ret=ble_get_notice(ble,0,0,0,buff,buff_size);
return ret;
}
//设置设备名称
int ble_set_name(ble_struct *ble,char *name)
{
if(ble==0) return 0;
uint8_t *data=ble->data_temp;
int size=0;
at_send_set_event(0x01,name,strlen(name));
if(ble_get_cmd_return(ble,data,&size)==1)
{
if(data[0]==1)
return 1;
}
return 0;
}
//获取设备mac地址
int ble_get_mac(ble_struct *ble,uint8_t mac[6])
{
if(ble==0) return 0;
uint8_t *data=ble->data_temp;
int size=0;
at_send_get_event(0x02,0,0);
if(ble_get_cmd_return(ble,data,&size)==1)
{
if(size==6)
{
memcpy(mac,data,6);
return 1;
}
}
return 0;
}
//重启
int ble_reboot(ble_struct *ble)
{
if(ble==0) return 0;
uint8_t *data=ble->data_temp;
int size=0;
int time_out=100;
do{
at_send_set_event(0x03,0,0);
rt_thread_delay(2);
ble_get_notice(ble,0,0,0,data,&size);
if((size==1)&&(data[0]==1))
{
rt_thread_delay(100);
at_clear_buff();
return 1;
}
}
while(time_out--);
return 0;
}
//设置uuid
int ble_set_uuid(ble_struct *ble,uint8_t sub,uint8_t type,uint8_t *uuid)
{
if(ble==0) return 0;
uint8_t *data=ble->data_temp;
int size=0;
data[0]=sub;data[1]=type;
memcpy(&data[2],uuid,type/8);
at_send_set_event(0x05,data,2+type/8);
if(ble_get_cmd_return(ble,data,&size)==1)
{
if(data[0]==1)
return 1;
}
return 0;
}
//打开/关闭数据传输
int ble_set_data_transport(ble_struct *ble,uint8_t power)
{
if(ble==0) return 0;
uint8_t *data=ble->data_temp;
int size=0;
at_send_set_event(0x06,&power,1);
if(ble_get_cmd_return(ble,data,&size)==1)
{
if(data[0]==1)
return 1;
}
return 0;
}
//发送数据
int ble_send_data(ble_struct *ble,uint16_t handle,uint8_t *buff,int len)
{
if(ble==0) return 0;
uint8_t *data=ble->data_temp;
int size=0;
int pack_len=0;
while(len)
{
data[0]=handle;
data[1]=handle>>8;
if(len>20) pack_len=20;
else pack_len=len;
memcpy(&data[2],buff,pack_len);
at_send_set_event(0x07,data,pack_len+2);
if(ble_get_cmd_return(ble,data,&size)==1)
{
if(data[0]==1)
{
if (len==0)
return 1;
}
else
{
return 0;
}
}
else
return 0;
len-=pack_len;
buff+=pack_len;
}
return 0;
}
//设置为从机模式
int ble_set_slave(ble_struct *ble)
{
if(ble==0) return 0;
uint8_t *data=ble->data_temp;
int size=0;
at_send_set_event(0x10,0,0);
if(ble_get_cmd_return(ble,data,&size)==1)
{
if(data[0]==1)
{
ble->mode='s';
return 1;
}
}
return 0;
}
//设置为主机模式
int ble_set_host(ble_struct *ble)
{
if(ble==0) return 0;
uint8_t *data=ble->data_temp;
int size=0;
at_send_set_event(0x20,0,0);
if(ble_get_cmd_return(ble,data,&size)==1)
{
if(data[0]==1)
{
ble->mode='h';
return 1;
}
}
return 0;
}
//连接指定的从机
int ble_connect_by_mac(ble_struct *ble,uint8_t mac[6])
{
if(ble==0) return 0;
uint8_t *data=ble->data_temp;
int size=0;
at_send_set_event(0x21,mac,6);
if(ble_get_cmd_return(ble,data,&size)==1)
{
if(data[0]==1)
{
memcpy(ble->conn_mac,mac,6);
return 1;
}
}
return 0;
}
//断开指定的从机
int ble_discon_by_mac(ble_struct *ble,uint8_t mac[6])
{
if(ble==0) return 0;
uint8_t *data=ble->data_temp;
int size=0;
at_send_set_event(0x22,mac,6);
if(ble_get_cmd_return(ble,data,&size)==1)
{
if(data[0]==1)
return 1;
}
return 0;
}
//扫描
int ble_scan(ble_struct *ble,ble_mac_name mac[32],int *mac_num)
{
if(ble==0) return 0;
uint8_t *data=ble->data_temp;
int size=0;
*mac_num=0;
at_send_set_event(0x23,0,0);
rt_thread_delay(3500);
while(1)
{
if(ble_get_cmd_return(ble,data,&size)==1)
{
if(size==1)
{
if(data[0]==1)
return 1;
else
return 0;
}
else if(size>=7)
{
memcpy(mac[*mac_num].mac,data,6);
mac[*mac_num].rssi=data[6];
if(size>7)
{
int len=size-7;
memcpy(mac[*mac_num].name,data+7,len);
mac[*mac_num].name[len]=0;
}
else
mac[*mac_num].name[0]=0;
(*mac_num)++;
}
}
else
return 0;
}
}
//发送用户设置数据
int ble_user_cmd_set(ble_struct *ble,uint8_t *tx,int tx_len)
{
if(ble==0) return 0;
uint8_t *data=ble->data_temp;
int size=0;
at_send_set_event(0xff,tx,tx_len);
if(ble_get_cmd_return(ble,data,&size)==1)
{
if(size==1)
return 1;
}
return 0;
}
//发送用户获取数据rx_len获取的数据长度失败返回0
int ble_user_cmd_get(ble_struct *ble,uint8_t *tx,int tx_len,uint8_t *rx,int *rx_len)
{
if(ble==0) return 0;
uint8_t *data=ble->data_temp;
int size=0;
int recv_len=0;
uint8_t obj;
int obj_size;
at_send_get_event(0xff,tx,tx_len);
while(1)
{
if(ble_get_notice(ble,&obj,&obj_size,0,data,&size)==1)
{
if(obj_size==0)
return data[0];
else
{
if(recv_len==0)
{
if(size>*rx_len) recv_len=*rx_len;
else recv_len=size;
memcpy(rx,data,recv_len);
//ble_print_data(rx,recv_len);
*rx_len=recv_len;
}
}
}else break;
}
return 0;
}
static int g_service_work;
static int g_service_done=1;
// ble 服务线程
static void ble_service_thread(void *t)
{
ble_struct *ble=t;
g_service_done=0;
int ev;
while(g_service_work)
{
ev=at_get_event();
if(ev&CMDAT_EVENT_RECV)
{
ev&=~CMDAT_EVENT_RECV;
while(ble_deal_notice(ble)==1);
}
if(ev&CMDAT_EVENT_USER)
{
ev&=~CMDAT_EVENT_USER;
at_send_packet();
}
if(ev)
{
}
}
g_service_done=1;
}
static int ble_service_on(void *t)
{
rt_err_t result = RT_EOK;
rt_thread_t tid;
// 保证线程没有被创建
if(g_service_done)
{
g_service_work=1;
tid = rt_thread_create("ble_service_thread", ble_service_thread, t, 2048, 11, 10);
if (tid != NULL && result == RT_EOK)
rt_thread_startup(tid);
return 0;
}
else
{
return -1;
}
}
static int ble_service_off(void)
{
// 保证线程已经被创建
if(g_service_work)
{
g_service_work=0;
at_send_user_event(0x04);
while(g_service_done==0)
{
rt_thread_delay(10);
}
return 0;
}
else
{
return -1;
}
}