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

460 lines
9.5 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 "24l01.h"
#include "nrf.h"
#include "stdio.h"
#include "buff.h"
#include "string.h"
#include "rthw.h"
// 接口函数
static void nrf_dalay_us(int us)
{
rt_hw_us_delay(us);
}
static int nrf_get_random(void)
{
static int d=0;
d++;
return d;
}
/* -------------------------- 通信协议相关 ---------------------------- */
typedef struct{
// 连接状态
int connect_state;
// 数据交互状态
int interaction_err;
// 不发送回应
int no_respond;
// 数据发送成功
int send_ok;
// 交互超时时间us
int interaction_time_out;
// 连接超时时间ms
int connect_time_out;
// 重试次数
int retry_itmes;
// 信道频率
int channel_frequency;
// 发送数据包总数
int send_packet_all;
// 发送失败的数据包总数
int send_packet_failed;
// 本机地址
u8 addr_myself[5];
// 目标机地址
u8 addr_dst[5];
// 最近发送使用的魔数
u8 magic_number_send;
// 最近接收使用的魔数
u8 magic_number_recv;
}nrf_env_struct;
static nrf_env_struct g_nrf_env={0};
static data_buff g_buff={0};
static const u8 g_dst_addr[TX_ADR_WIDTH]={0x34,0x43,0x10,0x10,0x01}; //发送地址
static const u8 g_my_addr[RX_ADR_WIDTH]={0x34,0x43,0x10,0x10,0x01}; //发送地址
// 设置连接状态
int nrf_set_connect_state(int s)
{
g_nrf_env.connect_state=s;
return NRF_OK;
}
// 获取连接状态
int nrf_get_connect_state(void)
{
return g_nrf_env.connect_state;
}
// 设置通信地址
int nrf_set_addr(const u8 *my,const u8 *dst)
{
if(my) memcpy(g_nrf_env.addr_myself,my,5);
if(dst) memcpy(g_nrf_env.addr_dst,dst,5);
nrf24l01_set_addr(g_nrf_env.addr_myself,g_nrf_env.addr_dst);
return NRF_OK;
}
// 设置重试次数
int nrf_set_retry_times(int times)
{
g_nrf_env.retry_itmes=times;
return NRF_OK;
}
// 设置信道
int nrf_set_chan(u8 chan)
{
if(chan>=64) return NRF_ERR;
if(g_nrf_env.channel_frequency!=chan)
{
g_nrf_env.channel_frequency=chan;
nrf24l01_set_chan(g_nrf_env.channel_frequency);
}
return NRF_OK;
}
// 获取当前信道
int nrf_get_chan(void)
{
return g_nrf_env.channel_frequency;
}
// 设置超时时间
int nrf_set_time_out(int connect_time_ms,int interaction_time_us)
{
g_nrf_env.connect_time_out=connect_time_ms;
g_nrf_env.interaction_time_out=interaction_time_us;
return 0;
}
// 获取发送数据包情况
int nrf_get_packet_num(int *all,int *failed)
{
if(all) *all=g_nrf_env.send_packet_all;
if(failed) *failed=g_nrf_env.send_packet_failed;
return NRF_OK;
}
// 清空数据包发送记录
int nrf_clear_packet_num(void)
{
g_nrf_env.send_packet_all=0;
g_nrf_env.send_packet_failed=0;
return NRF_OK;
}
// 发送完成数据回调
void nrf_send_cb(void *t);
// 接收到数据回调
void nrf_recv_cb(void *t);
// 无线通信初始化
int nrf_init(void)
{
memset(&g_nrf_env,0,sizeof(nrf_env_struct));
buff_init(&g_buff,4096*16,0,0,0);
nrf24l01_set_recv_cb(nrf_recv_cb,0);
nrf24l01_set_send_cb(nrf_send_cb,0);
nrf24l01_init();
g_nrf_env.channel_frequency=-1;
nrf_set_connect_state(1);
nrf_set_addr(g_my_addr,g_dst_addr);
nrf_set_chan(20);
nrf_set_time_out(1000,5000);
nrf_set_retry_times(1000);
if(nrf24l01_check()==0)
return NRF_OK;
else
{
buff_deinit(&g_buff);
return NRF_ERR;
}
}
// 去初始化
int nrf_deinit(void)
{
buff_deinit(&g_buff);
nrf24l01_deinit();
return NRF_OK;
}
// 读取一个字节数据NRF_OK成功
int nrf_read_byte(uint8_t *data)
{
if(buff_read_byte(&g_buff,data)==0)
return NRF_OK;
else return NRF_ERR;
}
// 清空接收区
int nrf_clear(void)
{
buff_clear(&g_buff);
return NRF_OK;
}
// 发送任意长度的数据成功返回NRF_OK
int nrf_send(void *data,int size,int *rs)
{
int ret=NRF_OK;
int len=0;
uint8_t *ptr=data;
nrf_load_struct load;
while(size>0)
{
if(size>29)
len=29;
else len=size;
nrf_packet_pack(&load,NRF_TYPE_DATA,ptr,len);
if(ret=nrf_send_load(&load),ret!=NRF_OK)
{
return ret;
}
else
{
if(rs) (*rs)+=len;
size-=len;
ptr+=len;
}
}
return ret;
}
// 同步通信信道
int nrf_ctrl_chan(u8 chan)
{
if(nrf_get_connect_state()==0) return NRF_ERR;
nrf_load_struct load={0};
nrf_chan_struct c={0};
c.chan=chan;
c.times=0;
u8 chan_old=g_nrf_env.channel_frequency;
// 第一次发送是收不到回应的,因为从机已经改了信道
nrf_packet_pack(&load,NRF_TYPE_CHAN,&c,sizeof(nrf_chan_struct));
nrf_send_load(&load);
// 这里修改信道后发送第二次
nrf_set_chan(c.chan);
c.times++;
// 这次要是成功了则调频成功
nrf_packet_pack(&load,NRF_TYPE_CHAN,&c,sizeof(nrf_chan_struct));
if(nrf_send_load(&load)==NRF_OK)
{
return NRF_OK;
}
else
{
// 设置回之前的信道
nrf_set_chan(chan_old);
return NRF_ERR;
}
}
// 通过协议发送负载数据,成功返回 NRF_OK
int nrf_send_load(nrf_load_struct *load)
{
int ret=0;
int time_out=0;
int retry_times=0;
// 交互成功设置为NRF_ERR在收到对方返回后自动更新
g_nrf_env.interaction_err=NRF_ERR;
// 在发送的时候设置魔数
do{
load->magic_number=nrf_get_random();
}while(load->magic_number==g_nrf_env.magic_number_send);
g_nrf_env.magic_number_send=load->magic_number;
// TODO 这里设置收到数据回调函数,用于接收对方的回应
retry:
nrf24l01_send(load);
g_nrf_env.send_packet_all++;
while(time_out<g_nrf_env.interaction_time_out)
{
if(g_nrf_env.interaction_err==NRF_OK) return NRF_OK;
if(g_nrf_env.interaction_err!=NRF_ERR) return g_nrf_env.interaction_err;
nrf_dalay_us(1);
time_out++;
}
if(retry_times<g_nrf_env.retry_itmes)
{
g_nrf_env.send_packet_failed++;
retry_times++;
time_out=0;
goto retry;
}
return NRF_TIMEOUT;
}
// 在接收到数据之后回复对方
int nrf_respond(nrf_load_struct *load)
{
if(g_nrf_env.no_respond) return NRF_OK;
int ret=0;
int time_out=0;
int retry_times=0;
// 发送成功设置为0在发送完成后自动置1
g_nrf_env.send_ok=0;
// 把魔数设置成和接收时相同
load->magic_number=g_nrf_env.magic_number_recv;
// 由于这个函数在中断中调用,因此不能在这里判断发送成功,
// 先假设每次都发送成功,再由主机端来做重试操作
nrf24l01_send(load);
return NRF_OK;
}
// 设置是否回应,1,不回应0回应
int nrf_set_no_respond(int power)
{
g_nrf_env.no_respond=power;
return NRF_OK;
}
// 打包帧,返回NRF_OK成功
int nrf_packet_pack(nrf_load_struct *load,u8 type,void *data,int data_len)
{
if(data_len>29) return NRF_ERR;
if(load==0) return NRF_ERR;
load->len=data_len;
load->type=type;
memcpy(load->load,data,data_len);
return NRF_OK;
}
// 比较两个地址是否相同是返回1
int nrf_addr_cmp(u8 addr1[5],u8 addr2[5])
{
for(int i=0;i<5;i++)
{
if(addr1[i]!=addr2[i]) return 0;
}
return 1;
}
// 接收到数据回调
void nrf_recv_cb(void *t)
{
nrf_load_struct r={0};
nrf24l01_read(&r);
// TODO 接收到数据之后重置超时定时器
u8 magic_number_old=g_nrf_env.magic_number_recv;
g_nrf_env.magic_number_recv=r.magic_number;
switch(r.type)
{
case NRF_TYPE_NULL:
// TODO 是空操作,回复成功即可
nrf_packet_pack(&r,NRF_TYPE_ANSWER,NRF_ANSWER_OK);
nrf_respond(&r);
break;
case NRF_TYPE_CONN:
{
nrf_conn_struct *c=(nrf_conn_struct *)r.load;
if(nrf_addr_cmp(c->addr_dst,g_nrf_env.addr_myself))
{
nrf_packet_pack(&r,NRF_TYPE_ANSWER,NRF_ANSWER_OK);
nrf_respond(&r);
// TODO 这里设置连接后的信道
nrf_set_addr(0,c->addr_src);
nrf_set_chan(c->chan);
}
}
break;
case NRF_TYPE_CHAN:
{
// 在与主句连接后可以切换信道
nrf_chan_struct *c=(nrf_chan_struct *)r.load;
if(nrf_get_connect_state())
{
if(c->times==0)
{
// 第一次接收直接改信道,不回应
nrf_set_chan(c->chan);
}
else if(c->times==1)
{
// 第二次回应成功
nrf_packet_pack(&r,NRF_TYPE_ANSWER,NRF_ANSWER_OK);
nrf_respond(&r);
}
}
}
break;
case NRF_TYPE_ANSWER:
{
// TODO 根据返回的错误类型设置交互状态
if(g_nrf_env.magic_number_send==r.magic_number)
{
u8 err=r.load[0];
g_nrf_env.interaction_err=err;
}
else
{
g_nrf_env.interaction_err=NRF_MISMATCH;
}
}
break;
case NRF_TYPE_DATA:
{
// 保存接收到的数据
if(magic_number_old!=r.magic_number)
{
for(int i=0;i<r.len;i++)
{
if(buff_save_byte(&g_buff,r.load[i])!=0)
{
printf("%s:buff overflow\r\n",__func__);
}
}
}
else
{
printf("%s:resave\r\n",__func__);
}
nrf_packet_pack(&r,NRF_TYPE_ANSWER,NRF_ANSWER_OK);
nrf_respond(&r);
}
break;
default:
break;
}
}
// 发送完成数据回调
void nrf_send_cb(void *t)
{
g_nrf_env.send_ok=1;
}