| 
									
										
										
										
											2023-06-10 11:52:00 +08:00
										 |  |  |  | #include "stdio.h"
 | 
					
						
							|  |  |  |  | #include "rtthread.h"
 | 
					
						
							|  |  |  |  | #include "board.h"
 | 
					
						
							|  |  |  |  | #include "mystdlib.h"
 | 
					
						
							|  |  |  |  | #include "list.h"
 | 
					
						
							|  |  |  |  | #include "mystring.h"
 | 
					
						
							|  |  |  |  | #include "signal.h"
 | 
					
						
							|  |  |  |  | #include "prot_mcu.h"
 | 
					
						
							|  |  |  |  | #include "buff.h"
 | 
					
						
							|  |  |  |  | #include "bytearray.h"
 | 
					
						
							|  |  |  |  | #include "debug.h"
 | 
					
						
							|  |  |  |  | #include "crc.h"
 | 
					
						
							|  |  |  |  | #include "mymisc.h"
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | //#define DBG_WARN(...)
 | 
					
						
							|  |  |  |  | //#define DBG_LOG(...)
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | typedef struct{ | 
					
						
							|  |  |  |  |   uint16_t no; | 
					
						
							|  |  |  |  |   list_def *cmds;//int
 | 
					
						
							|  |  |  |  |   uint8_t addr; | 
					
						
							|  |  |  |  |   uint8_t cmd; | 
					
						
							|  |  |  |  |   array_def *data; | 
					
						
							|  |  |  |  |   int retry; | 
					
						
							|  |  |  |  |   int timeout_ms; | 
					
						
							|  |  |  |  | }protm_slave; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static int protm_slave_sub(void *a,void *b) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   protm_slave *a_=a; | 
					
						
							|  |  |  |  |   protm_slave *b_=b; | 
					
						
							|  |  |  |  |   return a_->addr-b_->addr; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static int protm_slave_del(void *t) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   protm_slave *p=t; | 
					
						
							|  |  |  |  |   CHECK_DO(p->cmds,list_delete); | 
					
						
							|  |  |  |  |   return 0; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static protm_slave *protm_slave_creat(void) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   protm_slave *p=calloc(1,sizeof(protm_slave)); | 
					
						
							|  |  |  |  |   param_check(p); | 
					
						
							|  |  |  |  |   return p; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | array_def *protm_decode(protm_def *p,array_def *data); | 
					
						
							|  |  |  |  | protm_slave *protm_get_slave(protm_def *p,uint8_t addr); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | typedef struct{ | 
					
						
							|  |  |  |  |   array_def *data; | 
					
						
							|  |  |  |  |   int addr; | 
					
						
							|  |  |  |  | }send_data_def; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 定义事件
 | 
					
						
							|  |  |  |  | #define EVENT_RECV      0x1
 | 
					
						
							|  |  |  |  | #define EVENT_SEND      0x2
 | 
					
						
							|  |  |  |  | #define EVENT_TIMEOUT   0x4
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 接收buff大小
 | 
					
						
							|  |  |  |  | #define RECV_BUFF_SIZE  300
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | struct _protm_def{ | 
					
						
							|  |  |  |  |   uart_def *uart; | 
					
						
							|  |  |  |  |   uint8_t *buff; | 
					
						
							|  |  |  |  |   int buff_index; | 
					
						
							|  |  |  |  |   int num_to_recv; | 
					
						
							|  |  |  |  |   rt_event_t event; | 
					
						
							|  |  |  |  |   rt_timer_t timer; | 
					
						
							|  |  |  |  |   int run; | 
					
						
							|  |  |  |  |   char *str_err; | 
					
						
							|  |  |  |  |   list_def *slaves;//protm_slave
 | 
					
						
							|  |  |  |  |   list_def *slaves_addr;//int
 | 
					
						
							|  |  |  |  |   //list_def *send_data;//send_data_def
 | 
					
						
							|  |  |  |  |   int in_send;//在发送状态时为1
 | 
					
						
							|  |  |  |  |   uint8_t recv_cmd; | 
					
						
							|  |  |  |  |   uint8_t recv_src; | 
					
						
							|  |  |  |  |   int send_index;//发送时指向对应的从机
 | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void recv_irq(void *t,uint8_t d) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   protm_def *p=t; | 
					
						
							|  |  |  |  |   p->buff[p->buff_index]=d; | 
					
						
							|  |  |  |  |   p->buff_index++; | 
					
						
							|  |  |  |  |   switch(p->buff_index){ | 
					
						
							|  |  |  |  |     case 2: | 
					
						
							|  |  |  |  |       if(p->buff[0]=='Y'&&p->buff[1]=='e') | 
					
						
							|  |  |  |  |       { | 
					
						
							|  |  |  |  |         p->num_to_recv=4; | 
					
						
							|  |  |  |  |       }else{ | 
					
						
							|  |  |  |  |         p->buff[0]=p->buff[1]; | 
					
						
							|  |  |  |  |         p->buff_index--; | 
					
						
							|  |  |  |  |         p->num_to_recv=0; | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  |       break; | 
					
						
							|  |  |  |  |     case 4: | 
					
						
							|  |  |  |  |       { | 
					
						
							|  |  |  |  |         int len=p->buff[2]|((p->buff[3])<<8); | 
					
						
							|  |  |  |  |         p->num_to_recv=len; | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  |       break; | 
					
						
							|  |  |  |  |     default: | 
					
						
							|  |  |  |  |       break; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   // 此时一帧数据已完成
 | 
					
						
							|  |  |  |  |   if(p->num_to_recv>0&&p->num_to_recv==p->buff_index) | 
					
						
							|  |  |  |  |   { | 
					
						
							|  |  |  |  |     rt_event_send(p->event,EVENT_RECV); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void do_later(void *t) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   protm_def *p=t; | 
					
						
							|  |  |  |  |   DBG_LOG("recv end irq rx_buff=%08x.",p->buff); | 
					
						
							|  |  |  |  |   rt_event_send(p->event,EVENT_RECV); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void recv_end_irq(void *t,uint32_t len) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   protm_def *p=t; | 
					
						
							|  |  |  |  |   p->num_to_recv=len; | 
					
						
							|  |  |  |  |   p->buff_index=len; | 
					
						
							|  |  |  |  |   rt_event_send(p->event,EVENT_RECV); | 
					
						
							|  |  |  |  |   //later_execute(do_later,t,1);
 | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /*
 | 
					
						
							|  |  |  |  | * 与从机通信的串口是串行的,一个通信事务完成之后才能开始下一个通信 | 
					
						
							|  |  |  |  | * 协议层接收的通信事务是并行的,应用层来的通信任务会被放入队列 | 
					
						
							|  |  |  |  | */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void protm_send_next(void *t); | 
					
						
							|  |  |  |  | int protm_send(protm_def *p,protm_slave *s); | 
					
						
							|  |  |  |  | static void protm_send_timeout(void *t); | 
					
						
							|  |  |  |  | static void protm_run(void *t) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   protm_def *p=t; | 
					
						
							|  |  |  |  |   array_def *data; | 
					
						
							|  |  |  |  |   array_def *decode_data; | 
					
						
							|  |  |  |  |   uint32_t ev; | 
					
						
							|  |  |  |  |   while(p->run) | 
					
						
							|  |  |  |  |   { | 
					
						
							|  |  |  |  |     rt_event_recv(p->event,0xffffffff,RT_EVENT_FLAG_OR|RT_EVENT_FLAG_CLEAR,RT_WAITING_FOREVER,&ev); | 
					
						
							|  |  |  |  |     if(ev&EVENT_RECV) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       data=arr_creat(); | 
					
						
							|  |  |  |  |       arr_appends(data,p->buff,p->buff_index); | 
					
						
							|  |  |  |  |       //DBG_LOG("recv:%s",str_temp(arr_string(data)));
 | 
					
						
							|  |  |  |  |       p->num_to_recv=0; | 
					
						
							|  |  |  |  |       p->buff_index=0; | 
					
						
							|  |  |  |  |       decode_data=protm_decode(p,data); | 
					
						
							|  |  |  |  |       if(strcmp(p->str_err,"ok")==0){ | 
					
						
							|  |  |  |  |         //DBG_LOG("slave:%d,",p->recv_src);
 | 
					
						
							|  |  |  |  |         protm_send_next(p); | 
					
						
							|  |  |  |  |         emit protm_recv_signal(p,p->recv_src,p->recv_cmd,arr_temp(decode_data),str_temp(str_duplicate(p->str_err))); | 
					
						
							|  |  |  |  |       }else{ | 
					
						
							|  |  |  |  |         DBG_WARN("slave:%d, %s",p->recv_src,str_temp(arr_string(data))); | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  |       arr_delete(data); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     else if(ev&EVENT_TIMEOUT) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       protm_send_timeout(p); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (ev&EVENT_SEND) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       //DBG_LOG("protmcu:send event.");
 | 
					
						
							|  |  |  |  |       if(p->send_index>=0) | 
					
						
							|  |  |  |  |       { | 
					
						
							|  |  |  |  |         protm_slave *s=(protm_slave *)list_get(p->slaves,p->send_index); | 
					
						
							|  |  |  |  |         //DBG_LOG("send to:%d",s->addr);
 | 
					
						
							|  |  |  |  |         protm_send(p,s); | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     ev=0; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static int protm_find_next(protm_def *p) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   for(int i=0;i<list_length(p->slaves);i++) | 
					
						
							|  |  |  |  |   { | 
					
						
							|  |  |  |  |     p->send_index++; | 
					
						
							|  |  |  |  |     if(p->send_index>=list_length(p->slaves)) | 
					
						
							|  |  |  |  |       p->send_index=0; | 
					
						
							|  |  |  |  |     protm_slave *s=list_get(p->slaves,p->send_index); | 
					
						
							|  |  |  |  |     if(s->data){ | 
					
						
							|  |  |  |  |       return p->send_index; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   p->send_index=-1; | 
					
						
							|  |  |  |  |   return p->send_index; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 发送下一个
 | 
					
						
							|  |  |  |  | static void protm_send_next(void *t) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   protm_def *p=t; | 
					
						
							|  |  |  |  |   //DBG_LOG("timer stop");
 | 
					
						
							|  |  |  |  |   rt_timer_stop(p->timer); | 
					
						
							|  |  |  |  |   protm_slave *s=protm_get_slave(p,p->recv_src); | 
					
						
							|  |  |  |  |   //DBG_LOG("delete data");
 | 
					
						
							|  |  |  |  |   arr_delete(s->data); | 
					
						
							|  |  |  |  |   s->retry=0; | 
					
						
							|  |  |  |  |   // 如果发送列表中有数据,此时发送
 | 
					
						
							|  |  |  |  |   if (protm_find_next(p)>=0) | 
					
						
							|  |  |  |  |   { | 
					
						
							|  |  |  |  |     // DBG_LOG("protmcu:EVENT_SEND.");
 | 
					
						
							|  |  |  |  |     rt_event_send(p->event,EVENT_SEND); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   else{ | 
					
						
							|  |  |  |  |     irq_disable(); | 
					
						
							|  |  |  |  |     p->in_send=0; | 
					
						
							|  |  |  |  |     irq_enable(); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void protm_send_timeout_cb(void *t) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   protm_def *p=t; | 
					
						
							|  |  |  |  |   rt_event_send(p->event,EVENT_TIMEOUT); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 接收超时
 | 
					
						
							|  |  |  |  | static void protm_send_timeout(void *t) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   protm_def *p=t; | 
					
						
							|  |  |  |  |   protm_slave *s=list_get(p->slaves,p->send_index); | 
					
						
							|  |  |  |  |   if(s->retry>0){ | 
					
						
							|  |  |  |  |     s->retry--; | 
					
						
							|  |  |  |  |     //DBG_WARN("slave:%d retry left %d",s->addr,s->retry);
 | 
					
						
							|  |  |  |  |   }else{ | 
					
						
							|  |  |  |  |     DBG_WARN("slave:%d retry timeout,remove the send data.",s->addr); | 
					
						
							|  |  |  |  |     arr_delete(s->data); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   // 如果发送列表中有数据,此时发送
 | 
					
						
							|  |  |  |  |   if (protm_find_next(p)>=0) | 
					
						
							|  |  |  |  |   { | 
					
						
							|  |  |  |  |     // DBG_LOG("protmcu:EVENT_SEND.");
 | 
					
						
							|  |  |  |  |     rt_event_send(p->event,EVENT_SEND); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   else{ | 
					
						
							|  |  |  |  |     irq_disable(); | 
					
						
							|  |  |  |  |     p->in_send=0; | 
					
						
							|  |  |  |  |     irq_enable(); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 发送队列删除条目
 | 
					
						
							|  |  |  |  | static int _list_send_data_del(void *t) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   send_data_def *a=t; | 
					
						
							|  |  |  |  |   arr_delete(a->data); | 
					
						
							|  |  |  |  |   return 0; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | protm_def *protm_creat(uart_def *uart,int *addrs,int num) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   static uint16_t count=0; | 
					
						
							|  |  |  |  |   char name[20]={0}; | 
					
						
							|  |  |  |  |   protm_def *p=calloc(1,sizeof(protm_def)); | 
					
						
							|  |  |  |  |   param_check(p); | 
					
						
							|  |  |  |  |   p->uart=uart; | 
					
						
							|  |  |  |  |   sprintf(name,"protm_event#%d",count); | 
					
						
							|  |  |  |  |   p->event=rt_event_create(name,RT_IPC_FLAG_FIFO); | 
					
						
							|  |  |  |  |   p->buff=malloc(RECV_BUFF_SIZE); | 
					
						
							|  |  |  |  |   p->run=1; | 
					
						
							|  |  |  |  |   p->slaves=list_creat(sizeof(protm_slave),protm_slave_sub,protm_slave_del,0); | 
					
						
							|  |  |  |  |   p->slaves_addr=list_creat_int(); | 
					
						
							|  |  |  |  |   // 创建超时定时器,超过指定时间则不再等待从机返回
 | 
					
						
							|  |  |  |  |   p->timer=rt_timer_create("port_timer",protm_send_timeout_cb,p, | 
					
						
							|  |  |  |  |       rt_tick_from_millisecond(55), | 
					
						
							|  |  |  |  |       RT_TIMER_FLAG_ONE_SHOT|RT_TIMER_FLAG_SOFT_TIMER); | 
					
						
							|  |  |  |  |   list_appends(p->slaves_addr,addrs,num); | 
					
						
							|  |  |  |  |   sprintf(name,"protm_t#%d",count); | 
					
						
							|  |  |  |  |   rt_thread_t rt_t=rt_thread_create(name,protm_run,p,2048,5+count,20); | 
					
						
							|  |  |  |  |   rt_thread_startup(rt_t); | 
					
						
							| 
									
										
										
										
											2023-06-14 22:15:00 +08:00
										 |  |  |  |   p->uart->init(p->uart,0); | 
					
						
							| 
									
										
										
										
											2023-06-10 11:52:00 +08:00
										 |  |  |  |   //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); | 
					
						
							|  |  |  |  |    | 
					
						
							|  |  |  |  |   count++; | 
					
						
							|  |  |  |  |   return p; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 得到指定地址的从机,找不到则添加
 | 
					
						
							|  |  |  |  | protm_slave *protm_get_slave(protm_def *p,uint8_t addr) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   protm_slave *r=0; | 
					
						
							|  |  |  |  |   for(int i=0;i<list_length(p->slaves);i++) | 
					
						
							|  |  |  |  |   { | 
					
						
							|  |  |  |  |     r=list_get(p->slaves,i); | 
					
						
							|  |  |  |  |     if(r->addr==addr) | 
					
						
							|  |  |  |  |       return r; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   r=protm_slave_creat(); | 
					
						
							|  |  |  |  |   r->addr=addr; | 
					
						
							|  |  |  |  |   r->cmds=list_creat_int(); | 
					
						
							|  |  |  |  |   r->no=0; | 
					
						
							|  |  |  |  |   list_append(p->slaves,r); | 
					
						
							|  |  |  |  |   free(r); | 
					
						
							|  |  |  |  |   return list_get(p->slaves,-1); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 设置所有从机流水号
 | 
					
						
							|  |  |  |  | void protm_set_no_all(protm_def *p,uint16_t no,list_def *cmd/*int*/) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   for(int i=0;i<list_length(p->slaves);i++) | 
					
						
							|  |  |  |  |   { | 
					
						
							|  |  |  |  |     protm_slave *s=list_get(p->slaves,i); | 
					
						
							|  |  |  |  |     s->no=no; | 
					
						
							|  |  |  |  |     list_clear(s->cmds); | 
					
						
							|  |  |  |  |     list_append_from(s->cmds,cmd); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 设置单个从机流水号
 | 
					
						
							|  |  |  |  | void protm_set_no(protm_def *p,uint8_t addr,uint16_t no,list_def *cmd/*int*/) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   protm_slave *s=protm_get_slave(p,addr); | 
					
						
							|  |  |  |  |   s->no=no; | 
					
						
							|  |  |  |  |   list_clear(s->cmds); | 
					
						
							|  |  |  |  |   list_append_from(s->cmds,cmd); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 解码
 | 
					
						
							|  |  |  |  | array_def *protm_decode(protm_def *p,array_def *data) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   array_def *r=arr_creat(); | 
					
						
							|  |  |  |  |   param_check(r); | 
					
						
							|  |  |  |  |   str_set(p->str_err,"ok"); | 
					
						
							|  |  |  |  |   if(arr_length(data)<10) | 
					
						
							|  |  |  |  |   { | 
					
						
							|  |  |  |  |     DBG_WARN("recv data len too less."); | 
					
						
							|  |  |  |  |     DBG_WARN("data=%s",str_temp(arr_string(data))); | 
					
						
							|  |  |  |  |     str_set(p->str_err,"recv data len too less."); | 
					
						
							|  |  |  |  |     return r; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   uint8_t src=arr_get(data,4); | 
					
						
							|  |  |  |  |   p->recv_src=src; | 
					
						
							|  |  |  |  |   uint16_t len=arr_get(data,2)|(arr_get(data,3)<<8); | 
					
						
							|  |  |  |  |   uint8_t crc=crc_crc8(arr_data(data),arr_length(data)-1); | 
					
						
							|  |  |  |  |   if(len!=arr_length(data)) | 
					
						
							|  |  |  |  |   { | 
					
						
							|  |  |  |  |     // 如果长度不相等则产生了数据丢失
 | 
					
						
							|  |  |  |  |     DBG_WARN("recv data have lossed."); | 
					
						
							|  |  |  |  |     str_set(p->str_err,"recv data have lossed."); | 
					
						
							|  |  |  |  |     return r; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   uint16_t no=arr_get(data,7)|(arr_get(data,8)<<8); | 
					
						
							|  |  |  |  |   uint16_t h_no=protm_get_slave(p,src)->no; | 
					
						
							|  |  |  |  |   if(no!=h_no) | 
					
						
							|  |  |  |  |   { | 
					
						
							|  |  |  |  |     // 发送一条指令等待其返回,此时流水号应相同
 | 
					
						
							|  |  |  |  |     //DBG_WARN("slave_addr=%d cmd_no error:h_no=%d,no=%d.",src,h_no,no);
 | 
					
						
							|  |  |  |  |     //str_set(p->str_err,"cmd no err.");
 | 
					
						
							|  |  |  |  |     //return r;
 | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   if(crc!=arr_get(data,-1)) | 
					
						
							|  |  |  |  |   { | 
					
						
							|  |  |  |  |     DBG_WARN("recv data crc check error:%02x,%02x.",crc,arr_get(data,-1)); | 
					
						
							|  |  |  |  |     str_set(p->str_err,"crc check err."); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   p->recv_cmd=arr_get(data,6); | 
					
						
							|  |  |  |  |   list_def *cmds=protm_get_slave(p,src)->cmds; | 
					
						
							|  |  |  |  |   if(list_contains(cmds,(int []){p->recv_cmd})==0){ | 
					
						
							|  |  |  |  |     // 命令号校验不对
 | 
					
						
							|  |  |  |  |     DBG_WARN("cmd check err.cmds=%s,recv_cmd=%d",tappend(list_string(cmds),0),p->recv_cmd); | 
					
						
							|  |  |  |  |     str_set(p->str_err,"cmd check err."); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   arr_delete(r); | 
					
						
							|  |  |  |  |   return arr_mid(data,9,len-10); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 编码
 | 
					
						
							|  |  |  |  | array_def *protm_encode(protm_def *p,uint8_t dst,uint8_t cmd,list_def *comp_cmd/*int*/,array_def *data) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   array_def *t=arr_creat(); | 
					
						
							|  |  |  |  |   param_check(t); | 
					
						
							|  |  |  |  |   uint16_t len=arr_length(data)+10; | 
					
						
							|  |  |  |  |   protm_slave *slave=protm_get_slave(p,dst); | 
					
						
							|  |  |  |  |   slave->no++; | 
					
						
							|  |  |  |  |   protm_set_no(p,dst,slave->no,comp_cmd); | 
					
						
							|  |  |  |  |   arr_append(t,'Y'); | 
					
						
							|  |  |  |  |   arr_append(t,'e'); | 
					
						
							|  |  |  |  |   arr_append(t,len&0xff); | 
					
						
							|  |  |  |  |   arr_append(t,len>>8); | 
					
						
							|  |  |  |  |   arr_append(t,0);// 源地址
 | 
					
						
							|  |  |  |  |   arr_append(t,dst);// 目标地址
 | 
					
						
							|  |  |  |  |   arr_append(t,cmd);// 命令码
 | 
					
						
							|  |  |  |  |   arr_append(t,slave->no&0xff); | 
					
						
							|  |  |  |  |   arr_append(t,slave->no>>8); | 
					
						
							|  |  |  |  |   arr_appends_from(t,data); | 
					
						
							|  |  |  |  |   arr_append(t,crc_crc8(arr_data(t),arr_length(t))); | 
					
						
							|  |  |  |  |   return t; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 发送数据,发送前先开启超时定时器
 | 
					
						
							|  |  |  |  | int protm_send(protm_def *p,protm_slave *s) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   rt_tick_t tick=0; | 
					
						
							|  |  |  |  |   //DBG_LOG("send:%s",str_temp(arr_string(s->data)));
 | 
					
						
							|  |  |  |  |   tick=rt_tick_from_millisecond(s->timeout_ms); | 
					
						
							|  |  |  |  |   rt_timer_control(p->timer,RT_TIMER_CTRL_SET_TIME,&tick); | 
					
						
							|  |  |  |  |   //DBG_LOG("timer start");
 | 
					
						
							|  |  |  |  |   rt_timer_start(p->timer); | 
					
						
							|  |  |  |  |   if(s->data==0) | 
					
						
							|  |  |  |  |   { | 
					
						
							|  |  |  |  |     DBG_WARN("addr=%d,d->data=0",s->addr); | 
					
						
							|  |  |  |  |     return 0; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   return p->uart->write(p->uart,arr_data(s->data),arr_length(s->data)); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 槽函数,发送数据到指定地址
 | 
					
						
							|  |  |  |  | void protm_send_call(protm_def *p,uint8_t addr,uint8_t cmd,list_def *comp_cmd/*int*/,array_def *data,int timeout_ms,int retry) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   param_check(p); | 
					
						
							|  |  |  |  |   if(list_contains(p->slaves_addr,(int []){addr})==1) | 
					
						
							|  |  |  |  |   { | 
					
						
							|  |  |  |  |     array_def *t=0; | 
					
						
							|  |  |  |  |     t=protm_encode(p,addr,cmd,comp_cmd,data); | 
					
						
							|  |  |  |  |     //protm_send(p,t);
 | 
					
						
							|  |  |  |  |     //arr_delete(t);
 | 
					
						
							|  |  |  |  |     // 添加到发送队列,发送必须等到回应或超时才能发送下一个
 | 
					
						
							|  |  |  |  |     //DBG_LOG("send to:%d",addr);
 | 
					
						
							|  |  |  |  |     send_data_def sd={0}; | 
					
						
							|  |  |  |  |     sd.addr=addr;sd.data=t; | 
					
						
							|  |  |  |  |     protm_slave *s=protm_get_slave(p,addr); | 
					
						
							|  |  |  |  |     s->retry=retry; | 
					
						
							|  |  |  |  |     s->timeout_ms=timeout_ms; | 
					
						
							|  |  |  |  |     if(s->data){ | 
					
						
							|  |  |  |  |       DBG_WARN("s->data not null."); | 
					
						
							|  |  |  |  |       arr_delete(s->data); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     s->data=t; | 
					
						
							|  |  |  |  |     if(p->in_send==0){ | 
					
						
							|  |  |  |  |       irq_disable(); | 
					
						
							|  |  |  |  |       p->in_send=1; | 
					
						
							|  |  |  |  |       irq_enable(); | 
					
						
							|  |  |  |  |       protm_find_next(p); | 
					
						
							|  |  |  |  |       //DBG_LOG("send call");
 | 
					
						
							|  |  |  |  |       rt_event_send(p->event,EVENT_SEND); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 返回1表示此地址可以发送到这个端口
 | 
					
						
							|  |  |  |  | int protm_contains(protm_def *p,uint8_t addr) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   param_check(p); | 
					
						
							|  |  |  |  |   return list_contains(p->slaves_addr,(int []){addr}); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 |