代码理解
IEC104NASlave.h窗口协议从站实现文件
已注释过内容不再注释,请参考
C++代码审阅–ice104协议从站(1)
C++代码审阅–ice104协议从站(2)
C++代码审阅–ice104协议从站(3)
C++代码审阅–ice104协议从站(4)
C++代码审阅–ice104协议从站(5)
C++代码审阅–ice104协议从站(6)
后面几篇内容只需了解iec104协议基础知识即可理解,请看以下链接
电力IEC104规约协议解读(含源码下载)
// IEC104Slave.cpp: implementation of the CIEC104Slave class.
//
//
#include "stdafx.h"
#include "IEC104NASlave.h"
#include "IEC104Slave.h"
#pragma comment (lib, "WS2_32.lib")
#define PORT 2404
#define CLIENT_NUM 10
#define MAX_NUM_WORD 1024
#define MAX_ASDU_LENGTH 249
#define NA_TRIP 1
#define NA_CLOSE 0
BOOL isYKACK = false;
BOOL isT1Start = false;
BOOL isT2Start = false;
BOOL isT3Start = false;
BOOL isRevI = false;
int timer_T1 = 0; // t1计数变量
int timer_T2 = 0; // t2计数变量
int timer_T3 = 0; // t3计数变量
int IMsgLen; // 遥测帧ASDU的长度
BYTE IMsg[249];
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
CIEC104Slave *iec104slave;
SOCKET currentSock;
SOCKET Server = NULL;
BOOL IsListeThr = TRUE;
BOOL IsTimerHandler = TRUE;
BOOL isRxHandler = TRUE;
BOOL isDealIFrameHandler = TRUE;
BOOL IsStart = TRUE;
BOOL isDealNoIFrameResponseS = TRUE;
//定义结构体类型;
typedef struct ClientInfo
{
SOCKET sock;
SOCKADDR_IN clientAddr; // 定义地址族
}ClientInfomation;
HANDLE hRevThread = NULL;
HANDLE hTrThread = NULL;
HANDLE hStartThread = NULL;
HANDLE hDealIFrameThread = NULL;
HANDLE hDealNOSResponse = NULL;
//
// Construction/Destruction
//
CIEC104Slave::CIEC104Slave()
{
iec104slave = this;
this->Connected = false;
SetParams();
hRevThread = 0;
hTrThread = 0;
hStartThread = 0;
// hDealIFrameThread = 0;
RxCounter = 0;
TxCounter = 0;
LastAckRx = 0;
LastAckTx = 0;
}
CIEC104Slave::~CIEC104Slave()
{
}
DWORD WINAPI CIEC104Slave::ListeThr(LPVOID lpParam)
{
while(IsListeThr) // IsListeThr
{
SOCKET client;
sockaddr_in from;
ClientInfomation SendSocket[CLIENT_NUM];
int currentClient=0;
int fromlen ;
fromlen = sizeof(from);
// printf(" 正在等待用户连接...\n");
client = INVALID_SOCKET;
while(INVALID_SOCKET == client && Server) // 只要服务器处于启动状态就应该等 && Server && Server && iec104slave->Connected
{
client = accept(Server, (struct sockaddr *)&from, &fromlen); //如果没有用户连接一直执行这句
}
isT3Start = true;
#if 1
if(!hTrThread)
{
hTrThread = CreateThread(0, 0, &TimerHandler, (LPVOID)&SendSocket[currentClient],0, NULL);
if(hTrThread==0)
{
AfxMessageBox("Create hTrThread Thread Failed!");
break;
}
}
#endif
// 建立连接后, 发送序号和接收序号清零
iec104slave->RxCounter = 0;
iec104slave->LastAckTx = 0;
timer_T3 = 0; // 启动T3定时器(连接建立)
// 设置界面内容
iec104slave->OnUpdateTime(3);
// 设置初始剩余时间
iec104slave->OnUpdateRemainTime(3, iec104slave->T3 - timer_T3);
currentClient=(currentClient+1)%10;
// printf("%s connected \n",inet_ntoa(from.sin_addr));
//record client socket;
SendSocket[currentClient].sock = client;
SendSocket[currentClient].clientAddr.sin_addr=from.sin_addr;
client = INVALID_SOCKET;
#if 1
if(!hRevThread)
{
hRevThread = CreateThread(NULL, 0, RxHandler, (LPVOID)&SendSocket[currentClient], 0, NULL);
if ( hRevThread == NULL )
{
// cout<<"Create Thread Failed!"<<endl;
AfxMessageBox("Create Thread Failed!");
break;
}
}
#endif
iec104slave->Connected = true;
Sleep(75);
}
if(hStartThread != NULL)
{
CloseHandle(hStartThread);
hStartThread = NULL;
}
return 0;
}
DWORD WINAPI CIEC104Slave::DealNOIFrameResponseS(LPVOID lpParam) // 未被确认的 I 帧最大数目 k
{
/*
while(isDealNoIFrameResponseS)
{
if((iec104slave->TxCounter - iec104slave->LastAckTx) >= (iec104slave->K)*2) // 发送的需要与最后响应的序号比较差值大于K
{
iec104slave->slave_stop(); // 断开连接
iec104slave->slave_start(); // 重新启动监听
iec104slave->TxCounter = 0;
iec104slave->LastAckTx = 0;
}
}
*/
if(hDealNOSResponse != NULL)
{
CloseHandle(hDealNOSResponse);
hDealNOSResponse = NULL;
}
return 0;
}
// RX Thread 消息接收线程
DWORD WINAPI CIEC104Slave::RxHandler(LPVOID lpParam)
{
CString str, ch;
char buf[65535];
int res = 0;
unsigned int j = 0;
unsigned char len = 0;
ClientInfomation *CientSocket = (ClientInfomation*)lpParam;
while(isRxHandler)
{
if(res != SOCKET_ERROR)
{
res = recv(CientSocket->sock, buf, sizeof(buf), 0);
int n = WSAGetLastError();
CString str, ch;
for(int i = 0; i<res; i++)
{
ch.Format(" %02x ", buf[i]);
str += ch;
}
str = "";
ch = "";
if(res <= 0 || res == WSAECONNRESET)
{
// TRACE( "Connection Closed.\n");
isT3Start = false; // 关闭t3定时器(断开连接时)
iec104slave->OnUpdateTime(3, TRUE);
iec104slave->OnUpdateRemainTime(3, timer_T3, TRUE);
iec104slave->OnUpdateTime(2, TRUE);
iec104slave->OnUpdateRemainTime(2, timer_T2, TRUE);
iec104slave->OnUpdateTime(1, TRUE);
iec104slave->OnUpdateRemainTime(1, timer_T1, TRUE);
isT2Start = FALSE;
isT1Start = FALSE;
timer_T1 = 0;
timer_T2 = 0;
timer_T3 = 0;
// 如果是主站将连接关闭则要在这里将相应的server也关闭
// closesocket(Server);
// WSACleanup();
iec104slave->TxCounter = 0;
iec104slave->RxCounter = 0;
// 更新界面
AfxMessageBox("连接已断开");
// 将当前的client销毁
// 如果是我断开的那我不需要做任何事情
// 如果是其他原因导致断开的我应该始终处于侦听状态
// iec104slave->OnUpdateWnd();
break;
}
/* 解析报文,根据接收的报文内容响应回复信息*/
j = 0;
len = 0;
while(j < (unsigned)res && res >= 6) // 68是启动字符 长度 控制域1-4
{
if(buf[j] == 0x68)
{
len = buf[j+1];
// call callback
iec104slave->OnRxMsg((BYTE*)&buf[j], len+2);
APCI *p = (APCI*) &buf[j];
currentSock = CientSocket->sock;
int n = (p->field1 & 0x03);
/* 以下分别处理U S I格式帧,函数封装*/
timer_T3 = 0; // 收到I/S/U格式帧T3复位 重新开始计数
iec104slave->OnUpdateTime(3);
iec104slave->OnUpdateRemainTime(3, iec104slave->T3-timer_T3);
int formatType = p->field1&0x03;
if(!hDealNOSResponse)
{
hDealNOSResponse = CreateThread(NULL, 0, DealNOIFrameResponseS, NULL, 0, NULL);
if(hDealNOSResponse==0)
{
AfxMessageBox("Create hDealNOSResponse Thread Failed!");
break;
}
}
if(formatType == 0 || formatType == 2)
{
int revSendNum = (p->field2<<8) | p->field1 ; // 接收序号也就是对方的发送序号
iec104slave->RxCounter = revSendNum;
/*
if(iec104slave->RxCounter == revSendNum)
iec104slave->RxCounter += 2; // 如果收到的发送序号与接收序号相等,接收序号加1
else if(iec104slave->RxCounter < revSendNum)
; // 有报文丢失
else if(iec104slave->RxCounter > revSendNum)
; // 发送方发生了重传
*/
// 公共地址 2字节
for(int i = 0; i< NA_IEC_104_ASDUADDRESSBYTE; i++)
iec104slave->CommonAsduAddress[i] = buf[NA_STARTASDUADDRESS +i +j];
// 信息体地址 3字节
for(int i=0; i<NA_IEC_104_INFORMATIONBYTE; i++)
iec104slave->InformationObject[i] = buf[NA_STARTINFORMATION+i+j];
isT2Start = false; // 关闭T2定时器
iec104slave->OnUpdateTime(2, TRUE);
iec104slave->OnUpdateRemainTime(2, timer_T2, TRUE);
// 启个线程去处理I格式帧
isRevI = true;
IMsgLen = len+2-sizeof(APCI);
memset(IMsg, 0, sizeof(IMsg));
memcpy(IMsg, (BYTE*)&buf[j+sizeof(APCI)], IMsgLen);
if(!hDealIFrameThread)
{
hDealIFrameThread = CreateThread(NULL, 0, DealIFrameHandler, (LPVOID)&buf, 0, NULL);
if(hDealIFrameThread==0)
{
AfxMessageBox("Create hDealIFrameThread Thread Failed!");
break;
}
}
iec104slave->Send_S_Msg(); // RTU每接收到一帧I帧都会发送一帧S帧用于确认
}
else
{
if(formatType == 1) /* S */
{
// 从第一次收到S帧开始启线程
isT2Start = false; // 关闭T2定时器
iec104slave->OnUpdateTime(2, TRUE);
iec104slave->OnUpdateRemainTime(2, timer_T2, TRUE);
iec104slave->LastAckTx = (p->field4<<8) | p->field3; // 获取接收序号,接收序号与发送序号比较
}
else
{
if(formatType == 3) /* U */
iec104slave->ProcessFormatU(p);
}
}
j = j + len + 1; // 考虑到一次可能接收到多个报文(每个报文以68开头)
_ASSERT(len < res); //ERROR
}
j++;
}
Sleep(75);
}
}
if(hRevThread != NULL)
{
CloseHandle(hRevThread);
hRevThread = NULL;
}
return 0;
}
int CIEC104Slave::Send_U_Msg(int cmd)
{
if(GetSockConnectStatus())
{
APCI header;
header.start = 0x68;
header.len=0x04;
header.field1 = 0x03 | cmd; // U-Format
header.field2 = 0;
header.field3 = 0;
header.field4 = 0;
if(send(currentSock, (const char*)&header, sizeof(header), 0) == SOCKET_ERROR)
{
printf(LastError, "send() failed with error: %d\n", WSAGetLastError());
TRACE(LastError);
slave_stop();
return -1;
}
// call callback
iec104slave->OnTxMsg((BYTE*)&header,sizeof(header));
iec104slave->timer_U_Testflag = false; // reset TestFR time-out
return 0;
}
return -1;
}
int CIEC104Slave::slave_start()
{
hRevThread = NULL;
hTrThread = NULL;
hStartThread = NULL;
hDealIFrameThread = NULL;
IsListeThr = TRUE;
IsTimerHandler = TRUE;
isRxHandler = TRUE;
isDealIFrameHandler = TRUE;
IsStart = TRUE;
isDealNoIFrameResponseS = TRUE;
WSADATA WSAData;
int WSAreturn;
//初始化套接字
WSAreturn = WSAStartup(MAKEWORD(2,2),&WSAData);
if(WSAreturn)
{
// cout<<"Init Windows Socket Failed::"<<GetLastError()<<endl;
AfxMessageBox("Init Windows Socket Failed");
return 0;
}
// 创建套接字
Server = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(Server ==INVALID_SOCKET)
{
// cout<<"Create Socket Failed::"<<GetLastError()<<endl;
AfxMessageBox("Create Socket Failed");
return 0;
}
sockaddr_in local;
local.sin_family = AF_INET;
//local.sin_addr.s_addr = inet_addr(IP_ADDRESS);
local.sin_addr.s_addr = INADDR_ANY;
// 绑定
local.sin_port = htons(PORT);
if(bind(Server,(sockaddr *)&local,sizeof(local)) ==SOCKET_ERROR)
{
// cout<<"Bind Socket Failed::"<<GetLastError()<<endl;
AfxMessageBox("Bind Socket Failed");
return 0;
}
if(listen(Server,CLIENT_NUM)==SOCKET_ERROR) // 侦听
{
// cout<<"listen Socket Failed::"<<GetLastError()<<endl;
AfxMessageBox("listen Socket Failed");
return 0;
}
AfxMessageBox("服务端已经启动");
hStartThread = CreateThread(NULL, 0, ListeThr, (LPVOID)this, 0, NULL);
if (hStartThread == NULL )
{
return -1;
}
return 0;
}
void CIEC104Slave::slave_stop()
{
int rev = closesocket(Server);
if(rev != 0)
{
int x = WSAGetLastError();
if(WSAGetLastError() == WSAENOTSOCK)
AfxMessageBox("closesocket");
int y = WSACleanup();
return;
}
this->Connected = false;
WSACleanup();
Server = NULL;
IsListeThr = FALSE;
IsTimerHandler = FALSE;
isRxHandler = FALSE;
isDealIFrameHandler = FALSE;
IsStart = FALSE;
isDealNoIFrameResponseS = FALSE;
if(hRevThread != NULL)
{
CloseHandle(hRevThread);
hRevThread = NULL;
}
if(hTrThread != NULL)
{
CloseHandle(hTrThread);
hTrThread = NULL;
}
if(hDealIFrameThread != NULL)
{
CloseHandle(hDealIFrameThread);
hDealIFrameThread = NULL;
}
if(hStartThread != NULL)
{
CloseHandle(hStartThread);
hStartThread = NULL;
}
if(hDealNOSResponse != NULL)
{
CloseHandle(hDealNOSResponse);
hDealNOSResponse = NULL;
}
}
BOOL CIEC104Slave::GetSockConnectStatus()
{
return Connected;
}
/* 解析I格式报文*/
int CIEC104Slave::ProcessFormatI(BYTE *msgbuf, unsigned int len)
{
// 应该将整个ASDU传输过来,而不应该只是一个ASDU头
unsigned short i;
AsduQualifier = msgbuf[NA_STARTQUALIFIER];
ASDU_header *header=NULL;
unsigned char num=0, cause=0, n=0;
bool seq=false;
int asdu=0;
header = (ASDU_header*)msgbuf;
num = header->qual & 0x7F; // number of objects.
if(header->qual & 0x80) // sequence of objects ?
seq = true;
cause = header->tx_cause_1; // cause of tx.
asdu = header->commom_asdu_2 << 8;
asdu |= header->commom_asdu_1;
// actual time
SYSTEMTIME st;
FILETIME ft;
GetSystemTime(&st);
SystemTimeToFileTime(&st,&ft);
// type identification
switch(header->type)
{
case 1: // 单点遥信
if(cause == 5)
NAIec104YXACK(msgbuf, len);
break;
case 11: // 遥测 标度化测量值
if(cause == 5)
NAIec104YCACK(msgbuf, len);
break;
case 15: // 电度值
break;
case 45: // 遥控
if(cause == 6 && !isYKACK) // 遥控返校
{
NAIec104YKACK(msgbuf, len);
isYKACK = true;
}
else if(cause == 6 && isYKACK) // 执行确认
{
NAIec104YKEXEACK(msgbuf, len);
isYKACK = false;
}
if(cause == 8) // 遥控撤销
NAIec104YKDeactACK(msgbuf, len);
break;
case 49:
if(cause == 5) // 遥调请求
NAIec104YTACK(msgbuf, len);
break;
case 47:
YkInformation = msgbuf[NA_STARTINFORMATION+NA_IEC_104_INFORMATIONBYTE];
YkReason = msgbuf[NA_STARTREASON];
YkObject = msgbuf[NA_STARTINFORMATION]+msgbuf[NA_STARTINFORMATION+1]*256;
YkObject -= 0xb01;
NAIec104ProcessYkYt();
break;
case 53: // 请求功图数据
NAIec104ProcessGT();
break;
case 55: // 请求历史数据
NAIec104ProcessHistory(msgbuf, len);
break;
case 100: // 总召唤命令 包含分组召唤和总召唤
NAIec104InterrogationAll();
break;
case 101: // 计数量召唤 电能脉冲召唤
Qcc = msgbuf[NA_IEC_104_QCC_POSITION];
FreezeSign = Qcc&0xc0;
FreezeSign>>=6;
PulseGroup = Qcc&0x3f;
NAIec104ProcessPulseAll();
break;
case 103: // 时钟同步
{
CString str, ch;
for(i=0;i<7;i++)
{
TimeSave[i] = msgbuf[NA_IEC_104_TIME_POSITION+i];
ch.Format(" %02x ", TimeSave[i]);
str += ch;
}
NAIec104ProcessTime();
}
break;
default:
return -1;
}
return 0;
}
int CIEC104Slave::Send_S_Msg()
{
if(GetSockConnectStatus())//
{
APCI header;
header.start = 0x68;
header.len = 0x04;
header.field1 = 0x01; // S-Format
header.field2 = 0x00;
header.field3 = RxCounter & 0xFE;
header.field4 = (RxCounter>>8) & 0xFF;
LastAckRx = RxCounter; // memorize last rx acknowledge
if(send(currentSock, (const char*)&header, sizeof(header), 0) == SOCKET_ERROR)
{
return -1;
}
// call callback
iec104slave->OnTxMsg((BYTE*)&header,sizeof(header));
iec104slave->timer_U_Testflag = false; // reset TestFR time-out
iec104slave->timer_S_Ackflag = false; // reset ACK time-out.
return 0;
}
return -1;
}
int CIEC104Slave::Send_I_Msg(BYTE *msgbuf, unsigned int len)
{
CString str, ch;
for(unsigned int i = 0; i<len; i++)
{
ch.Format(" %02x ", msgbuf[i]);
str += ch;
}
if(GetSockConnectStatus())
{
char buf[1024];
APCI *header = (APCI*)buf;
(*header).start = 0x68;
(*header).len = 0x04 + len;
(*header).field1 = TxCounter & 0xFE; // I-Format
(*header).field2 = (TxCounter>>8) & 0xFF;
(*header).field3 = RxCounter & 0xFE; // I-Format
(*header).field4 = (RxCounter>>8) & 0xFF;
CString str, ch;
ch.Format(" %02x ", (*header).field1);
str += ch;
ch.Format(" %02x ", (*header).field2);
str += ch;
ch.Format(" %02x ", (*header).field3);
str += ch;
ch.Format(" %02x ", (*header).field4);
str += ch;
LastAckRx = RxCounter; // memorize last rx acknowledge
memcpy(&buf[sizeof(APCI)],msgbuf,len);
if(send(currentSock, (const char*)buf, len + sizeof(APCI), 0) == SOCKET_ERROR)
{
printf(LastError, "send() failed with error: %d\n", WSAGetLastError());
TRACE(LastError);
slave_stop();
return -1;
}
// call callback
iec104slave->OnTxMsg((BYTE*)&buf, len + sizeof(APCI));
iec104slave->timer_U_Testflag = false; // reset TestFR time-out
iec104slave->timer_S_Ackflag = false; // reset ACK time-out.
// increment N(S) Send Sequence Number
TxCounter += 2;
return 0;
}
return -1;
}
void CIEC104Slave::ProcessFormatU(APCI *p)
{
if((p->field1 & 0xfc) == CMD_STARTV) // U启动
{
Send_U_Msg(CMD_STARTC);
}
else if((p->field1 & 0xfc) == CMD_STOPV) // U停止
{
Send_U_Msg(CMD_STOPC);
}
else if((p->field1 & 0xfc) == CMD_TESTV) // U测试
{
Send_U_Msg(CMD_TESTC);
}
else if((p->field1 & 0xfc) == CMD_TESTC) // U测试确认帧
{
isT1Start = false; // 关闭T1计时器(收到U测试确认帧)
// 将控件设置为无效
iec104slave->OnUpdateTime(1, TRUE);
iec104slave->OnUpdateRemainTime(1, timer_T1, TRUE);
}
}
void CIEC104Slave::NAIec104ProcessYkYt()
{
unsigned char YkAction;
// NS_RELATION Dear;
YkWhat=0; /* nothing */
if(YkReason==6)
{
if(YkInformation&0x80) /* YkSelect */
YkWhat=1;
else
YkWhat=2; /* YkExe */
}
else
if(YkReason==8) /* Esc */
YkWhat=3;
switch(YkWhat)
{
case 1: /* select */
ReceiveYkId = YkObject;
YkAction = YkInformation&0x03;
switch(YkAction)
{
case 1: /* Open */
YkCellAction = NA_TRIP;
break;
case 2: /* close */
YkCellAction = NA_CLOSE;
break;
default:
break;
}
break;
case 2: /* YkExe */
ReceiveYkId=YkObject;
YkAction=YkInformation&0x03;
switch(YkAction)
{
case 1: /* Open */
YkCellAction = NA_TRIP;
break;
case 2: /* close */
YkCellAction = NA_CLOSE;
break;
default:
YkCellAction = 0xff;
break;
}
break;
case 3: /* Esc */
ReceiveYkId = YkObject;
YkAction = YkInformation&0x03;
switch(YkAction)
{
case 1: /* Open */
YkCellAction = NA_TRIP;
break;
case 2: /* close */
YkCellAction = NA_CLOSE;
break;
default:
YkCellAction = 0xff;
break;
}
break;
default:
break;
}
}
void CIEC104Slave::NAIec104ProcessTime()
{
unsigned short i,Index;
ASDU msg;
msg.header.type = 103; // 时钟同步命令
msg.header.qual = 0x01; // number of elements
msg.header.tx_cause_1 = 0x07; // confirm
msg.header.tx_cause_2 = 0x00;
msg.header.commom_asdu_1 = CommonAsduAddress[0];
msg.header.commom_asdu_2 = CommonAsduAddress[1];
// group information
Index = 0;
msg.data[Index++] = InformationObject[0];
msg.data[Index++] = InformationObject[1];
msg.data[Index++] = InformationObject[2];
for(i=0; i<7; i++)
msg.data[Index++] = TimeSave[i];
Send_I_Msg((BYTE*)&msg, Index+6);
}
void CIEC104Slave::NAIec104InterrogationAll()
{
// 1. 总召确认
InterrogationConfirm();
// 2. 发送遥信所有数据 0-7共8组遥信数据
ReturnAllYXData();
// 3. 发送遥测所有数据 8-11共4组遥测数据
ReturnAllYCData();
// 5. 激活结束
InterrogationComplete();
}
/*****************总召唤确认*************************/
void CIEC104Slave::InterrogationConfirm()
{
ASDU msg;
msg.header.type = 0x64; // interrogation command
msg.header.qual = 0x01; // number of elements
msg.header.tx_cause_1 = 0x07; // confirm
msg.header.tx_cause_2 = 0x00;
msg.header.commom_asdu_1 = CommonAsduAddress[0];
msg.header.commom_asdu_2 = CommonAsduAddress[1];
// group information
msg.data[0] = InformationObject[0];
msg.data[1] = InformationObject[1];
msg.data[2] = InformationObject[2];
msg.data[3] = 20;
Send_I_Msg((BYTE*)&msg, 10);
}
/*****************总召唤结束*************************/
void CIEC104Slave::InterrogationComplete()
{
ASDU msg;
msg.header.type = 0x64; // interrogation command
msg.header.qual = 0x01; // number of elements
msg.header.tx_cause_1 = 0x0a; // confirm
msg.header.tx_cause_2 = 0x00;
msg.header.commom_asdu_1 = CommonAsduAddress[0];
msg.header.commom_asdu_2 = CommonAsduAddress[1];
// group information
msg.data[0] = InformationObject[0];
msg.data[1] = InformationObject[1];
msg.data[2] = InformationObject[2];
msg.data[3] = 20;
Send_I_Msg((BYTE*)&msg, 10);
}
/*****************返回所有遥信数据:共8组(0-7)*************************/
void CIEC104Slave::ReturnAllYXData()
{
unsigned char *p, start;
unsigned short Index;
unsigned long InformationObject, i;
CString ch, str;
#if 0
for(i = 0; i<288; i++)
{
if(i%10 == 0)
str += '\n';
ch.Format(" %02x ", ALLYXData[i]);
str += ch;
}
#endif
/* Send Yx total send 1024 yx 共288组数据*/
for(start=0; start<NA_IEC_104_TOTAL_YX_TIMES; start++)
{
ASDU msg;
msg.header.type = 0x01; // 单点信息
msg.header.qual = NA_IEC_104_ONCE_YX|0x80; // number of elements
msg.header.tx_cause_1 = 20;
msg.header.tx_cause_2 = 0x00;
msg.header.commom_asdu_1 = CommonAsduAddress[0];
msg.header.commom_asdu_2 = CommonAsduAddress[1];
// group information
Index = 0;
InformationObject = 0x01 + start*NA_IEC_104_ONCE_YX;
p = (unsigned char *)&InformationObject;
for(i= 0; i<NA_IEC_104_INFORMATIONBYTE; i++)
{
msg.data[Index++] = p[i];
}
#if 0
ch.Format(" %02x ", p[0]);
str += ch;
ch.Format(" %02x ", p[1]);
str += ch;
ch.Format(" %02x ", p[2]);
str += ch;
#endif
for(i = (InformationObject-1); i< (InformationObject+NA_IEC_104_ONCE_YX-1); i++)
{
msg.data[Index++] = ALLYXData[i];
}
Send_I_Msg((BYTE*)&msg, Index+6);
}
}
/*****************返回所有遥测数据:发60次,一次100个字节,一共5902,最后一次发02个*************************/
void CIEC104Slave::ReturnAllYCData()
{
/* Send Yc */
CString str, ch;
unsigned char *p, start;
unsigned short iIndex, i;
unsigned long InformationObject;
for(start=0; start<NA_IEC_104_TOTAL_YC_TIMES; start++)// NA_IEC_104_TOTAL_YC_TIMES
{
ASDU msg;
msg.header.type = 0x0b; // 标度化测量值
if(start != (NA_IEC_104_TOTAL_YC_TIMES-1))
{
msg.header.qual = NA_IEC_104_ONCE_YC|0x80; // number of elements
}
else
{
msg.header.qual = 0x81;
}
msg.header.tx_cause_1 = 20; // 响应总召
msg.header.tx_cause_2 = 0x00;
msg.header.commom_asdu_1 = CommonAsduAddress[0];
msg.header.commom_asdu_2 = CommonAsduAddress[1];
// group information
iIndex = 0;
InformationObject = 0x4001 + start*NA_IEC_104_ONCE_YC;
p = (unsigned char *)&InformationObject;
for(i= 0; i<NA_IEC_104_INFORMATIONBYTE; i++)
{
msg.data[iIndex++] = p[i];
ch.Format(" %02x ", p[i]);
str += ch;
}
if(start != (NA_IEC_104_TOTAL_YC_TIMES-1))
{
for(i = 0 + start*NA_IEC_104_ONCE_YC; i< NA_IEC_104_ONCE_YC+start*NA_IEC_104_ONCE_YC; i++)
{
msg.data[iIndex++] = LOBYTE(ALLYCData[i]);
msg.data[iIndex++] = HIBYTE(ALLYCData[i]);
msg.data[iIndex++] = 0x00;
}
}
else
{
for(i = 0 + start*NA_IEC_104_ONCE_YC; i< 1+start*NA_IEC_104_ONCE_YC; i++)
{
msg.data[iIndex++] = LOBYTE(ALLYCData[i]);
msg.data[iIndex++] = HIBYTE(ALLYCData[i]);
msg.data[iIndex++] = 0x00;
}
}
// int timeOrigin = GetTickCount();
// while((GetTickCount() - timeOrigin) < 50);
Sleep(75);
Send_I_Msg((BYTE*)&msg, iIndex + 6);
}
}
DWORD WINAPI CIEC104Slave::DealIFrameHandler(LPVOID lpParam)
{
while(isDealIFrameHandler) //
{
if(isRevI)
{
if(iec104slave->ProcessFormatI(IMsg, IMsgLen) != -1)
{
isRevI = false;
isT2Start = true; // 启动T2定时器
timer_T2 = 0; // 发送完I格式帧以后开始计时
iec104slave->OnUpdateTime(2);
iec104slave->OnUpdateRemainTime(2, iec104slave->T2 - timer_T2);
}
}
Sleep(75);
}
if(hDealIFrameThread != NULL)
{
CloseHandle(hDealIFrameThread);
hDealIFrameThread = NULL;
}
return 0;
}
void CIEC104Slave::NAIec104ProcessPulseAck()
{
ASDU msg;
msg.header.type = 101; // 电能脉冲召唤命令
msg.header.qual = 0x01; // number of elements
msg.header.tx_cause_1 = 0x07; // confirm
msg.header.tx_cause_2 = 0x00;
msg.header.commom_asdu_1 = CommonAsduAddress[0];
msg.header.commom_asdu_2 = CommonAsduAddress[1];
// group information
msg.data[0] = InformationObject[0];
msg.data[1] = InformationObject[1];
msg.data[2] = InformationObject[2];
msg.data[3] = Qcc;
Send_I_Msg((BYTE*)&msg, 10);
}
void CIEC104Slave::NAIec104ProcessPulseEnd()
{
ASDU msg;
msg.header.type = 101; // 电能脉冲召唤命令
msg.header.qual = 0x01; // number of elements
msg.header.tx_cause_1 = 0x0a; // over
msg.header.tx_cause_2 = 0x00;
msg.header.commom_asdu_1 = CommonAsduAddress[0];
msg.header.commom_asdu_2 = CommonAsduAddress[1];
// group information
msg.data[0] = InformationObject[0];
msg.data[1] = InformationObject[1];
msg.data[2] = InformationObject[2];
msg.data[3] = Qcc;
Send_I_Msg((BYTE*)&msg, 10);
}
void CIEC104Slave::NAIec104ProcessPulseAll()
{
/* First Send Confirm */
NAIec104ProcessPulseAck();
/* 累计量 */
ReturnALLYMData();
/* Send Pulse End Packet */
NAIec104ProcessPulseEnd();
}
/*****************返回所有电度值信息***********************/
void CIEC104Slave::ReturnALLYMData()
{
unsigned char *p;
unsigned short i, iIndex;
unsigned long InformationObject;
// WORD highWord;
// BYTE lowWordHighByte, lowWordLowByte;
ASDU msg;
msg.header.type = 15; // 电能脉冲召唤命令
msg.header.qual = NA_IEC_104_ONCE_YM|0x80; // number of elements 20, 连续的20个数据
msg.header.tx_cause_1 = 5; // 请求,被请求
msg.header.tx_cause_2 = 0x00;
msg.header.commom_asdu_1 = CommonAsduAddress[0];
msg.header.commom_asdu_2 = CommonAsduAddress[1];
iIndex = 0;
InformationObject = 0x6401;
p = (unsigned char *)&InformationObject;
for(i= 0; i<NA_IEC_104_INFORMATIONBYTE; i++)
{
msg.data[iIndex++] = p[i];
}
CString str, ch;
for(i = 0; i< NA_IEC_104_ONCE_YM; i++)
{
msg.data[iIndex++] = HIBYTE(HIWORD(ALLYMData[i]));
msg.data[iIndex++] = LOBYTE(HIWORD(ALLYMData[i]));
msg.data[iIndex++] = HIBYTE(LOWORD(ALLYMData[i]));
msg.data[iIndex++] = LOBYTE(LOWORD(ALLYMData[i]));
/*
int iTemp = 0;
ch.Format(" %08x ", ALLYMData[i]);
msg.data[iIndex++] = HIBYTE(HIWORD(ALLYMData[i]));
ch.Format(" %02x ", HIBYTE(HIWORD(ALLYMData[i])));
str += ch;
iTemp++;
msg.data[iIndex++] = LOBYTE(HIWORD(ALLYMData[i]));
ch.Format(" %02x ", LOBYTE(HIWORD(ALLYMData[i])));
str += ch;
msg.data[iIndex++] = HIBYTE(LOWORD(ALLYMData[i]));
ch.Format(" %02x ", HIBYTE(LOWORD(ALLYMData[i])));
str += ch;
msg.data[iIndex++] = LOBYTE(LOWORD(ALLYMData[i]));
ch.Format(" %02x ", LOBYTE(LOWORD(ALLYMData[i])));
str += ch;
*/
}
BYTE TEST[128];
memcpy(TEST, (BYTE*)&msg, iIndex+6);
for(i = 0; i< iIndex +6; i++)
{
ch.Format(" %02x ", TEST[i]);
str += ch;
}
Send_I_Msg((BYTE*)&msg, iIndex+6);
/*
if(isRevS)
{
Send_I_Msg((BYTE*)&msg, iIndex+6);
isRevS = false;
}
*/
}
void CIEC104Slave::NAIec104YKACK(BYTE *msgbuf, unsigned int len)
{
msgbuf[2] = 0x07;
Send_I_Msg(msgbuf, len);
}
void CIEC104Slave::NAIec104YKDeactACK(BYTE *msgbuf, unsigned int len)
{
msgbuf[2] = 0x09;
Send_I_Msg(msgbuf, len);
}
void CIEC104Slave::NAIec104YKEXEACK(BYTE *msgbuf, unsigned int len)
{
msgbuf[2] = 0x07;
Send_I_Msg(msgbuf, len);
}
void CIEC104Slave::NAIec104YTACK(BYTE *msgbuf, unsigned int len)
{
Send_I_Msg(msgbuf, len);
}
void CIEC104Slave::NAIec104YXACK(BYTE *msgbuf, unsigned int len)
{
BOOL isContinuous;
unsigned short dataNum, startPosition, iIndex, i;
// 解析可变结构限定词
// 解析信息体起始地址
// 取数据,组包
// {" 01 82 05 00 01 00 01 00 00 "}
BYTE lenSign;
lenSign = msgbuf[1];
// 判断是否连续
if(lenSign & 0x80)
isContinuous = true;// 连续
else
isContinuous = false;
// 求出有多少个数据
dataNum = lenSign & 0x7f;
WORD startAddress;
startAddress = MAKEWORD(msgbuf[6], msgbuf[7]);
startPosition = startAddress - 0x0001;
// 相对位置
ASDU msg;
msg.header.type = 0x01; // 单点遥信
msg.header.qual = dataNum|0x80; // number of elements
msg.header.tx_cause_1 = 0x05; // 请求,被请求
msg.header.tx_cause_2 = 0x00;
msg.header.commom_asdu_1 = msgbuf[4]; // 公共地址
msg.header.commom_asdu_2 = msgbuf[5];
iIndex = 0;
msg.data[iIndex++] = msgbuf[6];
msg.data[iIndex++] = msgbuf[7];
msg.data[iIndex++] = msgbuf[8];
for(i = 0; i<dataNum; i++)
{
msg.data[iIndex++] = ALLYXData[startPosition+i];
}
Send_I_Msg((BYTE*)&msg, iIndex +6); // 根据要求返回遥信数据,解析要回哪些地址的数据,要看限定词
}
void CIEC104Slave::NAIec104YCACK(BYTE *msgbuf, unsigned int len)
{
Send_I_Msg(msgbuf, len); // 根据要求返回遥测数据
}
DWORD WINAPI CIEC104Slave::TimerHandler(LPVOID lpParam)
{
while(IsTimerHandler)
{
// 间隔1s
int timeOrigin = GetTickCount();
while((GetTickCount() - timeOrigin) < 1000);
#if 1
// T1:RTU(服务器)端启动U格式测试过程后等待U格式测试应答的超时时间(超时处理:断开连接)
// 启动条件:发送U测试帧
// 关闭条件:接收U测试帧
if(isT1Start)
{
timer_T1++;
iec104slave->OnUpdateRemainTime(1, iec104slave->T1-timer_T1);
if(timer_T1 > iec104slave->T1)
{
// timer_T1 = 0;
AfxMessageBox("t1超时");
iec104slave->slave_stop();
}
}
#endif
#if 1
// T2: RTU(服务器)端
// 1) 以突发的传送原因向主站(客户)端上送了变化信息
// 2) 或以激活结束的传送原因向主站(客户)端上送了总召唤/电度召唤结束后
// 等待主站(客户)端回S格式的超时时间,若超过此时间还没有收到,就主动关闭TCP连接
// 处理完I格式帧后开始计时(置0),接收到S帧置0
// 启动条件:发送完所有I帧
// 关闭条件:收到S/I帧
if(isT2Start)
{
timer_T2++;
iec104slave->OnUpdateRemainTime(2, iec104slave->T2-timer_T2);
if(timer_T2 > iec104slave->T2)
{
timer_T2 = 0;
AfxMessageBox("t2超时");
iec104slave->slave_stop();
}
}
#endif
#if 1
// T3:当RTU(服务器)端和主站(客户)端之间没有实际的数据交换时,任何一端启动U格式测试过程的最大间隔时间(超时处理:发送U测)
// 启动条件:建立连接
// 关闭条件:断开连接
if(isT3Start)
{
timer_T3++;
iec104slave->OnUpdateRemainTime(3, iec104slave->T3-timer_T3);
if(timer_T3 > iec104slave->T3 && !isT1Start)
{
// timer_T3 = 0;
// AfxMessageBox("t3超时");
iec104slave->Send_U_Msg(CMD_TESTV);
isT1Start = true; // 启动T1计时器(发送U测试帧)
// 设置界面内容
iec104slave->OnUpdateTime(1);
// 设置初始剩余时间
timer_T1 = 0; // 发送完U测置0
iec104slave->OnUpdateRemainTime(1, iec104slave->T1 - timer_T1);
}
}
#endif
Sleep(75);
}
if(hTrThread != NULL)
{
CloseHandle(hTrThread);
hTrThread = NULL;
}
return 0;
}
void CIEC104Slave::SetParams(int t0, int t1, int t2, int t3, int k, int w)
{
T0 = t0;
T1 = t1;
T2 = t2;
T3 = t3;
K = k;
W = w;
}
void CIEC104Slave::startT2Timer()
{
isT2Start = true; // 启动T2定时器
timer_T2 = 0;
iec104slave->OnUpdateTime(2);
iec104slave->OnUpdateRemainTime(2, iec104slave->T2-timer_T2);
}
void CIEC104Slave::SetAllYXData(BYTE *yxBuf, int yxLen)
{
memcpy(ALLYXData, yxBuf, yxLen);
#if 0
CString ch, str;
for(int i = 0; i<yxLen; i++)
{
if(i%10 == 0)
str += '\n';
ch.Format(" %02x ", ALLYXData[i]);
str += ch;
}
AfxMessageBox(str);
#endif
}
void CIEC104Slave::SetAllYCData(WORD *ycBuf, int ycLen)
{
// memcpy(ALLYCData, ycBuf, ycLen);
memmove(ALLYCData, ycBuf, ycLen);
#if 0
CString str, ch;
for(int i = 0; i<2951; i++)
{
ch.Format(" %04x ", ALLYCData[i]);
str += ch;
}
str = "";
ch = "";
#endif
}
void CIEC104Slave::SetAllYMData(DWORD *ymBuf, int ymLen) // 电度量数据
{
memcpy(ALLYMData, ymBuf, ymLen);
}
void CIEC104Slave::MyMemcpy(void *dest, void *src, int len)
{
for(int i = 0; i< len; i++)
{
((char*)dest)[i] = ((char*)src)[i];
}
}
void CIEC104Slave::NAIec104ProcessGT()
{
// AfxMessageBox("读取功图命令");
// 从站->主站:应答功图数据
// 从站->主站:应答功图数据
// 从站->主站:应答功图数据
// 从站->主站:功图数据上传结束(RTU结束后自行解除冻结)
NAIec104ProcessGTEnd();
}
void CIEC104Slave::NAIec104ProcessGTEnd()
{
ASDU msg;
msg.header.type = 0x35; // 电能脉冲召唤命令
msg.header.qual = 0x01; // number of elements
msg.header.tx_cause_1 = 0x0a; // over
msg.header.tx_cause_2 = 0x00;
msg.header.commom_asdu_1 = CommonAsduAddress[0];
msg.header.commom_asdu_2 = CommonAsduAddress[1];
// group information
msg.data[0] = InformationObject[0];
msg.data[1] = InformationObject[1];
msg.data[2] = InformationObject[2];
msg.data[3] = 20;
Send_I_Msg((BYTE*)&msg, 10);
}
void CIEC104Slave::NAIec104ProcessHistory(BYTE *msgbuf, unsigned int len)
{
// 回复历史YX数据
// 回复历史YC数据
// 回复历史电度数据
// 回复历史GT数据
// 历史数据请求结束帧
NAIec104ProcessHistoryEnd(msgbuf, len);
}
void CIEC104Slave::NAIec104ProcessHistoryEnd(BYTE *msgbuf, unsigned int len)
{
/*
CString str, ch;
for(int i = 0; i<len; i++)
{
ch.Format(" %02x ", msgbuf[i]);
str += ch;
}
*/
msgbuf[2] = 0x0a;
Send_I_Msg(msgbuf, len);
}