?? dev103.c
字號:
/*****************************************************************************
編寫人 :TT(06.2.21于淮鋼220變)
裝置說明:103規(guī)約,9600BD,偶校驗(yàn),485接口.
程序說明:上送保護(hù)信息,定值,軟壓板,對時.
*****************************************************************************/
#include "Dev103.h"
//接收中斷回調(diào)函數(shù),用以判斷數(shù)據(jù)幀的結(jié)束
static WORD c103_check_packet(const BYTE *p_data, WORD data_len)
{
if ((data_len == 1) && ((p_data[0] == 0x68) || (p_data[0] == 0x10)))
{
return UART_PKT_CON;
}
if (data_len < 5)
{
return UART_PKT_CON;
}
if (p_data[0] == 0x10 && data_len == 5 && p_data[4] == 0x16)
{
return UART_PKT_FIN;
}
else if (p_data[0] == 0x68 && data_len == p_data[1]+6 && p_data[data_len-1] == 0x16)
{
return UART_PKT_FIN;
}
return UART_PKT_CON;
}
//===================================================================
//設(shè)備初始化
BOOL IED_Initialize()
{
return DEV_Create_IED(g_ied_list, sizeof(g_ied_list)/sizeof(T_IED));
}
//===================================================================
//校驗(yàn)和
BYTE calc_check_sum(const BYTE *p_data, WORD data_len)
{
WORD i;
BYTE sum =0;
for(i=0;i<data_len;i++)
{
sum+=p_data[i];
}
return sum;
}
//===================================================================
//串口管理
WORD c103_serial_com(T_IED* p_ied,T_C103_FRAME* p_frame,BOOL brx)
{
WORD wSize,size,i;
m_c103_fcb[p_ied->dev_id] ^=0x20;//幀記數(shù)位取反
NU_Sleep(20);
switch(p_frame->type)
{
case FRAME_T_CON:
//固定幀長報文
m_tx_buf[0] =p_frame->type;
m_tx_buf[1] =p_frame->contral | m_c103_fcb[p_ied->dev_id];
m_tx_buf[2] =0x01;//p_frame->address;
m_tx_buf[3] =calc_check_sum(&m_tx_buf[1], 2);
m_tx_buf[4] =p_frame->endbyte;
wSize =5;
break;
case FRAME_T_VOL:
//可變幀長報文
m_tx_buf[0] =p_frame->type;
m_tx_buf[1] =p_frame->len;
m_tx_buf[2] =p_frame->len;
m_tx_buf[3] =p_frame->type;
m_tx_buf[4] =p_frame->contral | m_c103_fcb[p_ied->dev_id];
m_tx_buf[5] =0x01;//p_frame->address;
m_tx_buf[4 +p_frame->len] =calc_check_sum(&m_tx_buf[4], p_frame->len);
m_tx_buf[5 +p_frame->len] =p_frame->endbyte;
wSize =p_frame->len +6;
break;
default:
break;
}
//出現(xiàn)差錯重傳三次
for(i =0; i <3; i++)
{
UART_Write(m_dev_port, m_tx_buf, wSize);
if(!brx) break;
size=UART_Read(m_dev_port,m_rx_buf,2000);
if(size !=0) break;
NU_Sleep(200);
}
//接收報文分類
if(size)
{
p_ied->dev_flag |= DEV_F_ONLINE;//連接正常
switch(m_rx_buf[0])
{
case FRAME_T_CON://固定幀長
p_frame->type =FRAME_T_CON;
p_frame->contral =m_rx_buf[1];
p_frame->address =m_rx_buf[2];
p_frame->crc =m_rx_buf[3];
if(p_frame->crc ==calc_check_sum(&m_rx_buf[1],2)
&& p_ied->dev_data[0] == p_frame->address);//校驗(yàn)
{
memset(&m_rx_buf[5], 0, (UART_PACKET_SIZE-5));
return size;
}
break;
case FRAME_T_VOL://可變幀長
p_frame->type =FRAME_T_VOL;
p_frame->len =m_rx_buf[1];
p_frame->contral =m_rx_buf[4];
p_frame->address =m_rx_buf[5];
p_frame->crc =m_rx_buf[p_frame->len +4];
if(p_frame->crc ==calc_check_sum(&m_rx_buf[4], p_frame->len)
&& p_ied->dev_data[0] == p_frame->address);//校驗(yàn)
{
return size;
}
break;
}
}
if (brx && !size && p_frame->contral != 0x40) //超時無應(yīng)答發(fā)送復(fù)位(復(fù)位無應(yīng)答返回)
{
p_ied->dev_flag &=~DEV_F_ONLINE;
}
return 0;
}
//===================================================================
//用于初始化的串口函數(shù)。出現(xiàn)差錯不重傳,減少時間
WORD c103_serial_com_init(T_IED* p_ied,T_C103_FRAME* p_frame,BOOL brx)
{
WORD wSize,size,i;
m_c103_fcb[p_ied->dev_id] ^=0x20; //幀記數(shù)位取反
NU_Sleep(20);
switch(p_frame->type)
{
case FRAME_T_CON:
/* 固定幀長報文 */
m_tx_buf[0] =p_frame->type;
m_tx_buf[1] =p_frame->contral | m_c103_fcb[p_ied->dev_id];
m_tx_buf[2] =0x01;//p_frame->address;
m_tx_buf[3] =calc_check_sum(&m_tx_buf[1], 2);
m_tx_buf[4] =p_frame->endbyte;
wSize =5;
break;
case FRAME_T_VOL:
/* 可變幀長報文 */
m_tx_buf[0] =p_frame->type;
m_tx_buf[1] =p_frame->len;
m_tx_buf[2] =p_frame->len;
m_tx_buf[3] =p_frame->type;
m_tx_buf[4] =p_frame->contral | m_c103_fcb[p_ied->dev_id];
m_tx_buf[5] =0x01;//p_frame->address;
m_tx_buf[4 +p_frame->len] =calc_check_sum(&m_tx_buf[4], p_frame->len);
m_tx_buf[5 +p_frame->len] =p_frame->endbyte;
wSize =p_frame->len +6;
break;
default:
break;
}
UART_Write(m_dev_port, m_tx_buf, wSize);
size=UART_Read(m_dev_port,m_rx_buf,1000);
//接收報文分類
if(size)
{
p_ied->dev_flag |= DEV_F_ONLINE; //連接正常
switch (m_rx_buf[0])
{
case FRAME_T_CON: //固定幀長
p_frame->type =FRAME_T_CON;
p_frame->contral =m_rx_buf[1];
p_frame->address =m_rx_buf[2];
p_frame->crc =m_rx_buf[3];
if (p_frame->crc ==calc_check_sum(&m_rx_buf[1], 2)
&& p_ied->dev_data[0] == p_frame->address); //校驗(yàn)
{
memset(&m_rx_buf[5], 0, (UART_PACKET_SIZE-5));
return size;
}
break;
case FRAME_T_VOL: //可變幀長
p_frame->type =FRAME_T_VOL;
p_frame->len =m_rx_buf[1];
p_frame->contral =m_rx_buf[4];
p_frame->address =m_rx_buf[5];
p_frame->crc =m_rx_buf[p_frame->len +4];
if (p_frame->crc ==calc_check_sum(&m_rx_buf[4], p_frame->len)
&& p_ied->dev_data[0] == p_frame->address); //校驗(yàn)
{
return size;
}
break;
}
}
if (brx && !size && p_frame->contral != 0x40)
{
//超時無應(yīng)答發(fā)送復(fù)位(復(fù)位無應(yīng)答返回)
p_ied->dev_flag &=~DEV_F_ONLINE;
}
return 0;
}
//===================================================================
//請求一級用戶數(shù)據(jù)
BOOL c103_request_first(T_IED* p_ied)
{
T_DATE t_date;
T_EVENT t_event;
T_ALARM t_alarm;
T_LIST t_list;
T_DIC t_dic;
T_SOE t_soe;
T_DI t_di;
T_C103_FRAME t_frame;
T_C103_ASDU *p_asdu;
WORD di_lo;
WORD di_hi;
BYTE di_grp;
BYTE i;
t_frame.type = FRAME_T_CON;
t_frame.contral = 0x5a;
t_frame.address = (BYTE)p_ied->dev_data[0];
t_frame.len =3;
t_frame.endbyte =0x16;
if(!c103_serial_com(p_ied, &t_frame,1))
{
return false;
}
p_asdu = (T_C103_ASDU *) &m_rx_buf[6];
switch(p_asdu->type)
{
case ASDU5://設(shè)備標(biāo)識
break;
case ASDU8://總查詢結(jié)束
break;
case ASDU2://動作事件
if(p_asdu->cot != 1)
break;
SYS_Get_Clock(&t_date);
t_event.dev_id = m_rx_buf[9];
t_event.e_state =p_asdu->data[0] - 1;
t_event.e_date.msec =MAKEWORD(p_asdu->data[5],p_asdu->data[6]);
t_event.e_date.minute =p_asdu->data[7];
t_event.e_date.hour =p_asdu->data[8];
t_event.e_date.day =t_date.day;
t_event.e_date.month =t_date.month;
t_event.e_date.year =t_date.year;
t_list.l_type =LIST_T_EVENT;
t_event.e_code =C103_Get_Code(p_ied, &t_list, p_asdu->inf);
if(t_event.e_code!=0)
INF_Record_Event(&t_event);
break;
case ASDU1://自檢信息(硬壓板的信息是通過ASDU1上送的,以下作為遙信處理)
if((p_asdu->cot==1)||(p_asdu->cot==9))
{
SYS_Get_Clock(&t_date);
t_alarm.dev_id =m_rx_buf[9];
t_alarm.e_state =p_asdu->data[0] - 1;
t_alarm.e_date.msec =MAKEWORD(p_asdu->data[1],p_asdu->data[2]);
t_alarm.e_date.minute =p_asdu->data[3];
t_alarm.e_date.hour =p_asdu->data[4];
t_alarm.e_date.day =t_date.day;
t_alarm.e_date.month =t_date.month;
t_alarm.e_date.year =t_date.year;
t_list.l_type =LIST_T_ALARM;
t_alarm.e_code = C103_Get_Code(p_ied, &t_list, p_asdu->inf);
if(t_alarm.e_code!=0)
{
if((p_asdu->cot==1)&&(t_alarm.e_code<=(t_list.l_size-p_ied->dev_data[5])))
{
//告警事件(不上送壓板的事件信息)
INF_Record_Alarm(&t_alarm);
}
//告警事件和硬壓板的遙信
t_dic.dev_id = p_ied->dev_id;
t_dic.e_code = t_alarm.e_code;
t_dic.e_state = p_asdu->data[0] - 1;
INF_Record_Dic(&t_dic);
}
}
break;
case ASDU10://響應(yīng)ASDU21的報文(定值,描述...)
if(p_asdu->cot !=42 || p_asdu->fun !=254 || p_asdu->inf !=241)
break;
else
//此處要返回,讓通用報文處理.
return true;
case ASDU44://上送全遙信
break;
if(p_asdu->cot != 9) break;
if(p_asdu->fun != 1) break;
t_di.di_num = p_asdu->vsq * 16;
di_grp = (t_di.di_num + 31)/32;
for(i = 0; i < di_grp; i++)
{
di_lo = MAKEWORD(p_asdu->data[10*i + 0], p_asdu->data[10*i + 1]);
di_hi = MAKEWORD(p_asdu->data[10*i + 5], p_asdu->data[10*i + 6]);
t_di.di_val[i] = MAKEDWORD(di_lo, di_hi);
}
INF_Set_Di(p_ied->dev_id, &t_di);
break;
case ASDU40://變位遙信
break;
if(p_asdu->cot != 1)
break;
if(p_asdu->fun == 2)
{
t_dic.e_code = p_asdu->inf - DI_FIRST_INF+42;
}
else if(p_asdu->fun ==1 )
{
t_dic.e_code = p_asdu->inf - DI_FIRST_INF;//超過106個遙信需要計算FUN
}
else
return FALSE;
t_dic.dev_id = p_ied->dev_id;
t_dic.e_state= p_asdu->data[0];
INF_Record_Dic(&t_dic);
break;
case ASDU41://SOE
//break;
if(p_asdu->cot != 1)
break;
SYS_Get_Clock(&t_date);
t_soe.dev_id = p_ied->dev_id;
if(p_asdu->fun == 2)
{
t_soe.e_code = p_asdu->inf - DI_FIRST_INF+42;
}
else if(p_asdu->fun ==1 )
{
t_soe.e_code = p_asdu->inf - DI_FIRST_INF;
}
t_soe.e_state= p_asdu->data[0];
t_soe.e_date.msec = MAKEWORD(p_asdu->data[1],p_asdu->data[2]);
t_soe.e_date.minute= p_asdu->data[3];
t_soe.e_date.hour = p_asdu->data[4];
t_soe.e_date.day = t_date.day;
t_soe.e_date.month = t_date.month;
t_soe.e_date.year = t_date.year;
INF_Record_Soe(&t_soe);
break;
case ASDU64:
break;
default:
break;
}
//檢查是否有一級用戶數(shù)據(jù)
if((t_frame.contral &0x20)!=0)
{
return c103_request_first(p_ied);
}
if(t_frame.contral == 0x08 || t_frame.contral ==0x09)
{
return true;
}
return false;
}
//===================================================================
//請求二級用戶數(shù)據(jù)
BOOL c103_request_second(T_IED* p_ied)
{
T_C103_FRAME t_frame;
T_C103_ASDU *p_asdu;
T_MEASURE mea;
BYTE i;
t_frame.type = FRAME_T_CON;
t_frame.contral = 0x5b;
t_frame.address = (BYTE)p_ied->dev_data[0];
t_frame.len =3;
t_frame.endbyte =0x16;
if(!c103_serial_com(p_ied, &t_frame,1))
{
return false;
}
if(t_frame.type == FRAME_T_CON)
{
if((t_frame.contral &0x20)==0) //無所響應(yīng)的數(shù)據(jù)
return true;
}
else//遙測值
{
p_asdu = (T_C103_ASDU *) &m_rx_buf[6];
if(p_asdu->type != ASDU50 || p_asdu->cot != 0x02) return FALSE;
mea.ms_num = p_asdu->vsq;
for (i = 0; i < mea.ms_num; i++)
{
if (p_asdu->data[2*i+1] & 0x80)//負(fù)數(shù)
{
mea.ms_val[i] =(0-MAKEWORD(p_asdu->data[2*i]&0xf8, (p_asdu->data[2*i+1])))/8
& INF_MS_VALUE_MASK | INF_MS_NEGATIVE;
}
else
{
mea.ms_val[i] = (MAKEWORD(p_asdu->data[2*i]&0xf8, (p_asdu->data[2*i+1])))/8
& INF_MS_VALUE_MASK;
}
}
INF_Set_Measure(p_ied->dev_id, &mea);
}
if((t_frame.contral &0x20)!=0)
{
//有一級用戶數(shù)據(jù)
return c103_request_first(p_ied);
}
else
return FALSE;
}
//===================================================================
/* 主站ASDU21讀一個(組/條目)的屬性/值 */
/* p_ied: 設(shè)備標(biāo)識
ginh: 條目號(0:全部條目)
ginl: 組號 0 描述 1 參數(shù),2區(qū)號 3 保護(hù)定值 6 阮壓板 9 模擬量
kod: 數(shù)據(jù)類型
*/
static BOOL c103_generic_read(T_IED *p_ied, BYTE ginl, BYTE ginh, BYTE kod)
{
T_C103_FRAME t_frame;
T_C103_ASDU* p_asdu;
int i;
/* 構(gòu)建ASDU21通用分類讀命令 */
p_asdu =(T_C103_ASDU *)&m_tx_buf[6];
p_asdu->type =21;
p_asdu->vsq =0x81;
p_asdu->cot =42;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -