#include "board.h" #include "rtthread.h" #include "debug.h" #include "string.h" #include "dev_flash.h" #include "prot_uc.h" #include "input.h" #include "mystdlib.h" #include "transmit.h" #include "mymisc.h" #include "process.h" #include "tran_for_coder2ch.h" #include "coder_judge.h" /* 赋码操作流程控制 */ // 定义输入通道别名 #define INPUT_STOP_KEY 0 #define INPUT_CHECK_KEY 1 #define INPUT_MARK_END 2 #define INPUT_POS_LEFT 6 #define INPUT_POS_RIGHT 7 // 调试用输入通道别名 //#define INPUT_STOP_KEY 0 //#define INPUT_CHECK_KEY 1 //#define INPUT_MARK_END 2 //#define INPUT_POS_LEFT 3 //#define INPUT_POS_RIGHT 4 // 定义输出通道别名 #define OUTPUT_PUSH_CYLINDER 0 #define OUTPUT_SHELL_BAFFLE 1 #define OUTPUT_CLAMP_CYLINDER 2 #define OUTPUT_LED_OK 3 #define OUTPUT_LED_ERR 4 #define OUTPUT_MARK 7 // 定义总线选择 #define BUS_SELECT_LEFT 0 #define BUS_SELECT_RIGHT 1 // 定义推料气缸方向 #define PUSH_DIR_TO_RIGHT 1 #define PUSH_DIR_TO_LEFT 0 // 定义输出通道数量 #define OUTPUT_CHANNEL_NUM 10 // 急停时不动作 #define SAFE_CHECK(s)\ if(s->stop_state) return // 设置当前步骤 #define SET_STEP(s,d)\ if(s/right_idle){s=right_##d;}else{s=left_##d;} // 校验当前步骤是返回1,不是返回0 #define CHECK_STEP(s,d)\ (s/right_idle)?(s==right_##d):(s==left_##d) // 获取到位传感器通道 #define GET_POS_CHANNEL(s) \ (s/right_idle)?INPUT_POS_RIGHT:INPUT_POS_LEFT // 获取当前使用的总线 #define GET_BUS_CHANNEL(s)\ (s/right_idle)?BUS_SELECT_RIGHT:BUS_SELECT_LEFT // 获取当前推料气缸的方向 #define GET_PUSH_DIR(s)\ (s/right_idle)?PUSH_DIR_TO_LEFT:PUSH_DIR_TO_RIGHT // 重置状态 #define RESET_STEP(s)\ if(soutput[OUTPUT_LED_ERR],0);\ output_set(&s->output[OUTPUT_LED_OK],1);} #define SET_LED_ERR()\ {output_set(&s->output[OUTPUT_LED_ERR],1);\ output_set(&s->output[OUTPUT_LED_OK],0);} #define SET_LED_OFF()\ {output_set(&s->output[OUTPUT_LED_ERR],0);\ output_set(&s->output[OUTPUT_LED_OK],0);} // 设置输出通道状态 #define SET_OUTPUT(c,p)\ output_set(&s->output[c],p); // 复位输出状态 #define RESET_OUTPUT()\ {output_set(&s->output[OUTPUT_SHELL_BAFFLE],0);\ output_set(&s->output[OUTPUT_CLAMP_CYLINDER],0);\ output_set(&s->output[OUTPUT_MARK],0);} typedef struct{ gpioout_def *dev; int state; }output_def; // 设置输出状态 static int output_set(output_def *s,int state) { s->dev->set(s->dev,state); s->state=state; return 0; } typedef enum{ left_idle=0, left_push, left_requst, left_code, right_idle, right_push, right_requst, right_code, }process_step; typedef struct{ int inited; int run; void *tran; array_def *code_data;// 赋码数据 rt_timer_t timer; int busy;// 忙,此时不再响应启动按键 process_step step;// 流程步数0为空闲 int stop_state;// 急停标志,值1时不运行 output_def output[OUTPUT_CHANNEL_NUM]; output_def led; output_def mod1_use; output_def bus_sel; output_def mod_sel; }self_def; static self_def g_self; static const char *g_errinfo_table[]={ "", "左侧到位检测失败", "左侧请求三码数据失败", "左侧赋码失败", "", "右侧到位检测失败", "右侧请求三码数据失败", "右侧赋码失败", }; //static const char *g_errinfo_table[]={ // "", // "left pos check failed", // "left 3code request failed", // "left code failed", // "", // "right pos check failed", // "right 3code request failed", // "right code failed", //}; // 急停按钮响应函数 static void process_stop(void *arg) { self_def *s=arg; s->stop_state=1; SET_OUTPUT(OUTPUT_SHELL_BAFFLE,1); SET_LED_ERR(); DBG_LOG("stop key pressed."); } static void process_run(void *arg) { self_def *s=arg; s->stop_state=0; SET_LED_OFF(); DBG_LOG("stop key unpressed."); } // 异常上报函数 static void process_send_errinfo(void *arg) { self_def *s=arg; const char *err_info=g_errinfo_table[s->step]; int errlen=strlen(err_info); array_def *a=arr_creat(); arr_append(a,s->step); arr_appends(a,err_info,errlen); process_send_signal(s,0x8c,arr_temp(a)); } // 超时响应函数 static void process_timeout(void *arg) { self_def *s=arg; SAFE_CHECK(s); // 上报异常信息 process_send_errinfo(s); DBG_WARN("timeout,errcode=%d",s->step); if(CHECK_STEP(s->step,push)){ // 取消到位回调 input_set_callback_once(GET_POS_CHANNEL(s->step),1,0,0); } // 重置状态 RESET_STEP(s->step); // 复位输出状态 RESET_OUTPUT(); s->busy=0; SET_LED_ERR(); } // 重置定时器 static void process_timer_start(void *arg) { self_def *s=arg; SAFE_CHECK(s); if(s->timer==0) { s->timer=rt_timer_create("proc_tim",process_timeout,s, rt_tick_from_millisecond(5000), RT_TIMER_FLAG_ONE_SHOT|RT_TIMER_FLAG_SOFT_TIMER); } rt_timer_start(s->timer); } // 停止定时器 static void process_timer_stop(void *arg) { self_def *s=arg; if(s->timer){ rt_timer_stop(s->timer); } } // 检测按键响应函数 static void process_check_start(void *arg) { self_def *s=arg; SAFE_CHECK(s); if(s->busy) { DBG_WARN("check is running."); return; } s->busy=1; SET_LED_OFF(); process_timer_start(s); SET_STEP(s->step,push); // 启动推料气缸 SET_OUTPUT(OUTPUT_PUSH_CYLINDER,GET_PUSH_DIR(s->step)); // 设置到位回调 void process_pos(void *arg); input_set_callback_once(GET_POS_CHANNEL(s->step),1,process_pos,s); // 选择当前使用的总线 output_set(&s->bus_sel,GET_BUS_CHANNEL(s->step)); DBG_LOG("check_start key pressed."); } // 到位响应函数 static void process_pos(void *arg) { self_def *s=arg; SAFE_CHECK(s); int chip=coder_extract_chip(0); // 请求三码数据 array_def *a=arr_creat(); arr_append(a,chip); emit process_send_signal(s,0x8b,arr_temp(a)); SET_STEP(s->step,requst); process_timer_start(s); // 打开线夹 SET_OUTPUT(OUTPUT_CLAMP_CYLINDER,1); DBG_LOG("pos in place."); } // 开始注码响应函数 static void process_start_slot(void *arg) { self_def *s=arg; SAFE_CHECK(s); SET_STEP(s->step,code); process_timer_stop(s); DBG_LOG("start code."); } // 赋码结束响应函数 static void process_end_slot(void *obj,int ack,array_def *data) { self_def *s=obj; SAFE_CHECK(s); if(ack){ SET_LED_ERR(); // 发送异常信息 process_send_errinfo(s); // 发送赋码结果 emit tran_send_signal(s->tran,0x82,data); // 复位输出状态 RESET_OUTPUT(); // 复位步骤 RESET_STEP(s->step); s->busy=0; return; }else{ SET_LED_OK(); } // 保存到内部存储 if(s->code_data){ arr_delete(s->code_data); } s->code_data=arr_duplicate(data); // 关闭线夹 SET_OUTPUT(OUTPUT_CLAMP_CYLINDER,0); // 打开挡板 SET_OUTPUT(OUTPUT_SHELL_BAFFLE,1); // 400ms 后开始打标 void process_mark_start(void *arg); later_execute(process_mark_start,s,400); // 5s 后打标结束 void process_mark_end(void *arg); later_execute(process_mark_end,s,5000); } // 开始打标回调函数 static void process_mark_start(void *arg) { self_def *s=arg; SAFE_CHECK(s); SET_OUTPUT(OUTPUT_MARK,1); DBG_LOG("mark start."); } // 打标结束回调函数 static void process_mark_end(void *arg) { self_def *s=arg; SAFE_CHECK(s); // 关闭挡板 SET_OUTPUT(OUTPUT_SHELL_BAFFLE,1); SET_OUTPUT(OUTPUT_MARK,0); // 发送注码结果 if(s->code_data){ emit tran_send_signal(s->tran,0x82,s->code_data); } // 复位输出状态 RESET_OUTPUT(); // 复位步骤 RESET_STEP(s->step); s->busy=0; DBG_LOG("mark end."); } // 线程初始化 static void process_init(void *arg) { self_def *s=arg; // 初始化输出通道 char gpioout_name[]="gpioout0"; for(int i=0;ioutput[i].dev=dev_get(gpioout_name); s->output[i].dev->init(s->output[i].dev); } // 初始化led s->led.dev=dev_get("led"); s->led.dev->init(s->led.dev); // 初始化模块1使用,0把模块1连接到总线1,1不连接到总线1 // 如果要两个总线同时使用,则模块0必须连接到总线2 s->mod1_use.dev=dev_get("mod1_use"); s->mod1_use.dev->init(s->mod1_use.dev); output_set(&s->mod1_use,1); // 初始化总线选择,0选择bus1,1选择bus2 s->bus_sel.dev=dev_get("bus_sel"); s->bus_sel.dev->init(s->bus_sel.dev); output_set(&s->bus_sel,0); // 初始化模块选择,0选择模块0,1选择模块1 s->mod_sel.dev=dev_get("mod_sel"); s->mod_sel.dev->init(s->mod_sel.dev); output_set(&s->mod_sel,0); // 设置急停按钮 input_set_callback_always(INPUT_STOP_KEY,1,process_stop,s); input_set_callback_always(INPUT_STOP_KEY,0,process_run,s); // 设置启动按钮 input_set_callback_always(INPUT_CHECK_KEY,1,process_check_start,s); } static void process_thread(void *arg) { self_def *s=arg; process_init(s); while (s->run) { rt_thread_mdelay(200); output_set(&s->led,1); rt_thread_mdelay(200); output_set(&s->led,0); } } static void init_later(void *t) { void *protu=app_variable("protu",0,0); if(protu){ protu_codec_set(protu,protu_find_codec("ym_checker")); connect(t,process_send_signal,0,protu,protu_send_call); DBG_LOG("process thread created"); }else{ DBG_WARN("can not fond variable \"protu\""); } } static void init_tran(void *t) { self_def *s=t; s->tran=app_variable("tran",0,0); if(s->tran){ connect(s->tran,code2_end_signal,0, t,process_end_slot); connect(s->tran,code2_start_signal,0,t,process_start_slot); }else{ DBG_WARN("can not fond variable \"tran\""); } } static int init_thread(void) { self_def *s=&g_self; s->inited=1; s->run=1; rt_thread_t rt_t=rt_thread_create("process_t",process_thread,s,1024,15,20); rt_thread_startup(rt_t); app_valid_call("protu",init_later,s); app_valid_call("tran",init_tran,s); return 0; } app_init_export(init_thread) // 定义接收上位机命令用于模拟输入通道触发 typedef struct{ ucport_def u; }pccmd_def; void (*g_input_fun_table[])(void *t)={ process_stop, process_run, process_check_start, process_pos, }; static ucport_def *process_pccmd(tran_def *t, uint8_t cmd,array_def *data) { if(arr_length(data)<1){ DBG_WARN("cmd format err."); return 0; } int ret=0; pccmd_def *u=calloc(1,sizeof(pccmd_def)); int table_len=LENGTH(g_input_fun_table); int index=arr_get(data,0); if(index>=0&&index