385 lines
8.7 KiB
C
385 lines
8.7 KiB
C
#include "nrf.h"
|
||
#include "24l01.h"
|
||
#include "buff.h"
|
||
#include "rthw.h"
|
||
#include "stdio.h"
|
||
#include "string.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;
|
||
|
||
// 本机地址
|
||
uint8_t addr_myself[5];
|
||
|
||
// 目标机地址
|
||
uint8_t addr_dst[5];
|
||
|
||
// 最近发送使用的魔数
|
||
uint8_t magic_number_send;
|
||
|
||
// 最近接收使用的魔数
|
||
uint8_t magic_number_recv;
|
||
|
||
} nrf_env_struct;
|
||
|
||
static nrf_env_struct g_nrf_env = {0};
|
||
static data_buff g_buff = {0};
|
||
static const uint8_t g_dst_addr[TX_ADR_WIDTH] = {0x34, 0x43, 0x10, 0x10,
|
||
0x01}; // 发送地址
|
||
static const uint8_t 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 uint8_t *my, const uint8_t *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(uint8_t 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(uint8_t 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;
|
||
uint8_t 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, uint8_t 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(uint8_t addr1[5], uint8_t 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 接收到数据之后重置超时定时器
|
||
uint8_t 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) {
|
||
uint8_t 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; }
|