📄 dev103.c
字号:
/*****************************************************************************
编写人 :TT(06.2.21于淮钢220变)
装置说明:103规约,9600BD,偶校验,485接口.
程序说明:上送保护信息,定值,软压板,对时.
*****************************************************************************/
#include "Dev103.h"
//接收中断回调函数,用以判断数据帧的结束
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;
}
//===================================================================
//设备初始化
BOOL IED_Initialize()
{
return DEV_Create_IED(g_ied_list, sizeof(g_ied_list)/sizeof(T_IED));
}
//===================================================================
//校验和
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;//帧记数位取反
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;
}
//出现差错重传三次
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);//校验
{
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);//校验
{
return size;
}
break;
}
}
if (brx && !size && p_frame->contral != 0x40) //超时无应答发送复位(复位无应答返回)
{
p_ied->dev_flag &=~DEV_F_ONLINE;
}
return 0;
}
//===================================================================
//用于初始化的串口函数。出现差错不重传,减少时间
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; //帧记数位取反
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); //校验
{
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); //校验
{
return size;
}
break;
}
}
if (brx && !size && p_frame->contral != 0x40)
{
//超时无应答发送复位(复位无应答返回)
p_ied->dev_flag &=~DEV_F_ONLINE;
}
return 0;
}
//===================================================================
//请求一级用户数据
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://设备标识
break;
case ASDU8://总查询结束
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://响应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;
}
//检查是否有一级用户数据
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;
}
//===================================================================
//请求二级用户数据
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) //无所响应的数据
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)//负数
{
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)
{
//有一级用户数据
return c103_request_first(p_ied);
}
else
return FALSE;
}
//===================================================================
/* 主站ASDU21读一个(组/条目)的属性/值 */
/* p_ied: 设备标识
ginh: 条目号(0:全部条目)
ginl: 组号 0 描述 1 参数,2区号 3 保护定值 6 阮压板 9 模拟量
kod: 数据类型
*/
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;
/* 构建ASDU21通用分类读命令 */
p_asdu =(T_C103_ASDU *)&m_tx_buf[6];
p_asdu->type =21;
p_asdu->vsq =0x81;
p_asdu->cot =42;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -