458 lines
9.5 KiB
C
458 lines
9.5 KiB
C
#include "stdio.h"
|
|
#include "rtthread.h"
|
|
#include "board.h"
|
|
#include "mystdlib.h"
|
|
#include "list.h"
|
|
#include "mystring.h"
|
|
#include "signal.h"
|
|
#include "prot_uc.h"
|
|
#include "buff.h"
|
|
#include "bytearray.h"
|
|
#include "debug.h"
|
|
#include "crc.h"
|
|
#include "dev_flash.h"
|
|
#include "mymisc.h"
|
|
#include "elec_det.h"
|
|
#include "commend.h"
|
|
|
|
|
|
|
|
|
|
// 接收buff大小
|
|
#define RECV_BUFF_SIZE 300
|
|
|
|
// 最大接收信号个数
|
|
#define RECV_SEM_MAX_NUM 10
|
|
|
|
// 接收数据超时时间
|
|
#define RECV_EXPIRE_TIME 100
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void recv_irq(void *t,uint8_t d)
|
|
{
|
|
protu_def *p=t;
|
|
p->buff[p->buff_index]=d;
|
|
p->buff_index++;
|
|
switch(p->buff_index){
|
|
case 2:
|
|
if(p->buff[0]==0x59&&p->buff[1]==0x6d)
|
|
{
|
|
p->is_big_data=0;
|
|
p->num_to_recv=4;
|
|
}else{
|
|
p->buff[0]=p->buff[1];
|
|
p->num_to_recv=0;
|
|
}
|
|
break;
|
|
case 4:
|
|
{
|
|
int len=p->buff[2]|(p->buff[3]<<8);
|
|
if(len<65535){
|
|
p->is_big_data=0;
|
|
p->num_to_recv+=len+2;
|
|
}else{
|
|
p->is_big_data=1;
|
|
p->num_to_recv=11;
|
|
}
|
|
}
|
|
break;
|
|
case 11:
|
|
{
|
|
if(p->is_big_data==1)
|
|
{
|
|
int len=p->buff[7]|(p->buff[8]<<8)|(p->buff[9]<<16)|(p->buff[10]<<24);
|
|
p->num_to_recv=4+len+2;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
// 此时一帧数据已完成
|
|
if(p->num_to_recv>0&&p->num_to_recv==p->buff_index)
|
|
{
|
|
//DBG_LOG("recv:%s",str_temp(arr_string(p->buff)));
|
|
rt_sem_release(p->sem);
|
|
}
|
|
}
|
|
|
|
|
|
static void recv_end_irq(void *t,uint32_t len)
|
|
{
|
|
protu_def *p=t;
|
|
p->num_to_recv=len;
|
|
p->buff_index=len;
|
|
p->sem_num++;
|
|
if(p->sem_num<RECV_SEM_MAX_NUM){
|
|
rt_sem_release(p->sem);
|
|
p->recv_tick=rt_tick_get();
|
|
}
|
|
}
|
|
|
|
array_def *protu_decode_str(protu_def *p,array_def *data);
|
|
array_def *protu_encode_str(protu_def *p,array_def *data);
|
|
|
|
|
|
// 查找指定解码器
|
|
codec_item *protu_find_codec(const char *name)
|
|
{
|
|
extern const int codecstruct$$Base;
|
|
extern const int codecstruct$$Limit;
|
|
codec_item *start=(codec_item *)&codecstruct$$Base;
|
|
codec_item *end=(codec_item *)&codecstruct$$Limit;
|
|
for(codec_item *t=start;t<end;t++)
|
|
{
|
|
if(strcmp(t->name,name)==0)
|
|
{
|
|
return t;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
// 返回正在使用的解码器
|
|
codec_item *protu_codec_inuse(protu_def *p)
|
|
{
|
|
return p->codec;
|
|
}
|
|
void protu_codec_set(protu_def *p,codec_item *c)
|
|
{
|
|
p->codec=c;
|
|
}
|
|
|
|
|
|
// 尝试解码
|
|
static array_def *protu_try_decode(protu_def *p,array_def *data)
|
|
{
|
|
array_def *decode_data=0;
|
|
if(p->codec==0||p->codec->decode==protu_decode_str||
|
|
(decode_data=p->codec->decode(p,data),strcmp(p->str_err,"ok")!=0))
|
|
{
|
|
CHECK_DO(decode_data,arr_delete);
|
|
#if defined (__CC_ARM)
|
|
extern const int codecstruct$$Base;
|
|
extern const int codecstruct$$Limit;
|
|
codec_item *start=(codec_item *)&codecstruct$$Base;
|
|
codec_item *end=(codec_item *)&codecstruct$$Limit;
|
|
#elif defined (__GNUC__)
|
|
extern const int __start_codecstruct;
|
|
extern const int __stop_codecstruct;
|
|
codec_item *start=(codec_item *)&__start_codecstruct;
|
|
codec_item *end=(codec_item *)&__stop_codecstruct;
|
|
#endif
|
|
for(codec_item *t=start;t<end;t++)
|
|
{
|
|
decode_data=t->decode(p,data);
|
|
if(strcmp(p->str_err,"ok")==0)
|
|
{
|
|
p->codec=t;
|
|
break;
|
|
}
|
|
else{
|
|
arr_delete(decode_data);
|
|
}
|
|
}
|
|
}
|
|
if(decode_data==0)
|
|
decode_data=arr_creat();
|
|
return decode_data;
|
|
}
|
|
|
|
|
|
|
|
|
|
static void protu_run(void *t)
|
|
{
|
|
protu_def *p=t;
|
|
array_def *data;
|
|
array_def *decode_data;
|
|
uint32_t tick_now;
|
|
while(p->run)
|
|
{
|
|
rt_sem_take(p->sem,RT_WAITING_FOREVER);
|
|
p->sem_num=0;
|
|
if(p->buff_index==0){
|
|
continue;
|
|
}
|
|
tick_now=rt_tick_get();
|
|
if(tick_now-p->recv_tick>RECV_EXPIRE_TIME){
|
|
DBG_LOG("recv data expired.");
|
|
p->num_to_recv=0;
|
|
p->buff_index=0;
|
|
continue;
|
|
}
|
|
//DBG_LOG("protu run");
|
|
data=arr_creat();
|
|
arr_appends(data,p->buff,p->buff_index);
|
|
p->num_to_recv=0;
|
|
p->buff_index=0;
|
|
//DBG_LOG("recv:%s",str_temp(arr_string(data)));
|
|
decode_data=protu_try_decode(p,data);
|
|
//DBG_LOG("decode:%s",str_temp(arr_string(decode_data)));
|
|
if(p->codec)
|
|
emit protu_recv_signal(p,p->codec->name, p->cmd,arr_temp(decode_data),str_temp(str_duplicate(p->str_err)));
|
|
arr_delete(data);
|
|
irq_disable();
|
|
p->num_to_recv=0;
|
|
irq_enable();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 根据设备类型初始化编解码指针
|
|
static void protu_set_endecode_fun(protu_def *u)
|
|
{
|
|
const sys_param_def *par=sys_param();
|
|
if(strcmp(par->device_type,"coder")==0)
|
|
{
|
|
}
|
|
else if(strcmp(par->device_type,"checker")==0)
|
|
{
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
static int protu_init(void)
|
|
{
|
|
const sys_param_def *par=sys_param();
|
|
const char *name="host";
|
|
protu_def *protu=protu_creat(dev_get(name));
|
|
app_variable("protu",protu,0);
|
|
|
|
// 复制一个引用,用于命令行调试
|
|
app_variable("protu2",protu,0);
|
|
return 0;
|
|
}
|
|
app_init_export(protu_init)
|
|
|
|
|
|
|
|
protu_def *protu_creat(uart_def *uart)
|
|
{
|
|
static uint16_t count=0;
|
|
char name[20]={0};
|
|
protu_def *p=calloc(1,sizeof(protu_def));
|
|
param_check(p);
|
|
p->uart=uart;
|
|
sprintf(name,"protu_sem#%d",count);
|
|
p->sem=rt_sem_create(name,0,RT_IPC_FLAG_FIFO);
|
|
p->buff=malloc(RECV_BUFF_SIZE);
|
|
p->run=1;
|
|
p->cmd=0xff;// 命令字不可能是0xff
|
|
protu_set_endecode_fun(p);
|
|
sprintf(name,"protu_t#%d",count);
|
|
rt_thread_t rt_t=rt_thread_create(name,protu_run,p,1024,6,20);
|
|
rt_thread_startup(rt_t);
|
|
int bsp=sys_param()->uartbsp;
|
|
if(bsp==9600)
|
|
p->uart->init(p->uart,9600);
|
|
else
|
|
p->uart->init(p->uart,0);
|
|
//p->uart->set_irq(p->uart,recv_irq,p);
|
|
p->uart->set_end_irq(p->uart,p->buff,RECV_BUFF_SIZE,recv_end_irq,p);
|
|
p->timer=dev_get("timer");
|
|
p->timer->init(p->timer);
|
|
count++;
|
|
return p;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int protu_send(protu_def *p,array_def *data,int timeout_ms)
|
|
{
|
|
//DBG_LOG("send:%s",str_temp(arr_string(data)));
|
|
return p->uart->write(p->uart,arr_data(data),arr_length(data),timeout_ms);
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef struct{
|
|
protu_def *p;
|
|
array_def *t;
|
|
int wnd_tick;// 窗口时间
|
|
int gap;// 发送循环时间
|
|
int send_failed_times;// 失败次数
|
|
uint32_t send_tick_ms;// 发送时的定时器值
|
|
uint32_t send_end_tick_ms;// 发送时的定时器值
|
|
}send_pkt_def;
|
|
|
|
static void protu_send_later(void *ptr)
|
|
{
|
|
send_pkt_def *s=ptr;
|
|
protu_send(s->p,s->t,1000);
|
|
// arr_delete(s->t);
|
|
}
|
|
|
|
static send_pkt_def g_send_pkt;
|
|
|
|
|
|
|
|
// 在指定时间间隙中发送
|
|
// 返回0失败
|
|
static int protu_send_ontime(protu_def *p,send_pkt_def *s)
|
|
{
|
|
uint32_t tick=p->timer->read(p->timer);
|
|
// 根据返回的数据长度计算发送需要的时间,添加1ms的余量
|
|
// 根据协议,每个指令从机的返回数据长度等长,所以需要的时间窗口也相等
|
|
// 253字节需要23ms
|
|
// 每ms传输的字节数为253/23=11,
|
|
// 考虑can总线自动重传保留1/3的余量
|
|
int wnd_tick=((arr_length(s->t)+4)/5+2);
|
|
int delay=tick%(wnd_tick*(p->num));
|
|
int gap=p->rank*wnd_tick;
|
|
int ret=0;
|
|
if(delay<=gap){
|
|
delay=gap-delay;
|
|
}else{
|
|
delay=gap+(wnd_tick*(p->num))-delay;
|
|
}
|
|
if(p->silent!=0){
|
|
// 广播命令在指定时间窗口发送
|
|
//later_execute(protu_send_later,s,delay);
|
|
g_send_pkt.wnd_tick=wnd_tick;
|
|
g_send_pkt.gap=gap;
|
|
while(p->timer->read(p->timer)<(tick+delay));
|
|
// protu_send_later(s);
|
|
g_send_pkt.send_tick_ms=p->timer->read(p->timer);
|
|
ret= protu_send(s->p,s->t,wnd_tick-1);
|
|
g_send_pkt.send_end_tick_ms=p->timer->read(p->timer);
|
|
return ret;
|
|
}else{
|
|
// 单播命令直接发送
|
|
protu_send_later(s);
|
|
return arr_length(s->t);
|
|
}
|
|
}
|
|
|
|
static int protu_send_ontime_loop(protu_def *p,send_pkt_def *s,int retry)
|
|
{
|
|
// g_send_failed_times=0;
|
|
for(int i=0;i<retry;i++)
|
|
{
|
|
if(protu_send_ontime(p,s)!=0){
|
|
break;
|
|
}else{
|
|
g_send_pkt.send_failed_times++;
|
|
}
|
|
}
|
|
arr_delete(s->t);
|
|
return 0;
|
|
}
|
|
static int send_failed(list_def *argv)
|
|
{
|
|
cmd_print("send failed times=%d",g_send_pkt.send_failed_times);
|
|
cmd_print("send_start_tick_ms=%d",g_send_pkt.send_tick_ms);
|
|
cmd_print("send_end_tick_ms=%d",g_send_pkt.send_end_tick_ms);
|
|
cmd_print("send_wnd_tick_ms=%d",g_send_pkt.wnd_tick);
|
|
cmd_print("send_gap_ms=%d",g_send_pkt.gap);
|
|
return 0;
|
|
}
|
|
|
|
commend_export(send_failed,send_failed,"print send_pkt info")
|
|
|
|
|
|
|
|
|
|
|
|
// 槽函数,回复上位机
|
|
void protu_reply_call(protu_def *p,array_def *data)
|
|
{
|
|
param_check(p);
|
|
array_def *t=0;
|
|
if(p->codec)
|
|
t=p->codec->encode(p,data);
|
|
// DBG_LOG("send encode:%s",arr_string(t));
|
|
if(t){
|
|
g_send_pkt.p=p;
|
|
g_send_pkt.t=t;
|
|
protu_send_ontime_loop(p,&g_send_pkt,3);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
// 槽函数,主动上发
|
|
void protu_send_call(protu_def *p,uint8_t cmd,array_def *data)
|
|
{
|
|
array_def *t=0;
|
|
if(cmd!=0){
|
|
p->cmd=cmd;
|
|
if(p->codec)
|
|
t=p->codec->encode(p,data);
|
|
}else if(p->cmd==0)
|
|
{
|
|
// 命令字为0是字符串
|
|
t=protu_encode_str(p,data);
|
|
}
|
|
if(t){
|
|
g_send_pkt.p=p;
|
|
g_send_pkt.t=t;
|
|
protu_send_ontime_loop(p,&g_send_pkt,3);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 字符串解码
|
|
array_def *protu_decode_str(protu_def *p,array_def *data)
|
|
{
|
|
array_def *r=arr_creat();
|
|
param_check(r);
|
|
DBG_LOG("decode for command");
|
|
str_set(p->str_err,"ok");
|
|
p->cmd=0;
|
|
if(str_is_print_str((const char *)arr_data(data),arr_length(data))==1)
|
|
{
|
|
p->silent=0;
|
|
arr_append(data,0);
|
|
arr_appends_from(r,data);
|
|
}else{
|
|
DBG_WARN("data not a string");
|
|
str_set(p->str_err,"not string");
|
|
//arr_remove(data,arr_length(data)-1,1);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
|
|
|
|
// 字符串编码
|
|
array_def *protu_encode_str(protu_def *p,array_def *data)
|
|
{
|
|
array_def *t=arr_creat();
|
|
param_check(t);
|
|
arr_appends_from(t,data);
|
|
return t;
|
|
}
|
|
|
|
|
|
protuc_codec_export(string,protu_decode_str,protu_encode_str);
|
|
|
|
|
|
|