/******************************************************************** 版权所有: 文件版本: V1.00 文件名称: IEC_LINK.c 生成日期: 2010年04月26日 作 者:hhw 使用范围: 功 能: 装置级联处理 更新信息: 更新日志1 修改者: 修改日期: 修改内容: 修改原因: *********************************************************************/ #include "head.h" volatile int g_net_104link_data[CFG_LINK_104_NUM]; // 级联104初始化标志 int g_link104_init_ok[CFG_LINK_104_NUM]; u8 g_link104_buf[CFG_LINK_104_NUM][IEC_BUF_LEN]; IECLINK_DEF g_link_104[CFG_LINK_104_NUM]; LINKYK_DEF g_lnk_yk[SWITCH_NUM_EXT_PUB]; LINKPAR_DEF g_link_par[SWITCH_NUM_EXT_PUB]; u8 g_link_par_cnt=0; /*当前遥参游标*/ #ifdef IEC_NOLINK_NO_CALLYX IEC_LINK_REG g_link_comm; #endif int get_index_setno(u8 group_type,u16 setno) { int i=0; for(i=0;inum;i++) { rt_printf("%02d:cp_m[%x],cp_s[%x],len=%d\r\n",i,msg->base_data[i].cp_m,msg->base_data[i].cp_s,msg->base_data[i].val_iec.size); } } par_queque_m * lnk_msg_ypara_head_s(u8 chnl) { u8 ch=0; u8 index=0; ch=(chnl>>5)&0x07; index = chnl&0x1f; if(ch >= 2) /*串口*/ { ch -= 2; /*串口号*/ if((ch < CFG_UART_NUM_MAX) && (tRunPara.tUartPara[ch].wProtocol == PROTOCOL_101_M)) { IECLINK_DEF *pt; pt=(IECLINK_DEF *)g_tRsComm[ch].ptBuf; return &pt->par_queue; } #ifdef FUN_IEC103_STA else if((ch < CFG_UART_NUM_MAX) && (tRunPara.tUartPara[ch].wProtocol == PROTOCOL_103_M || tRunPara.tUartPara[ch].wProtocol == PROTOCOL_YZ103_M)) { IECLINK_DEF *pt; pt=(IECLINK_DEF *)g_tRsComm[ch].ptBuf; return &pt->par_queue; } #endif } else /*网口*/ { index = index - 1; /*级联网络号*/ // 以太网通道 if(index < CFG_LINK_104_NUM) { IECLINK_DEF *pt; pt=&g_link_104[index]; if(g_link104_init_ok[index] == 0) { return 0; } else { return &pt->par_queue; } } } return 0; } msg_data_struct * lnk_msg_ypara_head_m(u8 chnl) { u8 ch=0; ch = chnl; if(ch < CFG_UART_NUM_MAX) /*串口子站*/ { IEC101_DEF *pt101; pt101 = (IEC101_DEF *)g_tRsComm[ch].ptBuf; if((tRunPara.tUartPara[ch].wProtocol==PROTOCOL_101) || (tRunPara.tUartPara[ch].wProtocol==PROTOCOL_101_PH)) // 串口级联规约 { return &pt101->msg_ypara_recv; } } else if(ch < CFG_UART_NUM_MAX + CFG_ETH_MAX_LOGIC) /*网口104*/ { IEC104_DEF *pt104; ch = chnl-CFG_UART_NUM_MAX; pt104=&g_t104[ch]; return &pt104->msg_ypara_recv; } return 0; } int get_stbl_index_s(u16 parId) { int i=0; for(i=0;i级联主站(msg),sport=%x,dport=%x,type=%d\r\n",sport,dport,msg->type); { for(i=0;ipar_queue; temp_par.dport = msg->dport; temp_par.sport = 0x1F; /*级联源口号0x1F表示不用返回*/ temp_par.flag = 0x81; add_data_queque(&par_queque->queue,(u8 *)&temp_par,OVER_QUEUE); } return 0; } } else { rt_printf("常规:::::::子站--->级联主站(msg),sport=%x,dport=%x,type=%d\r\n",sport,dport,msg->type); par_queque = lnk_msg_ypara_head_s(dport); if(par_queque == 0) { //sprintf(buf,"级联遥参:未找到从设备通道(link_ch=%02x)",dport); //log_str_time(LOG_OPERATE,buf,0,0); rt_printf("级联遥参:未找到从设备通道(link_ch=%02x)\r\n",dport); return -1; } //print_msg_base(msg); temp_par.dport = msg->dport; temp_par.sport = msg->sport; temp_par.flag = 0x81; add_data_queque(&par_queque->queue,(u8 *)&temp_par,OVER_QUEUE); rt_printf("----par_queue num=%d\r\n",get_queue_count(&par_queque->queue)); return 0; } return -1; } int rec_msg_ypara_return(msg_data_struct *msg,u8 sport,u8 dport) { msg_data_struct *msg_ypara; rt_printf("级联主站---子站(msg),sport=%d,dport=%d,type=%d\r\n",sport,dport,msg->ypara_msg.type); if((dport & 0x1F) == 0x1F) /*广播的不返回*/ { return 0; } msg_ypara = lnk_msg_ypara_head_m(dport); if(msg_ypara == 0) { rt_printf("级联主站---子站(msg)通道失败\r\n"); return -1; } //print_msg_base(msg); *msg_ypara = *msg; msg_ypara->flag = 1; return 0; } void lnk_slave_ypara_write(IECLINK_DEF *pt,u8 chnl,u8 vsq,u8 cot,u8 *ps,bool b104) { int i =0; u8 num=0; u8 off=0; u8 len =0; u16 link_cp=0; u8 pdi=0; msg_data_struct *msg_data; msg_ypara_data_struct *msg; iec_val_struct v; num=(vsq&0x7f); msg_data = &pt->temp_par; msg = &pt->temp_par.ypara_msg; memset(msg,0,sizeof(msg_ypara_data_struct)); off += 2; /*定值区*/ pdi = ps[off++]; /*参数特征标识*/ for(i=0;ibase_data[msg->num].val_iec = v; msg->base_data[msg->num].cp_s = link_cp; msg->base_data[msg->num].cp_m = 0; msg->num++; } if((pdi&0xc0)==0) // 定值固化 { if(cot & IEC_COT_PN) { msg->cmd = YP_EXE_FAULT; } else { msg->cmd = YP_EXE_RETURN; } } else if((pdi&0xc0)==0x40) /*撤销*/ { if(cot & IEC_COT_PN) { msg->cmd = YP_CANCEL_FAULT; } else { msg->cmd = YP_CANCEL_RETURN; } } else // 参数预置 { if(cot & IEC_COT_PN) { msg->cmd = YP_SEL_FAULT; } else { msg->cmd = YP_SEL_RETURN; } } msg->type = modify_set; msg_data->dport = pt->sport; msg_data->sport = chnl; rec_msg_ypara_return(msg_data,msg_data->sport,msg_data->dport); } void lnk_slave_ypara_read(IECLINK_DEF *pt,u8 chnl,u8 vsq,u8 cot,u8 *ps,bool b104) { int i =0; u8 num=0; u8 off=0; u16 link_cp=0; int index=0; SET_PARA_VAL *tmp_pval; u8 type=0,len=0; char str[64]; num=(vsq&0x7f); off += 2; /*定值区*/ off++; /*参数特征标识*/ if(cot & IEC_COT_PN) { return ; } for(i=0;idatatype = type; tmp_pval->len = len; memcpy(tmp_pval->str,str,len); //rt_printf("M104_read_unpack::chnl=0x%x,di=0x%x,tmp_pval[%d]:datatype=0x%x,len=0x%x\r\n",chnl,link_cp,index,tmp_pval->datatype,tmp_pval->len); } else { off += len; } } } void lnk_slave_ypara_updata(IECLINK_DEF *pt,u8 *ps) { u8 flag=0; ps += 3; /*信息体地址*/ flag = ps[0]; if(flag) { set_read_all(pt); } } void set_read_all(IECLINK_DEF *pt) { LNK_STATUS *ptlnk = &pt->tlnk; //rt_printf("!!!!!!!![%d]----set\r\n,",pt->chnl); ptlnk->bSet_all=true; } void clear_read_all(IECLINK_DEF *pt) { LNK_STATUS *ptlnk = &pt->tlnk; //rt_printf("!!!!!!!![%d]----clear\r\n,",pt->chnl); ptlnk->bSet_all=false; } void print_tPara_val(int index) { SET_PARA_VAL *tmp_pval; float val=0; if(index >=MAX_SET_NUMBER) return; tmp_pval = &tPara_val[index]; switch(tmp_pval->datatype) { case BOOL_R: case TINY_R: case UTINY_R: val=tmp_pval->str[0]; rt_printf("-----val[%f-[%02x]]\r\n",val,tmp_pval->str[0]); break; case UINT_R: case INT_R: case LONG_R: case ULONG_R: val=(tmp_pval->str[0]+(tmp_pval->str[1]<<8)+(tmp_pval->str[2]<<16)+(tmp_pval->str[3]<<24)); rt_printf("-----val[%f-[%02x-%02x-%02x-%02x]]\r\n",val,tmp_pval->str[0],tmp_pval->str[1],tmp_pval->str[2],tmp_pval->str[3]); break; case SHORT_R: case USHORT_R: val=(tmp_pval->str[0]+(tmp_pval->str[1]<<8)); rt_printf("-----val[%f-[%02x-%02x]]\r\n",val,tmp_pval->str[0],tmp_pval->str[1]); break; case FLOAT_R: { union{ float ff; u8 tt[4]; }ff; ff.tt[3]=tmp_pval->str[0]; ff.tt[2]=tmp_pval->str[1]; ff.tt[1]=tmp_pval->str[2]; ff.tt[0]=tmp_pval->str[3]; val=ff.ff; rt_printf("-----val[%f-[%02x-%02x-%02x-%02x]]\r\n",val,tmp_pval->str[0],tmp_pval->str[1],tmp_pval->str[2],tmp_pval->str[3]); break; } } } #endif u32 * lnk_get_ch_par_head(u8 chnl) { u8 ch=chnl; u8 index=0; ch=(chnl>>5)&0x07; index = chnl&0x1f; if(ch>=2) // 串口 { ch -=2; if(ch < CFG_LINK_101_NUM &&( tRunPara.tUartPara[ch].wProtocol == PROTOCOL_101_M||tRunPara.tUartPara[ch].wProtocol == PROTOCOL_101_PH_M)) { IECLINK_DEF *pt; pt=(IECLINK_DEF *)g_tRsComm[ch].ptBuf; return &pt->par_send_flag; } } else /*网口*/ { index = index - 1; /*级联网络号*/ // 以太网通道 if(index < CFG_LINK_104_NUM) { IECLINK_DEF *pt; pt=&g_link_104[index]; return &pt->par_send_flag; } } return 0; } u32 * lnk_get_ch_head(u8 chnl) { u8 ch=chnl; ch=(chnl>>5)&0x07; if(ch>=2) // 串口 { ch -=2; if(ch < CFG_LINK_101_NUM &&( tRunPara.tUartPara[ch].wProtocol == PROTOCOL_101_M||tRunPara.tUartPara[ch].wProtocol == PROTOCOL_101_PH_M)) { IECLINK_DEF *pt; pt=(IECLINK_DEF *)g_tRsComm[ch].ptBuf; return &pt->yk_send_flag; } else if(ch < CFG_LINK_101_NUM && tRunPara.tUartPara[ch].wProtocol == PROTOCOL_MODBUS) { MODBUS_DEF *pt; pt= (MODBUS_DEF *)g_tRsComm[ch].ptBuf; return &pt->yk_send_flag; } #if defined BATTERY_WITH_COMM && defined FUNC_SEL_BAT_MODULE else if(ch < CFG_LINK_101_NUM && tRunPara.tUartPara[ch].wProtocol == PROTOCOL_PWRM) { pwdmodlue_def *pt; pt= (pwdmodlue_def *)g_tRsComm[ch].ptBuf; return &pt->yk_sendflag; } #endif } else // 网口 { ch=chnl-1; // 以太网通道 if(ch < CFG_LINK_104_NUM) { IECLINK_DEF *pt; pt=&g_link_104[ch]; return &pt->yk_send_flag; } } return 0; } void lnk_call_all(void) { int i; for(i=0; islave_num;j++) { pt->tsla[j].tlnksave.bCallAll=true; } pt->tlnk.bCallAll=true; } } } void lnk_rst_set(void) { int i; for(i=0; itlnk.brst=true; for(j=0;jslave_num;j++) { pt->tsla[j].tlnksave.brst=true; } } } } void lnk_update_time_all(void) { int i; for(i=0; islave_num;j++) { pt->tsla[j].tlnksave.bSetTime=true; } pt->tlnk.bSetTime = true; } } } void lnk_slave_yx(u8 ch,u8 ti,u8 vsq,u8 cot,u8 al,u8 *ps) { u8 num=(vsq&0x7f); u8 ngd=(vsq&0x80); u8 v; u16 cp; int i; LINK_TABLE * lt; //struct di_table *dt; // 获取首地址 cp =(ps[0]+(ps[1]<<8)); ps+=al; // 循环处理每个数据 for(i=0;iowner,lt->indexno,v); } // 根据ngd修正后续地址 if(ngd) { cp++; } else { cp=(ps[0]+(ps[1]<<8)); ps+=al; } } } void lnk_find_yx_iec_no(u8 ch, u8 *ps)// 寻找级联点号对应的点表中点号,并替换 { int i; u16 di; di=ps[0]+(ps[1]<<8); for(i=0;idi_num;i++) { if(g_di_table[i].link_ch!=0) { if((g_di_table[i].link_cp==di) && (g_di_table[i].link_ch == ch)) // 级联点号有对应的点表值 { ps[0]=(u8)g_di_table[i].cp; ps[1]=(u8)(g_di_table[i].cp>>8); //rt_printf("\r\n yx %04x-->%04x",g_di_table[i].cp,di); break; } } } } void lnk_find_yc_iec_no(u8 ch, u8 *ps,u8 baddr3,u8 yc_type)// 寻找级联点号对应的点表中点号,并替换 { int i; u16 di; di=ps[0]+(ps[1]<<8); for(i=0;iac_num;i++) { if(g_ac_table[i].link_ch!=0) { if((g_ac_table[i].link_cp==di) && (g_ac_table[i].link_ch == ch)) // 级联点号有对应的点表值 { ps[0]=(u8)g_ac_table[i].cp; ps[1]=(u8)(g_ac_table[i].cp>>8); #ifdef IEC_EVENT_YC_RATE if(pRunSet->bTT_EV_YCRate) { union{ float ff; u8 tt[4]; }ff; u8 *pdat; u16 v=0; pdat = &ps[2]; if(baddr3) pdat = &ps[3]; if(yc_type == 13) { #ifdef MODE_LITTLE_ENDIAN ff.tt[0]=pdat[0]; ff.tt[1]=pdat[1]; ff.tt[2]=pdat[2]; ff.tt[3]=pdat[3]; #else ff.tt[3]=pdat[0]; ff.tt[2]=pdat[1]; ff.tt[1]=pdat[2]; ff.tt[0]=pdat[3]; #endif } else { ff.ff = pdat[0] + (pdat[1]<<8); } rt_printf("fault_yc_two::%f\r\n",ff.ff); ff.ff *= ((float)g_ac_table[i].rate/65536.0); //系数转换 v = ff.ff; rt_printf("fault_yc_one::%f\r\n",ff.ff); if(yc_type == 13) { #ifdef MODE_LITTLE_ENDIAN pdat[0] = ff.tt[0]; pdat[1] = ff.tt[1]; pdat[2] = ff.tt[2]; pdat[3] = ff.tt[3]; #else pdat[0] = ff.tt[3]; pdat[1] = ff.tt[2]; pdat[2] = ff.tt[1]; pdat[3] = ff.tt[0]; #endif } else { pdat[0] = (u8)v; pdat[1] = (u8)(v>>8); } } #endif //rt_printf("\r\n yc %04x-->%04x",g_ac_table[i].cp,di); break; } } } } int EventInfoAddr101_to_104(BYTE *frame,BYTE *pbuf) { int len; int yc_num,yc_type; int i,buf_pos=0,frame_pos=0; memcpy(pbuf,frame,4); buf_pos += 4; frame_pos += 4; memcpy(&pbuf[buf_pos],&frame[frame_pos],8); buf_pos += 8; frame_pos += 8; yc_num = frame[frame_pos]; yc_type = frame[frame_pos+1]; memcpy(&pbuf[buf_pos],&frame[frame_pos],2); buf_pos += 2; frame_pos += 2; for(i=0;i=IEC_FAULT_FRAMELEN-1)return; num=pdat[0]; pdat+=2; for(i=0;i IEC_FAULT_FRAMELEN-1) continue; memcpy(&pt->tfault.data[pt->tfault.head][1],tmp_buf,frame_len); pt->tfault.data[pt->tfault.head][0]=frame_len; } else { memcpy(&pt->tfault.data[pt->tfault.head][1],ps,len); pt->tfault.data[pt->tfault.head][0]=len; } pt->tfault.head++; if(pt->tfault.head==pt->tfault.tail) { pt->tfault.tail++; } } } for(i=0;i IEC_FAULT_FRAMELEN-1) continue; memcpy(&pt->tfault.data[pt->tfault.head][1],tmp_buf,frame_len); pt->tfault.data[pt->tfault.head][0]=frame_len; } else { memcpy(&pt->tfault.data[pt->tfault.head][1],ps,len); pt->tfault.data[pt->tfault.head][0]=len; } rt_printf("\r\n fault lenth=%d head=%d",len,pt->tfault.head); pt->tfault.head++; if(pt->tfault.head==pt->tfault.tail) { pt->tfault.tail++; } } } // void lnk_slave_yc(u8 ch,u8 ti,u8 vsq,u8 al,u8 *ps) { u8 num=(vsq&0x7f); u8 ngd=(vsq&0x80); u16 cp; int i; LINK_TABLE * lt; struct ac_table *at; u8 ycQDS=0; qs16 v; #ifndef MODE_LITTLE_ENDIAN u8 ycval[4]; #endif // 获取首地址 cp=(ps[0]+(ps[1]<<8)); ps+=al; // 循环处理每个数据 for(i=0;itbl_index]; if(at->owner == 0) { g_sw_pub.ac_in[at->indexno-1] = v; } else { g_sw[at->owner-1].ac_in[at->indexno-1] = v; g_sw[at->owner-1].link_qds[at->indexno-1] = ycQDS; } } // 根据ngd修正后续地址 if(ngd) { cp++; } else { cp=(ps[0]+(ps[1]<<8)); ps+=al; } } } // void lnk_slave_dd(u8 ch,u8 ti,u8 vsq,u8 cot,u8 al,u8 *ps) { u8 num=(vsq&0x7f); u8 ngd=(vsq&0x80); u16 cp; int i; LINK_TABLE * lt; struct dd_table *dt; struct rtc_time_t ct; u8 QDS; bool bchange=false; float v; #ifndef MODE_LITTLE_ENDIAN u8 ycval[4]; #endif // 获取首地址 cp=(ps[0]+(ps[1]<<8)); ps+=al; // 循环处理每个数据 for(i=0;itbl_index]; #ifdef METERING_ENERGY if((dt->owner >0)&&(pRunSet->dd_calc_mode == 2)) #else if(dt->owner >0) #endif { #ifdef M_IT_TC int j=0; if(bchange)//级联突发上送 { for(j=0;jowner-1].dd[dt->indexno-1].bsend101[j] = true; } for(j=0;jowner-1].dd[dt->indexno-1].bsend104[j] = true; } } #endif g_sw[dt->owner-1].dd[dt->indexno-1].fv= v; g_sw[dt->owner-1].dd[dt->indexno-1].ct= ct; g_sw[dt->owner-1].dd[dt->indexno-1].bchanged= bchange; // 记录遥测值 //rt_printf_time("owner=%d,index=%04x,v=%.4f.\r\n",dt->owner-1,dt->indexno,v); } } // 根据ngd修正后续地址 if(ngd) { cp++; } else { cp=(ps[0]+(ps[1]<<8)); ps+=al; } } } void lnk_slave_soe(IECLINK_DEF *pt,u8 ch,u8 ti,u8 vsq,u8 al,u8 *ps) { u8 num=(vsq&0x7f); u8 ngd=(vsq&0x80); u8 v; u16 cp; int i; LINK_TABLE * lt; // struct di_table *dt; struct rtc_time_t rt; struct timespec ts; // 获取首地址 cp=(ps[0]+(ps[1]<<8)); ps+=al; // 循环处理每个数据 for(i=0;itbl_index]; sw_di_set(lt->owner,lt->indexno,v); rtc_to_timespec(&rt,&ts); v = lt->is_inverse ? ((~v)&0x03) : v; soe_record_lnk(lt->cp ,v,&ts,(s32)lt,lt->is_mix,lt->cp_s); } // 根据ngd修正后续地址 if(ngd) { cp++; } else { cp=(ps[0]+(ps[1]<<8)); ps+=al; } } } extern u8 get_par_link_data(BYTE *out,BYTE *in,BYTE parNum,u8 ti);//test void lnk_slave_par(u8 ch,u8 ti,u8 cot,u8 al,u8 *ps,u8 vsq) { u8 ti_m=ti; u8 v,yktype; u16 cp; LINK_TABLE * lt; //struct do_table *dt; LINKPAR_DEF *par; u8 *pbuf=ps; int i; // 获取地址和值 cp=(ps[0]+(ps[1]<<8)); ps+=al; v=*ps++; // 查找点表,如果找到,保存。 lt = tbl_link_do(ch,cp); lt = &g_lt_do[1]; #ifdef YC_QUANTITY rt_printf("\r\nch=%02x parAddr=%02x vsq=%d\r\n",(ch>>4),cp-(pRunSet->dYC_num*((ch&0x0f)-1)),vsq); cp=cp-(pRunSet->dYC_num*((ch&0x0f)-1)) ;//点表转换 #else rt_printf("\r\nch=%02x parAddr=%02x vsq=%d\r\n",(ch>>4),cp-(FOS_PAR_SW_NUM*((ch&0x0f)-1)),vsq); cp=cp-(FOS_PAR_SW_NUM*((ch&0x0f)-1)) ;//点表转换 #endif for(i=0;idata[IECLINK_YK_ACK].ti == 0)) { yktype = IECLINK_YK_ACK; par->data[yktype].ti=ti; par->data[yktype].cot=7; par->data[yktype].len=v; par->flag[yktype] = true; } #endif yktype = cot==10 ? IECLINK_YK_END : IECLINK_YK_ACK; if(ti == FOS_PAR_SET_MUL_EXT) { ti_m = FOS_PAR_SET_MUL; } else if(ti == FOS_PAR_SET_ONE_EXT) { ti_m = FOS_PAR_SET_ONE; } else if(ti == FOS_PAR_READ_ONE_EXT) { ti_m = FOS_PAR_READ_ONE; } else if(ti == FOS_PAR_READ_MUL_EXT) { ti_m = FOS_PAR_READ_MUL; } par->data[yktype].ti=ti_m; par->data[yktype].cot=cot; par->data[yktype].len=1; par->data[yktype].vsq=vsq; // if(al == 2) { par->data[yktype].len = get_par_link_data(&par->data[yktype].buf[0] ,pbuf,vsq, ti_m); } else { par->data[yktype].len = get_par_link_data_dz(&par->data[yktype].buf[0] ,pbuf,vsq, ti_m); } par->flag[yktype] = true; rt_printf("级联遥参上行:(ch=%02x,cp_s=%04x,ti=%02x,cot=%02x,len=%02x yktype=%02x \r\n",ch,g_link_par[i].cp_s,ti_m,cot,par->data[yktype].len,yktype); #ifdef FUNC_MORE_PREREAD g_link_par[i].flag[IECLINK_YK_SND] = false; #endif return ; } } rt_printf_time("lnk_slave_par:查找级联表失败 ch=%02x,cp=%04x.\r\n",ch,cp); return ; } void lnk_slave_yk(u8 ch,u8 ti,u8 cot,u8 al,u8 *ps) { u8 v,yktype; u16 cp; LINK_TABLE * lt; struct do_table *dt; LINKYK_DEF *yk; char buf[128]; // 获取地址和值 cp=(ps[0]+(ps[1]<<8)); ps+=al; v=*ps++; // 查找点表,如果找到,保存。 lt = tbl_link_do(ch,cp); if(lt) { dt = &g_do_table[lt->tbl_index]; yk = &g_lnk_yk[dt->owner]; if(cp != yk->cp_s) { rt_printf_time("lnk_slave_yk err:cp=%04x,cp_s=%04x",cp,yk->cp_s); return; } // 由于有些从设备只发10,不发07,所以在10时将 07 10 报文同时发出。 if(cot == 10 && (yk->data[IECLINK_YK_ACK].ti == 0)) { yktype = IECLINK_YK_ACK; yk->data[yktype].ti=ti; yk->data[yktype].cot=7; yk->data[yktype].v=v; yk->flag[yktype] = true; } yktype = cot==10 ? IECLINK_YK_END : IECLINK_YK_ACK; yk->data[yktype].ti=ti; yk->data[yktype].cot=cot; yk->data[yktype].v=v; yk->flag[yktype] = true; sprintf(buf,"级联遥控上行:(ch=%02x,cp_s=%04x,cp_m=%04x,ti=%02x,cot=%02x,v=%02x)",ch,lt->cp_s,dt->cp,ti,cot,v); log_str_time(LOG_OPERATE,buf,0,0); rt_printf_time("%s\r\n",buf); } else { rt_printf_time("lnk_slave_yk:查找级联表失败 ch=%d,cp=%04x.\r\n",ch,cp); } } //定值参数&&... 数据级联转发 int lnk_master_par(struct do_table *pdt,u8 ti,u8 cot,u8 len,BYTE *datBuf,u8 vsq) { u8 yktype; LINKPAR_DEF * par; char buf[128]; u32 *par_send_flag; // 获取对应通道的结构,获取失败,直接返回 par_send_flag = lnk_get_ch_par_head(pdt->link_ch); if(par_send_flag == 0) { sprintf(buf,"级联:未找到从设备通道(cp=%04x,link_ch=%02x,link_cp=%04x)",pdt->cp,pdt->link_ch,pdt->link_cp); log_str_time(LOG_OPERATE,buf,0,0); rt_printf_time("%s\r\n",buf); return -1; } #ifdef FUNC_MORE_PREREAD par = &g_link_par[g_link_par_cnt]; *par_send_flag |= 1<owner); par = &g_link_par[pdt->owner]; #endif // 清对应数据结构 memset(par,0,sizeof(g_link_par[0])); // 赋值 yktype = IECLINK_YK_SND; par->data[yktype].ti=0xff;//??? par->data[yktype].vsq=vsq; par->data[yktype].cot=cot; par->data[yktype].len=len; memcpy(par->data[yktype].buf,datBuf,len); par->cp_m=pdt->cp; par->cp_s=pdt->link_cp; par->chnl=pdt->link_ch; par->flag[yktype] = true; //*par_send_flag |= (1<owner); par->data[yktype].ti_m = ti; // 记录日志 sprintf(buf,"级联遥参下行:(cp=%04x,link_ch=%02x,link_cp=%04x,ti=%02x,cot=%02x,len=%02x ,ti_m=%02x)",pdt->cp,pdt->link_ch,pdt->link_cp,ti,cot,len,par->data[yktype].ti_m); log_str_time(LOG_OPERATE,buf,0,0); rt_printf_time("%s\r\n",buf); return 0; } int lnk_master_yk(struct do_table *pdt,u8 ti,u8 cot,u8 v) { u8 yktype; LINKYK_DEF * yk; char buf[128]; u32 *yk_send_flag; // 获取对应通道的结构,获取失败,直接返回 yk_send_flag = lnk_get_ch_head(pdt->link_ch); if(yk_send_flag == 0) { sprintf(buf,"级联遥控:未找到从设备通道(cp=%04x,link_ch=%02x,link_cp=%04x)",pdt->cp,pdt->link_ch,pdt->link_cp); log_str_time(LOG_OPERATE,buf,0,0); rt_printf_time("%s\r\n",buf); return -1; } yk = &g_lnk_yk[pdt->owner]; // 清对应遥控数据结构 memset(yk,0,sizeof(g_lnk_yk[0])); // 赋值 yktype = IECLINK_YK_SND; yk->data[yktype].ti=ti; yk->data[yktype].cot=cot; yk->data[yktype].v=v; yk->cp_m=pdt->cp; yk->cp_s=pdt->link_cp; yk->chnl=pdt->link_ch; yk->flag[yktype] = true; *yk_send_flag |= (1<owner); // 记录日志 sprintf(buf,"级联遥控下行:(cp=%04x,link_ch=%02x,link_cp=%04x,ti=%02x,cot=%02x,v=%02x)",pdt->cp,pdt->link_ch,pdt->link_cp,ti,cot,v); log_str_time(LOG_OPERATE,buf,0,0); rt_printf_time("%s\r\n",buf); return 0; } void lnk_count_slaveaddr(IECLINK_DEF *pt,u8 chnl,LINK_TABLE* lt,u32 num) { u8 ch; u8 addr=0; int j; for(j=0;jcp_s>>21)&0x0f); addr=(u8)((lt->cp_s>>16)&0x1f); if(addr>0&&(ch==chnl)) // 通道相符 { if(pt->slave_num==0) { pt->tsla[pt->slave_num++].addr=addr; } else { int i; for(i=0;islave_num;i++) // 查找子站地址是否保存 { if(addr==pt->tsla[i].addr) { break; } } if(i==pt->slave_num) { pt->tsla[pt->slave_num++].addr=addr; } if(pt->slave_num>=32)pt->slave_num=31; } } lt++; } } int getstrval(char *buf) { char *str; int val=0; str=strchr(buf,'='); if(str) { str++; if(str[0]=='0'&&(str[1]=='x'||str[1]=='X')) { val=strtoul(str,NULL,16); } else { val=strtoul(str,NULL,10); } } return val; } static void lnk_getcfg(IECLINK_DEF *pt,u8 *filestr,u8 *keystr) { u8 str[32],str1[32]; if(filestr[0]=='[') // 是规约类型 { pt->bcfg=false; sprintf(str,"[COM%d_%s]",pt->chnl,keystr); sprintf(str1,"[%s_ALL]",keystr); if(strcmp(filestr,str)==0||strcmp(filestr,str1)==0) { pt->bcfg=true; } return; } if(!pt->bcfg)return; if(strstr(filestr,"appaddr")) // 遥信命令码 { pt->b101App2Byte=(getstrval(filestr)==2)?true:false; } else if(strstr(filestr,"linkaddr")) // { pt->b101Addr2Byte=(getstrval(filestr)==2)?true:false; } else if(strstr(filestr,"cotaddr")) // { pt->b101Cot2Byte=(getstrval(filestr)==2)?true:false; } else if(strstr(filestr,"callalltime")) // { pt->callalltime=getstrval(filestr)*SAM_FREQUENCY; // 单位秒,转为dTcounter 值 } else if(strstr(filestr,"retrytime")) // { pt->retrytime=getstrval(filestr)*SAM_FREQUENCY; // 单位秒,转为dTcounter 值 } else if(strstr(filestr,"sendinteraltime")) // { pt->sendinteraltime=getstrval(filestr)*SAMFREQ/20; // 单位毫秒,转为dTcounter值 } else if(strstr(filestr,"lb_master_en")) { pt->b_lb_master = getstrval(filestr); } else { return; } } static int lnk_init_cfg(IECLINK_DEF *pt,u8 *keystr) { u32 i,file_length; struct file * pfile; u8 *filebuf; u8 filestr[128],*pstr,strlenth; loff_t pos; // 打开文件 pt->callalltime=SAM_FREQUENCY*15; pt->retrytime=SAM_FREQUENCY*5; pt->sendinteraltime=T_100ms; rt_printf("\r\n%s:%d 级联参数初始化\r\n",keystr,pt->chnl); pfile = rt_file_open("/app/data/pcolcfg.ini",O_RDONLY ,0); if(IS_ERR(pfile)) { rt_printf("\r\nerror! 无法打开 pcolcfg.ini\r\n"); return -1; } // 得到文件长度 file_length = rt_file_getfile_size(pfile); if(file_length <= 0) { rt_file_close(pfile,0); return -2; } // 分配内存 filebuf = rt_malloc(file_length); if((filebuf) == NULL) { rt_file_close(pfile,0); return -3; } pos = 0; if(rt_file_read(pfile,filebuf,file_length,&pos) != file_length) { rt_file_close(pfile,0); rt_free(filebuf); return -4; } pstr = filestr; strlenth=0; // 纠错处理 //找到\r\n位置,得到一行长度 for(i = 0; i < file_length; i++) { *pstr++=filebuf[i]; strlenth++; if(filebuf[i] == 0x0a||strlenth>=128) { int j; pstr = filestr; for(j=0;jtlnk; memset(pt,0,sizeof(IECLINK_DEF)); pt->type=IEC101_CHN; pt->chnl=chnl; pt->sendbuf=g_tRsComm[chnl].sendbuf; pt->bPH101=bPH; // 初始化状态 ptlnk->bLinkOK=false; ptlnk->bCallLnk=true; ptlnk->dTMWait=dTCounter; ptlnk->dTInteral=dTCounter; ptlnk->dTCallAllTime=dTCounter; ptlnk->dTSendTime=dTCounter; pt->slave_num=0; pt->slave_current=0; lnk_init_cfg(pt,"IEC101_LNK"); lnk_count_slaveaddr(pt,chnl+2,&g_lt_di[0],g_lt_di_num); lnk_count_slaveaddr(pt,chnl+2,&g_lt_ac[0],g_lt_ac_num); lnk_count_slaveaddr(pt,chnl+2,&g_lt_dd[0],g_lt_dd_num); lnk_count_slaveaddr(pt,chnl+2,&g_lt_do[0],g_lt_do_num); //rintf("port[%d]------101装置数量:%d\r\n",chnl,pt->slave_num); #ifdef RCD_STRAN_M queue_init(&pt->rcd_m.queue,NEWRCD_COUNT_M,&pt->rcd_m.data,NEWRCD_SIZE_M); #endif #ifdef YPARA_LINK queue_init(&pt->par_queue.queue,PAR_COUNT_M,&pt->par_queue.data,PAR_SIZE_M); rt_printf("-----PAR_SIZE_M=%d\r\n",PAR_SIZE_M); #endif // 判断 装置是否有电度 for(i=0;islave_num;i++) { int j; pt->tsla[i].bDdValid=false; for(j=0;j>16)&0x1f))==pt->tsla[i].addr) { pt->tsla[i].bDdValid=true; } } } for(i=0; islave_num;i++) { // 初始化状态 pt->tsla[i].tlnksave.bLinkOK=false; pt->tsla[i].tlnksave.bCallLnk=true; pt->tsla[i].tlnksave.dTMWait=dTCounter; pt->tsla[i].tlnksave.dTInteral=dTCounter; pt->tsla[i].tlnksave.dTCallAllTime=dTCounter; pt->tsla[i].tlnksave.dTSendTime=dTCounter; } pt->slave_addr=pt->tsla[0].addr; } void lnk_101_send(IECLINK_DEF *pt) { RS_Send_Enable(pt->chnl); g_tRsComm[pt->chnl].nSendCnt=1; // 发送缓冲区的第一个字节为发送长度 g_tRsComm[pt->chnl].bSend=true; if(g_print_lnk && (g_print_port & (1<chnl))) { char tmpstr[24]; sprintf(tmpstr,"TL_101(%d):",pt->chnl); print_msg(tmpstr,&g_tRsComm[pt->chnl].sendbuf[1],g_tRsComm[pt->chnl].sendbuf[0]); } } static void lnk_101_call_fixed(IECLINK_DEF *pt,unsigned char zone,bool bFCV) { u8 *pd=pt->sendbuf; LNK_STATUS *ptlnk=&pt->tlnk; if(bFCV) { IEC101_SETFCV(zone); if(ptlnk->bMFCB) { IEC101_SETFCB(zone); } else { IEC101_CLRFCB(zone); } } if(!pt->b101Addr2Byte) { pd[0]=5; pd[1]=0x10; pd[2]=zone; pd[3]=(u8)pt->slave_addr; pd[4]=pd[2]+pd[3]; pd[5]=0x16; } else { pd[0]=6; pd[1]=0x10; pd[2]=zone; pd[3]=(u8)pt->slave_addr; pd[4]=(u8)(pt->slave_addr>>8); pd[5]=pd[2]+pd[3]+pd[4]; pd[6]=0x16; } } static void lnk_101_call(IECLINK_DEF *pt, u8 type,u8 ngd,u8 cot,u8 *pdat,u8 len) { u8 *pd; u8 cnt,checksum; u8 zone=0x53; u8 tmplen; LNK_STATUS *ptlnk=&pt->tlnk; tmplen=len+6; // 报文长度调整变量赋值 if(pt->b101Addr2Byte) tmplen++; if(pt->b101Cot2Byte) tmplen++; if(pt->b101App2Byte) tmplen++; if(ptlnk->bMFCB) { IEC101_SETFCB(zone); } else { IEC101_CLRFCB(zone); } pd=pt->sendbuf; *pd++=tmplen+6; *pd++=0x68; *pd++=tmplen; *pd++=tmplen; *pd++=0x68; *pd++=zone; *pd++=(u8)pt->slave_addr; //链路地址1 if(pt->b101Addr2Byte) { *pd++=(u8)(pt->slave_addr>>8); //链路地址2 } *pd++=type; //帧类型 *pd++=ngd; //VSQ *pd++=cot; //传送原因 if(pt->b101Cot2Byte) { *pd++=0; //传送原因2 } *pd++=(u8)pt->slave_addr; //应用服务单元地址1 if(pt->b101App2Byte) { *pd++=(u8)(pt->slave_addr>>8); //应用服务单元地址2 } for(cnt=0;cntsendbuf[5]; for(cnt=0;cntrcd_m.queue; if(queue->count == 0) return 0; /*无数据*/ pos = queue->front * queue->s_size; memcpy(&data, &queue->data[pos], queue->s_size); if(data.addr != pt->slave_addr) { return 0; } else { return 1; } } void lnk_rcdfile_check_104(IECLINK_DEF *pt) { char tmp[100]; newrcd_m_struct data; if(pt->tft.bTransing == false) /*为该地址并且,没有文件在传输*/ { if(get_queue_count(&pt->rcd_m.queue) > 0) { get_data_queque(&pt->rcd_m.queue,(u8 *)&data); strncpy(pt->tft.filename,data.filename,sizeof(pt->tft.filename)); pt->tft.fnamelen=strlen(pt->tft.filename); pt->tft.bFile=true; pt->tft.bTransing = true; /*启动传输*/ pt->tft.addr = pt->slave_addr; /*启动传输*/ pt->tft.us0_file_trans = ustimer_get_origin(); sprintf(tmp, "BAY%02d%s文件传输启动!!!!!!!", pt->chnl+1,pt->tft.filename+5); /*104替换成级联通道号*/ log_str_time(LOG_OPERATE,tmp,0,1); } } } void lnk_rcdfile_check(IECLINK_DEF *pt) { char tmp[100]; newrcd_m_struct data; if(lnk_qaddr_check(pt) && (pt->tft.bTransing == false)) /*为该地址并且,没有文件在传输*/ { if(get_queue_count(&pt->rcd_m.queue) > 0) { get_data_queque(&pt->rcd_m.queue,(u8 *)&data); strncpy(pt->tft.filename,data.filename,sizeof(pt->tft.filename)); pt->tft.fnamelen=strlen(pt->tft.filename); pt->tft.bFile=true; pt->tft.bTransing = true; /*启动传输*/ pt->tft.addr = pt->slave_addr; /*启动传输*/ sprintf(tmp, "%s传输启动!!!",pt->tft.filename); log_str_time(LOG_OPERATE,tmp,0,1); } } } void lnk_rcdfile(IECLINK_DEF *pt,u8 *buf,u16 addr) { char namestr[64]={0}; u8 namelen=0,num=0; s32 i=0,off=0; newrcd_m_struct data; //strncpy(pt->tfile_m.dirpath,RCD_DIR,sizeof(pt->tfile_m.dirpath)); /*默认目录名*/ num =buf[off++]; for(i=0;ircd_m.queue,(u8 *)&data,OVER_QUEUE); //print_queque(&pt->rcd_m.queue,0); } } #endif void lnk_101_app_recv(IECLINK_DEF *pt) { u8 *pd; u8 AddByte=0; u8 CotByte=0; //传送原因双字节 u8 AppByte=0; //应用单元地址双字节 BYTE addr; LNK_STATUS *ptlnk=&pt->tlnk; if(pt->bData) //有接收到的数据 { if(pt->b101Addr2Byte) AddByte=1; if(pt->b101Cot2Byte) CotByte=1; if(pt->b101App2Byte) AppByte=1; if(g_print_lnk && (g_print_port & (1<chnl))) { char tmpstr[24]; sprintf(tmpstr,"RL_101(%d):",pt->chnl); if(pt->recvbuf[0]==0x10) { print_msg(tmpstr,pt->recvbuf,5+AddByte); } else if(pt->recvbuf[0]==0xe5) { print_msg(tmpstr,pt->recvbuf,1); } else { print_msg(tmpstr,pt->recvbuf,pt->recvbuf[1]+6); } } pt->bData=false; // 检查帧类型 if(pt->recvbuf[0]==0x10) pd=&pt->recvbuf[1];//短帧 else if(pt->recvbuf[0]==0x68) pd=&pt->recvbuf[4];//长帧 else if(pt->recvbuf[0]==0xe5) pd=&pt->recvbuf[0];//长帧 else return; // 根据类型标识处理长帧 if(pt->recvbuf[0]==0x68) { u8 chnl,asdu_addr=0; addr=pd[1]; //装置地址 chnl=((pt->chnl+2)<<5)+addr; asdu_addr=pd[5+AddByte+CotByte]; if(asdu_addr == addr) { switch(pd[2+AddByte]) //帧类型 pd[7]=ngd { case 1: // 遥信帧:单点值 case 3: // 遥信帧:双点值 lnk_slave_yx(chnl,pd[2+AddByte],pd[3+AddByte],pd[4+AddByte],2,pd+6+AddByte+CotByte+AppByte); break; case 9: // 遥测帧:归一化值 case 11: // 遥测帧:标度化值 case 13: // 遥测帧:浮点值 case 21: // 遥测帧:不带品质描述字的归一化值 lnk_slave_yc(chnl,pd[2+AddByte],pd[3+AddByte],2,pd+6+AddByte+CotByte+AppByte); break; case 206: // 不带时标电度 case 207: //带时标 电度 lnk_slave_dd(chnl,pd[2+AddByte],pd[3+AddByte],pd[4+AddByte],2,pd+6+AddByte+CotByte+AppByte); break; case 30: // 事件记录:单点 case 31: // 事件记录:双点 lnk_slave_soe(pt,chnl,pd[2+AddByte],pd[3+AddByte],2,pd+6+AddByte+CotByte+AppByte); break; case 45: // 遥控确认帧 case 46: // 遥控确认帧 lnk_slave_yk(chnl,pd[2+AddByte],pd[4+AddByte],2,pd+6+AddByte+CotByte+AppByte); break; case FOS_PAR_READ_ONE: case FOS_PAR_SET_ONE: case FOS_PAR_SET_MUL: case FOS_PAR_READ_MUL: lnk_slave_par(chnl,pd[2+AddByte],pd[4+AddByte],2,pd+6+AddByte+CotByte+AppByte,pd[3+AddByte]); break; case 42: // 故障参数上送 lnk_slave_fault(chnl,pt->recvbuf[1]-6-AddByte-CotByte-AppByte,pd+6+AddByte+CotByte+AppByte,false); break; #ifdef YPARA_LINK case 202: lnk_slave_ypara_read(pt,chnl,pd[3+AddByte],pd[4+AddByte],pd+6+AddByte+CotByte+AppByte,false); break; case 203: //rt_printf("104级联读参数解包-------\r\n"); lnk_slave_ypara_write(pt,chnl,pd[3+AddByte],pd[4+AddByte],pd+6+AddByte+CotByte+AppByte,false); break; #endif case 210: // 文件传输 lnk_test_file_frame(pt,&pt->recvbuf[12+AddByte+CotByte+AppByte],pt->recvbuf[1]-(AddByte+CotByte+AppByte)-9); break; case 211: // 文件下载 lnk_update_file_frame(pt,pt->recvbuf[12+AddByte+CotByte+AppByte]); break; case 70: // 初始化结束帧 ptlnk->bCallAll=true; break; #ifdef RCD_STRAN_M case IECLINK_RCD: // 新录波帧 lnk_rcdfile(pt,&pt->recvbuf[12+AddByte+CotByte+AppByte],addr); break; #endif } } ptlnk->bEchoApp=(true&&pt->bPH101); } else if(pt->recvbuf[0]==0xe5) { pt->recvbuf[0]=0; // 防止影响: 设置1级数据标志 } else { // 连接建立 if((pd[0]&0x0f) == IEC101_ECHO_LINK_OK) { ptlnk->bLinkOK = true; pt->LinkCount++; rt_printf_time("101级联成功(通道=%d,连接计数=%d)!\r\n",pt->chnl,pt->LinkCount); ptlnk->dTCallAllTime=dTCounter; } else if(pt->bPH101) // 平衡101 { if((pd[0]&0xCf) == (IEC101_ECHO_NO_DATA|0xC0)) //召链路 { ptlnk->bEchoLnk=true; } else if((pd[0]&0xCf) == (IEC101_REMOTE_RESET|0xC0)) //召链路 { ptlnk->bEchoApp=true; } } } // 请求链路状态必须得到正确的报文才允许继续往下走 if(ptlnk->bLinkOK) { ptlnk->bMRecvOK=true; } ptlnk->dTInteral=dTCounter; // 设置1级数据标志 if(pd[0]&0x20) { ptlnk->bCallOne=(true&&!pt->bPH101); } ptlnk->dTSendTime=dTCounter; } } void lnk_101_salve_restore(IECLINK_DEF *pt,int pre,int m_current) //切换子站地址,并保存及恢复数据 { pt->tsla[pre].tlnksave=pt->tlnk; pt->tlnk=pt->tsla[m_current].tlnksave; pt->tlnk.bDdValid=pt->tsla[m_current].bDdValid; pt->slave_addr=pt->tsla[m_current].addr; } void lnk_101_change_slave(IECLINK_DEF *pt) //切换子站地址,并保存及恢复数据 { int m_current; LNK_STATUS *ptlnk=&pt->tlnk; if(pt->slave_num<=1) { ptlnk->bDdValid=pt->tsla[0].bDdValid; return; //只有一个子站地址,不切换 } if(ptlnk->bCallOne) return; //有一级数据需继续召唤,不切换子站地址 m_current=pt->slave_current; m_current++; if(m_current>=pt->slave_num)m_current=0; pt->slave_addr=pt->tsla[m_current].addr; lnk_101_salve_restore(pt,pt->slave_current,m_current); pt->slave_current=m_current; } void lnk_101_app_send(IECLINK_DEF *pt) { LNK_STATUS *ptlnk=&pt->tlnk; bool bWantEcho=true; if(pt->slave_num==0)return; #ifdef RCD_STRAN_M if((pt->tft.bTransing == false) /*有文件正在传输,加速召唤*/ &&(dTCounter-ptlnk->dTSendTimesendinteraltime)) { return; } #else if((dTCounter-ptlnk->dTSendTime) sendinteraltime) // 接收到报文后,发送间隔 { return; } #endif // 检查从机应答 if(ptlnk->bMSend) { if(!ptlnk->bMRecvOK) { // 如果超时未收到应答,重发 if(dTCounter-ptlnk->dTMWait>pt->retrytime) { ptlnk->dTMWait=dTCounter; //重发三次后,重新初始化 if(++ptlnk->byRetryTimes>2||ptlnk->bRetryErr) { ptlnk->bMSend=false; ptlnk->bCallLnk=true; ptlnk->bRetryErr=true; if(ptlnk->bLinkOK) { #ifdef RCD_STRAN_M if((pt->tft.bTransing) && (pt->tft.addr == pt->slave_addr)) /*通道中断,重新召唤*/ { log_str_time(LOG_OPERATE,"通讯断开,中断传输",0,1); pt->tft.bTransing = false; } #endif ptlnk->bLinkOK = false; rt_printf_time("重发失败,复位链路(通道=%d,连接计数=%d)!\r\n",pt->chnl,pt->LinkCount); } } else { //需重新组织发送 lnk_101_send(pt); } } // 发送,未收到数据,返回 return; } else { ptlnk->bRetryErr=false; } } lnk_101_change_slave(pt); #ifdef RCD_STRAN_M if(ptlnk->bLinkOK) { lnk_rcdfile_check(pt); } #endif // 上一帧从机应答OK,开始下一帧发送 ptlnk->bMSend=false; if(ptlnk->bEchoApp) { lnk_101_call_fixed(pt,IECLINK_ECHOAPP,false); ptlnk->bEchoApp=false; bWantEcho=false; } else if(ptlnk->bEchoLnk) { lnk_101_call_fixed(pt,IECLINK_ECHOLNK,false); ptlnk->bEchoLnk=false; bWantEcho=false; } else if(ptlnk->bCallLnk) { lnk_101_call_fixed(pt,IECLINK_CALLLNK,false); ptlnk->bMFCB=false; ptlnk->bCallLnk=false; ptlnk->bCallRst=true; } else if(ptlnk->bCallRst) { lnk_101_call_fixed(pt,IECLINK_CALLRST,false); ptlnk->bMFCB=false; ptlnk->bCallRst=false; if(!pt->bPH101) { ptlnk->bCallAll=true; ptlnk->bSetTime=true; #ifdef YPARA_LINK set_read_all(pt); #endif } } else if(ptlnk->bCallOne) { lnk_101_call_fixed(pt,IECLINK_CALLONE,true); ptlnk->bCallOne=false; } else if(ptlnk->bCallAll) { u8 dat[4]; int num=0; dat[num++]=0; dat[num++]=0; dat[num++]=0x14; lnk_101_call(pt,100,1,6,dat,num); ptlnk->bCallAll=false; ptlnk->bCallDD=true; ptlnk->dTCallAllTime=dTCounter; } else if(ptlnk->brst) { u8 dat[4]; int num=0; dat[num++]=0; dat[num++]=0; dat[num++]=0x14; lnk_101_call(pt,176,1,6,dat,num); ptlnk->brst=false; } else if(ptlnk->bCallDD&&ptlnk->bDdValid) { u8 dat[4]; int num=0; dat[num++]=0; dat[num++]=0; dat[num++]=0x05; lnk_101_call(pt,101,1,6,dat,num); ptlnk->bCallDD=false; } else if(ptlnk->bSetTime) { u8 dat[12]; int num=0; struct timespec ts; struct rtc_time_t rtc; clk_time_get(&ts); timespec_to_rtc(ts,&rtc,1); dat[num++]=0; //信息序号=0时钟同步 dat[num++]=0; //信息序号=0时钟同步 dat[num++]=(u8)rtc.ms; //MsL dat[num++]=(u8)(rtc.ms>>8); //MsH dat[num++]=rtc.min; //Min dat[num++]=rtc.hour; //hour dat[num++]=rtc.day; //Day dat[num++]=rtc.month; //month dat[num++]=rtc.year; //year lnk_101_call(pt,103,1,6,dat,num); ptlnk->bSetTime=false; ptlnk->us0_set_time = ustimer_get_origin(); } // 遥控 else if(pt->yk_send_flag) { u8 dat[12]; int i,num=0; for(i=0;iyk_send_flag & (1<slave_addr)continue; dat[num++]=(u8)g_lnk_yk[i].cp_s; dat[num++]=(u8)(g_lnk_yk[i].cp_s>>8); // 远动选择 if(g_lnk_yk[i].data[IECLINK_YK_SND].ti == 0xff) { dat[num]=g_lnk_yk[i].data[IECLINK_YK_SND].v|0x80; lnk_101_call(pt,46,1,g_lnk_yk[i].data[IECLINK_YK_SND].cot,dat,num+1); g_lnk_yk[i].data[IECLINK_YK_SND].ti = 0xfe; } // 远动遥控 else if(g_lnk_yk[i].data[IECLINK_YK_SND].ti == 0xfe) { dat[num]=g_lnk_yk[i].data[IECLINK_YK_SND].v; lnk_101_call(pt,46,1,g_lnk_yk[i].data[IECLINK_YK_SND].cot,dat,num+1); // 清除标志 g_lnk_yk[i].flag[IECLINK_YK_SND]=false; pt->yk_send_flag &= ~(1<yk_send_flag &= ~(1<bMSend=true; break; } } } // 遥参 else if(pt->par_send_flag) { u8 dat[256]; int i,num=0; for(i=0;ipar_send_flag & (1<slave_addr)continue; //dat[num++]=(u8)g_link_par[i].cp_s; //dat[num++]=(u8)(g_link_par[i].cp_s>>8); // 远动选择 if(g_link_par[i].data[IECLINK_YK_SND].ti == 0xff) { int count; //dat[num]=g_link_par[i].data[IECLINK_YK_SND].v|0x80; memcpy(&dat[num],&g_link_par[i].data[IECLINK_YK_SND].buf,g_link_par[i].data[IECLINK_YK_SND].len); rt_printf("参数选择 \r\n"); for (count=0;countdtpartime[i]=ustimer_get_origin(); #endif pt->par_send_flag &= ~(1<dtpartime[i]=ustimer_get_origin(); #else g_link_par[i].flag[IECLINK_YK_SND]=false; #endif pt->par_send_flag &= ~(1<dtpartime[i]=ustimer_get_origin(); #else g_link_par[i].flag[IECLINK_YK_SND]=false; #endif pt->par_send_flag &= ~(1<bMSend=true; break; } } } #ifdef YPARA_LINK //遥参 else if(get_queue_count(&pt->par_queue.queue) > 0) { u8 dat[256]; int i=0,num=0; msg_data_struct *msg =&pt->temp_par; msg_ypara_data_struct *ypara_msg = &msg->ypara_msg; //rt_printf("[%d]:::101遥参下发-----par_queue num=%d,[%x,%x]\r\n",pt->chnl,get_queue_count(&pt->par_queue.queue),msg->dport &0x1f,pt->slave_addr); check_data_queque(&pt->par_queue.queue,(u8 *)msg); if((msg->dport &0x1f) != pt->slave_addr) /*非当前地址*/ { return; } del_data_queue(&pt->par_queue.queue); if(ypara_msg->type == modify_set) { /*定值区*/ dat[num++] = (u8)ypara_msg->section_p; dat[num++] = (u8)(ypara_msg->section_p>>8); if(ypara_msg->cmd == YP_SEL) { dat[num++] = 0x80; /*特征码*/ for(i=0;inum;i++) { dat[num++]=(u8)ypara_msg->base_data[i].cp_s; dat[num++]=(u8)(ypara_msg->base_data[i].cp_s>>8); dat[num++] = ypara_msg->base_data[i].val_iec.tag; dat[num++] = ypara_msg->base_data[i].val_iec.size; if(ypara_msg->base_data[i].val_iec.size >0) { memcpy(&dat[num],ypara_msg->base_data[i].val_iec.value,ypara_msg->base_data[i].val_iec.size); num += ypara_msg->base_data[i].val_iec.size; } } } else if(ypara_msg->cmd == YP_EXE) { dat[num++] = 0; /*特征码*/ set_read_all(pt); } else { dat[num++] = 0x40; /*特征码*/ } if((ypara_msg->cmd == 2) || (ypara_msg->cmd == 1)) { lnk_101_call(pt,203,ypara_msg->num,6,dat,num); } else { lnk_101_call(pt,203,ypara_msg->num,8,dat,num); } pt->sport = msg->sport; ptlnk->bMSend=true; } else if(ypara_msg->type == settion_swht) //切换定值区 { } } else if(ptlnk->bSet_all) { u8 dat[4]; int num=0; dat[num++]=0; //当前定值区 dat[num++]=0; //当前定值区 lnk_101_call(pt,202,0,6,dat,num); clear_read_all(pt); ptlnk->bMSend=true; } #endif #ifdef RCD_STRAN_M else if((ptlnk->bRcd) && (get_queue_count(&pt->rcd_m.queue) <= 0) && (pt->tft.bTransing == false) && (tRunPara.b_lb_master || (pt->b_lb_master))) /*没有文件传输*/ { u8 dat[4]; int num=0; dat[num++]=0; dat[num++]=0; lnk_101_call(pt,IECLINK_RCD,1,6,dat,num); ptlnk->bRcd=false; } // 空闲时,以500ms间隔召二级数据 else if((lnk_file_check_trans(pt)) && (pt->tft.addr == pt->slave_addr)) { rt_printf("---------文件传输%d\r\n",pt->slave_addr); lnk_test_file_trans(pt); } else if((pt->tft.bTransing == true)&&(pt->tft.addr == pt->slave_addr)) /*有文件正在传输,加速召唤*/ { if(!pt->bPH101) { lnk_101_call_fixed(pt,IECLINK_CALLTWO,true); } else { return; } } #else // 空闲时,以500ms间隔召二级数据 else if(lnk_file_check_trans(pt)) { lnk_test_file_trans(pt); } #endif else if(dTCounter-ptlnk->dTInteral>pt->sendinteraltime) { if(!pt->bPH101) { lnk_101_call_fixed(pt,IECLINK_CALLTWO,true); } else { return; } } else { return; } // 开始发送,清重发标志,翻转FCB位 ptlnk->bMSend=true&& bWantEcho; ptlnk->bMRecvOK=false; ptlnk->dTMWait=dTCounter; ptlnk->byRetryTimes=0; if(bWantEcho) ptlnk->bMFCB=!ptlnk->bMFCB; lnk_101_send(pt); } void lnk_101_par_timer(IECLINK_DEF *pt) { int i=0; int flag=0; for(i=0;ipar_send_flag & (1<dtpartime[i]) > 10*USTIMER_SEC) /*10秒遥参*/ { rt_printf("--------遥参超时!!!\r\n"); g_link_par[i].flag[IECLINK_YK_SND] = false; } } } } void lnk_101_app_timer(IECLINK_DEF *pt) { LNK_STATUS *ptlnk=&pt->tlnk; // 定时总召 if(!ptlnk->bCallAll) { if(dTCounter-ptlnk->dTCallAllTime>pt->callalltime) // 10分钟总召一次 { ptlnk->bCallAll=true; ptlnk->dTCallAllTime=dTCounter; } } #ifdef RCD_STRAN_M if(ustimer_get_duration(ptlnk->dTRcdTime) > 3*USTIMER_SEC) /*3秒间隔*/ { ptlnk->bRcd = true; ptlnk->dTRcdTime=ustimer_get_origin(); } #endif #ifdef FUNC_MORE_PREREAD //lnk_101_par_timer(pt); #endif // 检查对时间隔 if(ustimer_get_duration(ptlnk->us0_set_time) > 5*60*USTIMER_SEC) { ptlnk->bSetTime = true; } } void lnk_101_app(IECLINK_DEF *pt) { LNK_STATUS *ptlnk=&pt->tlnk; lnk_101_app_recv(pt); lnk_101_app_send(pt); if(ptlnk->bLinkOK) { lnk_101_app_timer(pt); } } static void lnk_101_recv_rst(IECLINK_DEF *pt) { pt->nTypeCounter=0; pt->nRecvLenth=0; pt->nRecvCounter=0; } void lnk_101_recv(IECLINK_DEF *pt,u8 byRevData) { pt->recvbuf[pt->nRecvCounter++]=byRevData; switch(pt->nTypeCounter) { case 0: if(byRevData==0x68) { pt->nTypeCounter=1; pt->sum=0; } else if(byRevData==0x10) { if(!pt->b101Addr2Byte) { pt->nRecvLenth=2; } else { pt->nRecvLenth=3; } pt->nTypeCounter=6; pt->nRecvCnt=0; pt->sum=0; } else if(byRevData==0xe5) // e5处理 { lnk_101_recv_rst(pt); pt->bData=true; // 唤醒主循环 mainloop_wakeup(); } else { lnk_101_recv_rst(pt); } break; case 1: pt->nTypeCounter=2; pt->nRecvLenth=byRevData; //长帧长度 if(pt->nRecvLenth>IECLINK_RECVBUF_MAX) { lnk_101_recv_rst(pt); } break; case 2: if(pt->nRecvLenth==byRevData) { pt->nTypeCounter=3; } else { lnk_101_recv_rst(pt); } break; case 3: if(byRevData==0x68) { pt->nTypeCounter=6; pt->nRecvCnt=0; } else { lnk_101_recv_rst(pt); } break; //case 4: //控制域 // pt->sum=byRevData; // pt->nTypeCounter=5; // break; //case 5: //目标地址 // pt->sum+=byRevData; // pt->nRecvCnt=0; // pt->nTypeCounter=6; // if(pt->nRecvLenth==2)//短帧 // pt->nTypeCounter=7; // break; case 6: //有效数据 //有效数据 if(++pt->nRecvCnt>=pt->nRecvLenth) { pt->nTypeCounter=7; } pt->sum+=byRevData; break; case 7: //校验和 if(pt->sum==byRevData) { pt->nTypeCounter=8; } else { lnk_101_recv_rst(pt); } break; case 8: //结束符 lnk_101_recv_rst(pt); if(byRevData==0x16) //校验结束字符,报文接收完毕, { pt->bData=true; // 唤醒主循环 mainloop_wakeup(); return ; } break; } } // 下面是以太网级联代码 void lnk_104_init(int net) { IECLINK_DEF *pt = &g_link_104[net]; LNK_STATUS *ptlnk=&pt->tlnk; memset(pt,0,sizeof(IECLINK_DEF)); pt->type=IEC104_CHN; pt->chnl = net; pt->sendbuf=g_link104_buf[net]; ptlnk->bCallRst=true; ptlnk->dTMWait=dTCounter; ptlnk->dTInteral=dTCounter; ptlnk->dTCallAllTime=dTCounter; ptlnk->us0_set_time=ustimer_get_origin(); // 测试状态复位 pt->bStartTest=false; pt->us0_test=ustimer_get_origin(); lnk_init_cfg(pt,"IEC104_LNK"); pt->AckRecvNum=0; #ifdef RCD_STRAN_M queue_init(&pt->rcd_m.queue,NEWRCD_COUNT_M,&pt->rcd_m.data,NEWRCD_SIZE_M); #endif #ifdef YPARA_LINK queue_init(&pt->par_queue.queue,PAR_COUNT_M,&pt->par_queue.data,PAR_SIZE_M); #endif } void lnk_104_send(IECLINK_DEF *pt,u8 num) { char tmpstr[16]; sprintf(tmpstr,"TL_104(%d):",pt->chnl+1); if(g_print_lnk && (g_print_port & (1<chnl))) { print_msg(tmpstr,pt->sendbuf,num); } net_104link_send(pt->chnl,pt->sendbuf,num); // 发送了任意帧,复位T3定时器(测试帧超时) pt->us0_test=ustimer_get_origin(); } static void lnk_104_ack(IECLINK_DEF *pt,u8 zone) { u8 *pd=pt->sendbuf; int sum=0; pd[sum++]=0x68; pd[sum++]=0x04; pd[sum++]=zone; pd[sum++]=0x00; pd[sum++]=0x00; pd[sum++]=0x00; lnk_104_send(pt,sum); } static void lnk_104_sAck(IECLINK_DEF *pt) { u8 *pd=pt->sendbuf; int sum=0; pd[sum++]=0x68; pd[sum++]=0x04; pd[sum++]=0x01; pd[sum++]=0x00; sum += CopySwap(&pd[sum],pt->RecvNum.tt,2,true); pt->AckRecvNum=pt->RecvNum.ss; lnk_104_send(pt,sum); } static void lnk_104_call(IECLINK_DEF *pt, u8 type,u8 ngd,u8 cot,u8 *pdat,u8 len) { u8 *pd; int sum=0; int i; pd=pt->sendbuf; //68 14 00 00 00 00 67 01 06 01 01 00 00 00 00 34 df 1d 0e 51 09 0d //对时 //68 0e 02 00 04 00 64 01 06 01 01 00 00 00 00 14 //总招 //68 0e 04 00 4c 00 2e 01 06 01 01 00 01 60 00 82 //遥控 pd[sum++]=0x68; pd[sum++]=len+10; sum += CopySwap(&pd[sum],pt->SendNum.tt,2,true); sum += CopySwap(&pd[sum],pt->RecvNum.tt,2,true); pd[sum++]=type;//帧类型 pd[sum++]=ngd; pd[sum++]=cot; pd[sum++]=0; pd[sum++]=(u8)1; // 使用1作为级联从机的地址 pd[sum++]=(u8)0; for(i=0;iAckRecvNum=pt->RecvNum.ss; lnk_104_send(pt,sum); pt->SendNum.ss+=2; pt->bSendS = 0; } void lnk_104_app_recv(int net) { IECLINK_DEF *pt = &g_link_104[net]; u8 *pd,addr; Byte2WORD Num; LNK_STATUS *ptlnk=&pt->tlnk; char tmpstr[16]; if(pt->bData == 0) //有接收到的数据 { return; } sprintf(tmpstr,"RL_104(%d):",pt->chnl+1); if(g_print_lnk && (g_print_port & (1<chnl))) { print_msg(tmpstr,pt->recvbuf,pt->recvbuf[1]+2); } if(pt->recvbuf[0] != 0x68) { pt->bData=false; g_net_104link_data[net]=0; return; } switch(pt->recvbuf[2]&0x03) //控制域判断 { case 0x00: //I格式 case 0x02: // 确认发送帧的接收序号 pt->recvbuf[2] &= 0xfe; CopySwap(Num.tt,&pt->recvbuf[2],2,false); Num.ss += 2; if(Num.ss != pt->RecvNum.ss) { if(pt->bSendS == 0) { ptlnk->dTInteral=dTCounter; } pt->bSendS = ((Num.ss - pt->RecvNum.ss) > 8*2)? 2 : 1; pt->RecvNum.ss = Num.ss; } //确认序号 pt->recvbuf[4] &= 0xfe; CopySwap(pt->AckNum.tt,&pt->recvbuf[4],2,false); // 处理ASDU pd=&pt->recvbuf[6]; addr=pt->chnl+1; // 网络通道,统一使用网络1,级联地址代表参数表中子站地址,下发从1开始,pt->chnl从0开始 switch(pd[0]) { case 1: // 遥信帧:单点值 case 3: // 遥信帧:双点值 lnk_slave_yx(addr,pd[0],pd[1],pd[2],3,pd+6); break; case 9: // 遥测帧:归一化值 case 11: // 遥测帧:标度化值 case 13: // 遥测帧:浮点值 lnk_slave_yc(addr,pd[0],pd[1],3,pd+6); break; case 30: // 事件记录:单点 case 31: // 事件记录:双点 lnk_slave_soe(pt,addr,pd[0],pd[1],3,pd+6); break; case 45: // 遥控确认帧 case 46: // 遥控确认帧 lnk_slave_yk(addr,pd[0],pd[2],3,pd+6); break; case FOS_PAR_READ_ONE: case FOS_PAR_SET_ONE: case FOS_PAR_SET_MUL: case FOS_PAR_READ_MUL: lnk_slave_par(addr,pd[0],pd[2],3,pd+6,pd[1]); break; case FOS_PAR_READ_ONE_EXT: case FOS_PAR_SET_ONE_EXT: case FOS_PAR_SET_MUL_EXT: case FOS_PAR_READ_MUL_EXT: lnk_slave_par(addr,pd[0],pd[2],2,pd+6,pd[1]); break; #ifdef FUN_YPARA_CFG_NOTY case 116: lnk_para_chg(pt,addr,pd[1],pd[2],pd+6,true); break; #endif #ifdef YPARA_LINK case 202: lnk_slave_ypara_read(pt,addr,pd[1],pd[2],pd+6,true); break; case 203: //rt_printf("104级联读参数解包-------\r\n"); lnk_slave_ypara_write(pt,addr,pd[1],pd[2],pd+6,true); break; case SET_UP_TYPE: if(pd[2] & IEC_COT_PN) break; lnk_slave_ypara_updata(pt,pd+6); break; #endif #ifdef RCD_STRAN_M case IECLINK_RCD: // 新录波帧 ptlnk->bRcding = false; if(pd[2] & IEC_COT_PN) break; lnk_rcdfile(pt,&pt->recvbuf[15],tRunPara.byAddr); break; #endif case 206: // 不带时标电度 case 207: //带时标 电度 lnk_slave_dd(addr,pd[0],pd[1],pd[2],3,pd+6); break; case 42: // 故障参数上送 lnk_slave_fault(addr,pt->recvbuf[1]-10,pd+6,true); break; case 210: // 文件传输 lnk_test_file_frame(pt,&pt->recvbuf[15],pt->recvbuf[1]-14); break; case 211: // 文件传输 lnk_update_file_frame(pt,pt->recvbuf[15]); break; } break; case 0x01: //S格式 pt->recvbuf[4] &= 0xfe; CopySwap(pt->AckNum.tt,&pt->recvbuf[4],2,false); break; case 0x03: //U格式 // 如果是子站主动发送的测试帧,必须应答 if(pt->recvbuf[2] == FRAME_U_TEST) { pt->bTestAck = true; } break; } ptlnk->bMRecvOK=true; ptlnk->byRetryTimes=0; // 清Test计数器 pt->us0_test=ustimer_get_origin(); pt->bStartTest=false; pt->bData=false; g_net_104link_data[net]=0; } void lnk_104_app_send(int net) { IECLINK_DEF *pt = &g_link_104[net]; LNK_STATUS *ptlnk=&pt->tlnk; // 以下开始处理发送 // 检查从站应答 if(ptlnk->bMSend && (!ptlnk->bMRecvOK)) { if(dTCounter-ptlnk->dTMWait>pt->retrytime) // 2秒后,未收到应答报文 { ptlnk->dTMWait=dTCounter; ptlnk->bMSend=false; ptlnk->bCallRst=true; #ifdef RCD_STRAN_M if(pt->tft.bTransing) /*通道中断,重新召唤*/ { log_str_time(LOG_OPERATE,"通讯断开,中断传输",0,1); pt->tft.bTransing = false; } #endif } // 从站未应答,直接返回 return; } // 到这儿,以前的发送帧已应答完成,开始新的发送 // 先初始化数据 ptlnk->byRetryTimes=0; ptlnk->dTMWait=dTCounter; ptlnk->bMRecvOK=false; ptlnk->bMSend=false; #ifdef RCD_STRAN_M lnk_rcdfile_check_104(pt); /*扫描是否有录波文件召唤*/ #endif // 进入STARTDT状态 if(ptlnk->bCallRst) { lnk_104_ack(pt,0x07); ptlnk->bCallRst=false; ptlnk->bMSend=true; ptlnk->bCallAll=true; ptlnk->bSetTime=true; #ifdef YPARA_LINK set_read_all(pt); #endif pt->SendNum.ss=0; } // 总召 else if(ptlnk->bCallAll) { u8 dat[4]; int num=0; dat[num++]=0; dat[num++]=0; dat[num++]=0; dat[num++]=0x14; lnk_104_call(pt,100,1,6,dat,4); ptlnk->bCallAll=false; ptlnk->bCallDD=true; ptlnk->dTCallAllTime=dTCounter; ptlnk->bMSend=true; } else if(ptlnk->bCallDD) { u8 dat[4]; int num=0; dat[num++]=0; dat[num++]=0; dat[num++]=0; dat[num++]=0x05; lnk_104_call(pt,101,1,6,dat,4); //电度召唤 ptlnk->bCallDD=false; ptlnk->bMSend=true; } // 对时 else if(ptlnk->bSetTime) { u8 dat[12]; int num=0; struct timespec ts; struct rtc_time_t rtc; clk_time_get(&ts); timespec_to_rtc(ts,&rtc,1); dat[num++]=0; //信息序号=0时钟同步 dat[num++]=0; //信息序号=0时钟同步 dat[num++]=0; //信息序号=0时钟同步 dat[num++]=(u8)rtc.ms; //MsL dat[num++]=(u8)(rtc.ms>>8); //MsH dat[num++]=rtc.min; //Min dat[num++]=rtc.hour; //hour dat[num++]=rtc.day; //Day dat[num++]=rtc.month; //month dat[num++]=rtc.year; //year lnk_104_call(pt,103,1,6,dat,num); ptlnk->bSetTime=false; ptlnk->bMSend=true; ptlnk->us0_set_time = ustimer_get_origin(); } // 遥控 else if(pt->yk_send_flag) { u8 dat[12]; int i,num=0; for(i=0;iyk_send_flag & (1<>8); dat[num++]=0; if(g_lnk_yk[i].data[IECLINK_YK_SND].ti == 0xff) { dat[num]=g_lnk_yk[i].data[IECLINK_YK_SND].v|0x80; lnk_104_call(pt,46,1,g_lnk_yk[i].data[IECLINK_YK_SND].cot,dat,num+1); dat[num]=g_lnk_yk[i].data[IECLINK_YK_SND].v; lnk_104_call(pt,46,1,g_lnk_yk[i].data[IECLINK_YK_SND].cot,dat,num+1); } else { dat[num++]=g_lnk_yk[i].data[IECLINK_YK_SND].v; lnk_104_call(pt,g_lnk_yk[i].data[IECLINK_YK_SND].ti,1,g_lnk_yk[i].data[IECLINK_YK_SND].cot,dat,num); } g_lnk_yk[i].flag[IECLINK_YK_SND]=false; ptlnk->bMSend=true; // 清除标志 pt->yk_send_flag &= ~(1<par_send_flag) { u8 dat[256]; int i,num=0; int len=0; for(i=0;ipar_send_flag & (1<dtpartime[i]=ustimer_get_origin(); #endif pt->par_send_flag &= ~(1<dtpartime[i]=ustimer_get_origin(); #else g_link_par[i].flag[IECLINK_YK_SND]=false; #endif pt->par_send_flag &= ~(1<dtpartime[i]=ustimer_get_origin(); #else g_link_par[i].flag[IECLINK_YK_SND]=false; #endif pt->par_send_flag &= ~(1<bMSend=true; break; } } } #ifdef YPARA_LINK //遥参 else if(get_queue_count(&pt->par_queue.queue) > 0) { u8 dat[256]; int i=0,num=0; msg_data_struct *msg_data =&pt->temp_par; get_data_queque(&pt->par_queue.queue,(u8 *)msg_data); //rt_printf("-----104级联:::遥参下发\r\n"); //print_msg_base(ypara_msg); if(msg_data->type == modify_set) { msg_ypara_data_struct *ypara_msg = &msg_data->ypara_msg; /*定值区*/ dat[num++] = (u8)ypara_msg->section_p; dat[num++] = (u8)(ypara_msg->section_p>>8); if(ypara_msg->cmd == YP_SEL) { dat[num++] = 0x80; /*特征码*/ for(i=0;inum;i++) { dat[num++]=(u8)ypara_msg->base_data[i].cp_s; dat[num++]=(u8)(ypara_msg->base_data[i].cp_s>>8); dat[num++]=0; dat[num++] = ypara_msg->base_data[i].val_iec.tag; dat[num++] = ypara_msg->base_data[i].val_iec.size; if(ypara_msg->base_data[i].val_iec.size >0) { memcpy(&dat[num],ypara_msg->base_data[i].val_iec.value,ypara_msg->base_data[i].val_iec.size); num += ypara_msg->base_data[i].val_iec.size; } } } else if(ypara_msg->cmd == YP_EXE) { dat[num++] = 0; /*特征码*/ set_read_all(pt); } else { dat[num++] = 0x40; /*特征码*/ } if((ypara_msg->cmd == 2) || (ypara_msg->cmd == 1)) { lnk_104_call(pt,203,ypara_msg->num,6,dat,num); } else { lnk_104_call(pt,203,ypara_msg->num,8,dat,num); } pt->sport = msg_data->sport; ptlnk->bMSend=true; } else if(msg_data->type == settion_swht) { msg_oper_setion_struct *setion_msg = &msg_data->setion_msg; /*信息体地址0*/ dat[num++] = 0; dat[num++] = 0; dat[num++] = 0; /*定值区*/ dat[num++] = (u8)setion_msg->section_p; dat[num++] = (u8)(setion_msg->section_p>>8); lnk_104_call(pt,200,1,6,dat,num); pt->sport = msg_data->sport; ptlnk->bMSend=true; } } else if(ptlnk->bSet_all) { u8 dat[4]; int num=0; dat[num++]=0; //当前定值区 dat[num++]=0; //当前定值区 lnk_104_call(pt,202,0,6,dat,num); clear_read_all(pt); ptlnk->bMSend=true; } // 空闲时,以500ms间隔召二级数据 #endif #ifdef RCD_STRAN_M else if((ptlnk->bRcd) && (ptlnk->bRcding == false) && (get_queue_count(&pt->rcd_m.queue) <= 0) && (pt->tft.bTransing == false) && (tRunPara.b_lb_master || (pt->b_lb_master))) /*没有文件传输*/ { u8 dat[4]; int num=0; dat[num++]=0; dat[num++]=0; lnk_104_call(pt,IECLINK_RCD,1,6,dat,num); ptlnk->bMSend=true; ptlnk->bRcding = true; ptlnk->dRcdingTime = ustimer_get_origin(); ptlnk->bRcd=false; } #endif // 空闲时,以500ms间隔召二级数据 else if(lnk_file_check_trans(pt)) { lnk_test_file_trans(pt); } // 子站测试帧应答 if(pt->bTestAck) { lnk_104_ack(pt,FRAME_U_TEST_ACK); pt->bTestAck = false; } // 发送S帧 if(((pt->RecvNum.ss - pt->AckRecvNum) >=tRunPara.w104W) ||((pt->bSendS ==2) || ((pt->bSendS == 1) && (dTCounter-ptlnk->dTInteral > 5*T_1s))) ) { lnk_104_sAck(pt); pt->bSendS = 0; } } void lnk_104_par_timer(IECLINK_DEF *pt) { int i=0; int flag=0; for(i=0;ipar_send_flag & (1<dtpartime[i]) > 10*USTIMER_SEC) /*10秒遥参*/ { rt_printf("--------遥参超时!!!\r\n"); g_link_par[i].flag[IECLINK_YK_SND] = false; } } } } void lnk_104_app_timer(int net) { IECLINK_DEF *pt = &g_link_104[net]; LNK_STATUS *ptlnk=&pt->tlnk; if(!ptlnk->bCallAll) { if(dTCounter-ptlnk->dTCallAllTime>pt->callalltime) // 10分钟总召一次 { ptlnk->bCallAll=true; ptlnk->dTCallAllTime=dTCounter; } } #ifdef FUNC_MORE_PREREAD //lnk_104_par_timer(pt); #endif #ifdef RCD_STRAN_M if(ustimer_get_duration(ptlnk->dTRcdTime) > 1*USTIMER_SEC) /*10秒间隔*/ { ptlnk->bRcd = true; ptlnk->dTRcdTime=ustimer_get_origin(); } if(ptlnk->bRcding) { u8 tmp[64]; if(ustimer_get_duration(ptlnk->dRcdingTime)>(10*USTIMER_SEC)) /*10秒无文件内容,超时*/ { sprintf(tmp,"link[%d]::查询录波应答超时!!!!!!!",pt->chnl+1); log_str_time(LOG_OPERATE,tmp,0,1); ptlnk->bRcding = false; } } if(pt->tft.bTransing) { u8 tmp1[128]; if(ustimer_get_duration(pt->tft.us0_file_trans)>(10*USTIMER_SEC)) /*10秒无文件内容,超时*/ { sprintf(tmp1, "BAY%02d%s读文件传输超时(%d)!!!!!!!", pt->chnl+1,pt->tft.filename+5,pt->tft.offset); /*104替换成级联通道号*/ log_str_time(LOG_OPERATE,tmp1,0,1); pt->tft.bTransing=false; } } #endif // 检查对时间隔 if(ustimer_get_duration(ptlnk->us0_set_time) > 5*60*USTIMER_SEC) { ptlnk->bSetTime = true; } // 检查测试帧超时 if(pt->bStartTest)//启动了 { if(ustimer_get_duration(pt->us0_test_wait)>(tRunPara.w104AckTime*USTIMER_SEC)) { // 测试帧没有及时返回,主动关闭连接 rt_printf_time("级联104(%d) 测试帧超时!\r\n",net); net_104link_close(net); return; } } else if(ustimer_get_duration(pt->us0_test) > (tRunPara.w104TestTime*USTIMER_SEC))//超时测试 { // 发送测试帧 lnk_104_ack(pt,FRAME_U_TEST); pt->us0_test=ustimer_get_origin(); pt->us0_test_wait=ustimer_get_origin(); pt->bStartTest=true; } } void lnk_104_app(int net) { //通道未建立连接,直接返回 if(!net_104link_is_connect(net)) { return; } // 如果没有初始化,初始化 if(g_link104_init_ok[net] == 0) { lnk_104_init(net); g_link104_init_ok[net] = 1; } lnk_104_app_recv(net); lnk_104_app_send(net); lnk_104_app_timer(net); } static void _lnk_104_recv_reset(IECLINK_DEF *pt) { pt->nTypeCounter=0; pt->nRecvCnt=0; } void lnk_104_recv(int net,u8 cRcvData) { IECLINK_DEF *pt = &g_link_104[net]; pt->recvbuf[pt->nRecvCnt++]=cRcvData; switch(pt->nTypeCounter) { case 0: if( cRcvData==0x68) { pt->nTypeCounter=1; } else { _lnk_104_recv_reset(pt); } break; case 1: pt->nRecvLenth=cRcvData+2; pt->nTypeCounter=2; break; case 2: if(pt->nRecvCnt>=pt->nRecvLenth) /*报文接受完毕*/ { _lnk_104_recv_reset(pt); pt->bData=true; g_net_104link_data[net]=1; // 唤醒主循环 mainloop_wakeup(); } break; default: _lnk_104_recv_reset(pt); break; } } int lnk_info_printf(void) { int i; rt_printf("级联遥控信息:\n"); rt_printf("cp_m\tcp_s\tflg[0]\tflg[1]\tflg[2]\r\n"); for(i=0; icp_m,yk->cp_s,yk->flag[0],yk->flag[1],yk->flag[2]); } return 0; } /*********下面是文件传输,模拟主站程序,招目录后,招第一个文件******************/ void lnk_read_test_file(void) { int i; for(i=0; itft.bDir = true; } } for(i=0; itft.bUpdateStart = true; } } for(i=0; itft.bDir||pt->tft.bFile||pt->tft.bFileok||pt->tft.bwFile||pt->tft.bwTrans||pt->tft.b104ack||pt->tft.bUpdateStart||pt->tft.bUpdateEnd; return ret; } void lnk_test_file_trans(IECLINK_DEF *pt) { char * strdir="/app/data/filetest/"; u8 dirlen; dirlen=strlen(strdir); if(pt->tft.bDir) //招目录 { u8 dat[128]; int num=0; dat[num++]=0; // 信息体地址 dat[num++]=0; if(pt->type==IEC104_CHN)dat[num++]=0; dat[num++]=2; // 附加数据包类型 dat[num++]=1; // 读目录 dat[num++]=0; // ID dat[num++]=0; dat[num++]=0; dat[num++]=0; dat[num++]=dirlen; memcpy(&dat[num],strdir,dirlen); num+=dirlen; dat[num++]=0; // 召唤标识 :0 全部 :1 时间范围内 // 起始时间 dat[num++]=0; //MsL dat[num++]=0; //MsH dat[num++]=0; //Min dat[num++]=0; //hour dat[num++]=1; //Day dat[num++]=1; //month dat[num++]=17; //year // 结束时间 dat[num++]=0; //MsL dat[num++]=0; //MsH dat[num++]=10; //Min dat[num++]=15; //hour dat[num++]=21; //Day dat[num++]=2; //month dat[num++]=17; //year if(pt->type==IEC101_CHN) { lnk_101_call(pt,210,1,5,dat,num); } else { lnk_104_call(pt,210,1,5,dat,num); } pt->tft.bDir=false; } if(pt->tft.bFile) //召文件 { u8 dat[128]; int num=0; dat[num++]=0; // 信息体地址 dat[num++]=0; if(pt->type==IEC104_CHN)dat[num++]=0; dat[num++]=2; // 附加数据包类型 dat[num++]=3; // 读文件 dat[num++]=pt->tft.fnamelen; memcpy(&dat[num],pt->tft.filename,pt->tft.fnamelen); num+=pt->tft.fnamelen; if(pt->type==IEC101_CHN) { lnk_101_call(pt,210,1,5,dat,num); } else { lnk_104_call(pt,210,1,5,dat,num); } pt->tft.bFile=false; } if(pt->tft.bFileok) //文件传输确认 { u8 dat[128]; int num=0; dat[num++]=0; // 信息体地址 dat[num++]=0; if(pt->type==IEC104_CHN)dat[num++]=0; dat[num++]=2; // 附加数据包类型 dat[num++]=6; // 读文件 dat[num++]=(u8)pt->tft.fileid; // ID dat[num++]=(u8)(pt->tft.fileid>>8); dat[num++]=(u8)(pt->tft.fileid>>16); dat[num++]=(u8)(pt->tft.fileid>>24); dat[num++]=(u8)pt->tft.offset; // 偏移 dat[num++]=(u8)(pt->tft.offset>>8); dat[num++]=(u8)(pt->tft.offset>>16); dat[num++]=(u8)(pt->tft.offset>>24); dat[num++]=(pt->tft.offset+FILE_SEND_FRAME_LENTH)>=pt->tft.filelenth?0:1; // 有无后续 if(pt->type==IEC101_CHN) { lnk_101_call(pt,210,1,6,dat,num); } else { lnk_104_call(pt,210,1,6,dat,num); } pt->tft.bFileok=false; } if(pt->tft.bwFile) // 写文件 { u8 dat[128]; int num=0; #if defined(CPU_AM335X) char* ko_path ="/app/data/335x_dftu.ko"; char *filename="335x_dftu.ko"; #else char* ko_path ="/app/data/dftu.ko"; char *filename="dftu.ko"; #endif int namelen=strlen(filename); struct file *handle; loff_t pos; int ret; handle= rt_file_open(ko_path,O_RDONLY ,0); if(IS_ERR(handle)) { rt_printf("打开%s,失败",ko_path); pt->tft.bwFile=false; return; } //得到文件长度 pt->tft.wfilelenth = rt_file_getfile_size(handle); if(pt->tft.wfilelenth == 0) { rt_file_close(handle,0); return; } //分配内存 pt->tft.wbuf = rt_malloc(pt->tft.wfilelenth); if(pt->tft.wbuf == NULL) { pt->tft.bwFile=false; rt_printf("%s: 分配内存失败\r\n",__func__); return; } //读出文件内容 pos=0; ret = rt_file_read(handle,pt->tft.wbuf, pt->tft.wfilelenth,&pos); if(ret != pt->tft.wfilelenth) { rt_file_close(handle,0); rt_printf("%s: read error:file_length=%d,ret=%d!\r\n",__func__,pt->tft.wfilelenth,ret); pt->tft.bwFile=false; rt_free(pt->tft.wbuf); return ; } pt->tft.wId=0x1234; dat[num++]=0; // 信息体地址 dat[num++]=0; if(pt->type==IEC104_CHN)dat[num++]=0; dat[num++]=2; // 附加数据包类型 dat[num++]=7; // 读文件 dat[num++]=namelen; memcpy(&dat[num],filename,namelen); num+=namelen; dat[num++]=(u8)pt->tft.wId; // ID dat[num++]=(u8)(pt->tft.wId>>8); dat[num++]=(u8)(pt->tft.wId>>16); dat[num++]=(u8)(pt->tft.wId>>24); dat[num++]=(u8)pt->tft.wfilelenth; // ID dat[num++]=(u8)(pt->tft.wfilelenth>>8); dat[num++]=(u8)(pt->tft.wfilelenth>>16); dat[num++]=(u8)(pt->tft.wfilelenth>>24); if(pt->type==IEC101_CHN) { lnk_101_call(pt,210,1,6,dat,num); } else { lnk_104_call(pt,210,1,6,dat,num); } pt->tft.bwFile=false; pt->tft.woffset=0; rt_printf("%s:malloc:file_length=%d,ret=%d!\r\n",__func__,pt->tft.wfilelenth,ret); } if(pt->tft.bwTrans) // 写文件 { u8 dat[256]; int num=0; int i; BYTE datalen=FILE_SEND_FRAME_LENTH; bool beof=false; BYTE checksum=0; static u32 us0_1=0; if((ustimer_get_duration(us0_1) tft.woffset+FILE_SEND_FRAME_LENTH)>=pt->tft.wfilelenth) { datalen=pt->tft.wfilelenth-pt->tft.woffset; //最后一帧传输的字节数 beof=true; pt->tft.bwTrans=false; } dat[num++]=0; // 信息体地址 dat[num++]=0; if(pt->type==IEC104_CHN)dat[num++]=0; dat[num++]=2; // 附加数据包类型 dat[num++]=9; // 写文件 dat[num++]=(u8)pt->tft.wId; // ID dat[num++]=(u8)(pt->tft.wId>>8); dat[num++]=(u8)(pt->tft.wId>>16); dat[num++]=(u8)(pt->tft.wId>>24); dat[num++]=(u8)pt->tft.woffset; // 偏移 dat[num++]=(u8)(pt->tft.woffset>>8); dat[num++]=(u8)(pt->tft.woffset>>16); dat[num++]=(u8)(pt->tft.woffset>>24); dat[num++]=beof?0:1; // 有无后续 for(i=0;itft.wbuf[pt->tft.woffset+i]; dat[num++] = dd; checksum+=dd; } dat[num++]=checksum; if(pt->type==IEC101_CHN) { lnk_101_call(pt,210,1,5,dat,num); } else { lnk_104_call(pt,210,1,5,dat,num); } if(beof) { if(!pt->tft.wbuf) { rt_free(pt->tft.wbuf); pt->tft.wbuf=NULL; } rt_printf("%s:写文件传输完毕,释放内存",__func__); } if(pt->type==IEC101_CHN) { pt->tft.bwTrans=false; } if(pt->type==IEC104_CHN) { pt->tft.woffset+=FILE_SEND_FRAME_LENTH; if(pt->tft.woffset>=pt->tft.wfilelenth) { pt->tft.bwTrans=false; } } } if(pt->tft.bUpdateStart) //文件升级启动 { u8 dat[128]; int num=0; dat[num++]=0; // 信息体地址 dat[num++]=0; if(pt->type==IEC104_CHN)dat[num++]=0; dat[num++]=0x80; // ctype if(pt->type==IEC101_CHN) { lnk_101_call(pt,211,1,6,dat,num); } else { lnk_104_call(pt,211,1,6,dat,num); } pt->tft.bUpdateStart=false; } if(pt->tft.bUpdateEnd) //文件升级结束 { u8 dat[128]; int num=0; dat[num++]=0; // 信息体地址 dat[num++]=0; if(pt->type==IEC104_CHN)dat[num++]=0; dat[num++]=0x00; // ctype if(pt->type==IEC101_CHN) { lnk_101_call(pt,211,1,6,dat,num); } else { lnk_104_call(pt,211,1,6,dat,num); } pt->tft.bUpdateEnd=false; } if(pt->tft.b104ack) { lnk_104_sAck(pt); pt->tft.b104ack=false; } } void lnk_test_file_frame(IECLINK_DEF *pt,u8 *pdat,u8 framelen) // { u8 cmd ,*pd; int i; #ifdef RCD_STRAN_M s32 ret=0; char tmp[128],tmp1[128]; static s32 testnum=0; struct dir_file_ext_struct *pdfs; struct dir_file_ext_struct *pdfs_min=0; int file_cnt = 0; u8 flag=0; #endif pdat+=1; cmd=pdat[0]; if(cmd==1) // 目录 { rt_printf("\r\n 收到目录 成功标识:%d ID:%d 后续标识:%d 文件数量:%d\r\n",pdat[1],(pdat[2]|(pdat[3]<<8)|(pdat[4]<<16)|(pdat[5]<<24)),pdat[6],pdat[7]); pd=&pdat[8]; for(i=0;i63) { rt_printf("\r\n文件长度错误!"); break; } memcpy(namestr,&pd[1],namelen); namestr[namelen]='\0'; pd+=namelen+2; filelen=(pd[0]|(pd[1]<<8)|(pd[2]<<16)|(pd[3]<<24)); pd+=4; rt_printf("\r\n 文件名长度:%d 名称:%s 长度:%d 时间:%d-%d-%d %d:%d:%d.%d\r\n",namelen,namestr,filelen,pd[6],pd[5],pd[4],pd[3],pd[2],(pd[1]*256+pd[0])/1000,(pd[1]*256+pd[0])%1000); pd+=7; if(i==0) { pt->tft.filelenth=filelen; pt->tft.fnamelen=namelen; memcpy(pt->tft.filename,namestr,namelen); pt->tft.bFile=true; } } } if(cmd==4) // 读文件激活 { u8 namestr[64],namelen; u32 id,filelen; pd=&pdat[2]; namelen=pd[0]; if(namelen>63) { rt_printf("\r\n文件长度错误!"); return; } memcpy(namestr,&pd[1],namelen); namestr[namelen]='\0'; pd+=namelen+1; id=pd[0]|(pd[1]<<8)|(pd[2]<<16)|(pd[3]<<24); pd+=4; filelen=pd[0]|(pd[1]<<8)|(pd[2]<<16)|(pd[3]<<24); rt_printf("\r\n 文件名长度:%d 名称:%s 长度:%d id:%d\r\n",namelen,namestr,filelen,id); //pt->tft.bFile=true; { if(pt->type==IEC104_CHN) { char fnstr[64]; sprintf(fnstr,"/tmp/rmtfile_%d",pt->chnl); pt->tft.handle = rt_file_open(fnstr,O_CREAT|O_RDWR|O_TRUNC,0); if(IS_ERR(pt->tft.handle)) { pt->tft.handle = 0; rt_printf("%s创建失败!\r\n",fnstr); pt->tft.bFile=false; return ; } } else { //创建文件 char *fnstr="/app/data/rmtfile"; pt->tft.handle = rt_file_open(fnstr,O_CREAT|O_RDWR|O_TRUNC,0); if(IS_ERR(pt->tft.handle)) { pt->tft.handle = 0; rt_printf("%s创建失败!\r\n",fnstr); pt->tft.bFile=false; return ; } } } pt->tft.fileid=id; pt->tft.filelenth=filelen; pt->tft.us0_file_trans = ustimer_get_origin(); } if(cmd==5) // 读文件响应 { loff_t pos; u32 id,offset; pd=&pdat[1]; id=pd[0]|(pd[1]<<8)|(pd[2]<<16)|(pd[3]<<24); pd+=4; offset=pd[0]|(pd[1]<<8)|(pd[2]<<16)|(pd[3]<<24); #ifdef RCD_STRAN_M pd+=4; flag = *pd++; /*结束标识*/ pos=offset; if(pt->tft.bTransing == false) return; rt_file_write(pt->tft.handle,pd,framelen-11,&pos); if(flag == 0) { rt_file_close(pt->tft.handle,0); if(strncmp(pt->tft.filename,"BAY",3) == 0) /*录波文件*/ { if(pt->type==IEC104_CHN) { sprintf(pt->tft.filename, "BAY%02d%s", pt->chnl+1,pt->tft.filename+5); /*104替换成级联通道号*/ } sprintf(tmp, "%s传输完成!!!",pt->tft.filename); log_str_time(LOG_OPERATE,tmp,0,1); sprintf(tmp, "%s%s", HF_WAVE_DIR,pt->tft.filename); if(pt->type==IEC104_CHN) { sprintf(tmp1,"/tmp/rmtfile_%d",pt->chnl); ret = rt_file_mv(tmp1, tmp); } else { ret = rt_file_mv("/app/data/rmtfile", tmp); } if(ret != 0) { rt_printf("%s 文件移动失败(ret=%d)!\r\n","/app/data/rmtfile",ret); rt_file_del("/app/data/rmtfile"); } sprintf(tmp, "/tmp/dev_rcd_%d",(int)testnum++); pdfs = hf_get_dir_file_ext(HF_WAVE_DIR, &file_cnt, tmp); if((file_cnt) > (NEWRCD_COUNT_M*2)*2) { rt_printf("file_cnt=%d***********************************\r\n",file_cnt); //找到最早的文件,并删除 pdfs_min = pdfs; for(i=1;ifile_name+11, 19) < 0) { pdfs_min = &pdfs[i]; } } //因为文件以及已经排好序,找到第一个是cfg文件,第二个是dat文件 //先删除.cfg文件 sprintf(tmp, "%s%s", HF_WAVE_DIR,pdfs_min->file_name); rt_file_del(tmp); sprintf(tmp, "%s%s", HF_WAVE_DIR,pdfs_min[1].file_name); rt_file_del(tmp); } if(pdfs) { rt_free(pdfs); } } pt->tft.bTransing =false; pt->tft.bFileok=false; pt->tft.offset=offset; } else { if(pt->type==IEC104_CHN) pt->tft.b104ack=true; pt->tft.us0_file_trans = ustimer_get_origin(); } #else pd+=5; pos=offset; rt_file_write(pt->tft.handle,pd,framelen-11,&pos); if(offset+FILE_SEND_FRAME_LENTH>=pt->tft.filelenth) { rt_file_close(pt->tft.handle,0); rt_printf("文件传输完毕!\r\n"); pt->tft.bFileok=true; pt->tft.offset=offset; } else if(pt->type==IEC101_CHN) { pt->tft.bFileok=true; pt->tft.offset=offset; } else if(pt->type==IEC104_CHN) { pt->tft.b104ack=true; } #endif } if(cmd==8) //写文件激活 { pt->tft.bwTrans=true; pt->tft.woffset=0; } if(cmd==10) //写文件确认 { u32 id,offset; pd=&pdat[1]; id=pd[0]|(pd[1]<<8)|(pd[2]<<16)|(pd[3]<<24); pd+=4; offset=pd[0]|(pd[1]<<8)|(pd[2]<<16)|(pd[3]<<24); pd+=5; pt->tft.bwTrans=true; pt->tft.woffset=offset+FILE_SEND_FRAME_LENTH; if(pt->tft.woffset>=pt->tft.wfilelenth) { pt->tft.bwTrans=false; if(pdat[9]==0) { pt->tft.bUpdateEnd=true; } } } } void lnk_update_file_frame(IECLINK_DEF *pt,u8 ctype) // { if(ctype&0x80) // 目录 { pt->tft.bwFile=true; } } /************************endfile**********************/