#include "host_sacnet103.h" CHostSacNet103Item::CHostSacNet103Item() { m_scn = 0; apdu_t0_max = 30; apdu_t1_max = 15; apdu_t2_max = 600; } CHostSacNet103Item::~CHostSacNet103Item() { m_scn = 0; apdu_t0_max = 30; apdu_t1_max = 15; apdu_t2_max = 600; } void CHostSacNet103Item::Attach(int uid, int sock, DWORD peer_addr, WORD peer_port) { CNetProcessItem::Attach(uid, sock, peer_addr, peer_port); m_scn = 0; apdu_t0_begin = 1; apdu_t1_begin = 1; apdu_t2_begin = 1; } void CHostSacNet103Item::Release(void) { m_scn = 0; apdu_t0_max = 30; apdu_t1_max = 15; apdu_t2_max = 600; CNetProcessItem::Release(); } CHostSacNet103Process::CHostSacNet103Process() { } CHostSacNet103Process::~CHostSacNet103Process() { } CNetProcessItem *CHostSacNet103Process::CreateItem(int ord) { return dynamic_cast(new CHostSacNet103Item); } void CHostSacNet103Process::DestroyItem(int ord, BOOLEAN bDeleted /* = FALSE */) { CHostSacNet103Item *pItem = (CHostSacNet103Item *)GetItem(ord); if (pItem != NULL && !bDeleted) { delete pItem; return CNetProcess::DestroyItem(ord, TRUE); } return CNetProcess::DestroyItem(ord, bDeleted); } BOOLEAN CHostSacNet103Process::UDPSend(BOOLEAN set_time, BOOLEAN broadcast, DWORD addr) { int sock; struct sockaddr_in broadcast_addr; memset(&broadcast_addr, 0,sizeof(broadcast_addr)); broadcast_addr.sin_family = AF_INET; broadcast_addr.sin_port = htons(m_option.net.target_port); if (broadcast) { broadcast_addr.sin_addr.s_addr = m_option.net.target_addr; } else if (addr != 0) { broadcast_addr.sin_addr.s_addr = addr; } sock = socket(AF_INET, SOCK_DGRAM, 0); optval_t opt = 1; if (broadcast) { if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt)) < 0) { vLog(LOG_ERROR, "UDP socket set broadcast error(%d,%s).\r\n", errno, strerror(errno)); close(sock); sock = -1; return FALSE; } } BYTE buffer[48]; memset(buffer, 0x00, sizeof(buffer)); buffer[0] = 0xff; buffer[9] = 'S'; buffer[10] = 'P'; buffer[11] = 'i'; buffer[12] = 's'; buffer[13] = 'o'; buffer[14] = 'f'; buffer[15] = 't'; buffer[16] = '-'; buffer[17] = 'C'; buffer[18] = 'M'; buffer[19] = 'G'; if (set_time) { unionCP56Time st; memset(&st, 0, sizeof(st)); memcpy(&st, &system32.now, sizeof(st)); get_system_time(&st); if ((st.millisecond % 1000) < 900) { buffer[1] = 1; buffer[2] = st.millisecond & 0xff; buffer[3] = (st.millisecond >> 8) & 0xff; buffer[4] = st.minute; buffer[5] = st.hour; buffer[6] = st.dayofmonth|st.dayofweek; buffer[7] = st.month; buffer[8] = st.year; } } if (sendto(sock, (const char *)buffer, 41, 0, (sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) < 0) { vLog(LOG_ERROR, "udp socket send error(%d,%s).\r\n", errno, strerror(errno)); close(sock); sock = -1; return FALSE; } DisplayTxData(buffer, 41, TRUE); close(sock); sock = -1; return TRUE; } BOOLEAN CHostSacNet103Process::OnPreCreate(int id) { int i, j, uid; CHostSacNet103Item *pItem; if (!CNetProcess::OnPreCreate(id)) return FALSE; if (!GetOption(&m_option, sizeof(m_option))) return FALSE; for (i = 0; i < PROCESS_UNIT_NUM; i++) { pItem = (CHostSacNet103Item *)GetItem(i); if (NULL == pItem) continue; uid = GetUnitID(i); if (uid < 0 || uid >= UNIT_NUM) continue; if (!GetUnitAddr(uid, (BYTE *)&pItem->m_addr, 4)) { //获取单元地址成功,则该段原地址采用配置地址,否则该单元为无效地址。 pItem->m_addr = 0; //配置地址 } #if 0 //获取单元CPU id if (!GetUnitOption(uid, &pItem->m_option, sizeof(pItem->m_option))) { //未获取配置,采用协议配置 vLog(LOG_ERROR, "Unit(%d) get unit configured error!\n", uid); continue; } else { if (pItem->m_option.cpu_count <= 0) { //没有cpu vLog(LOG_ERROR, "Unit(%d) not configured cpu ids!\n", uid); continue; } } #endif pItem->apdu_t0_max = m_option.reconnect_interval; pItem->apdu_t1_max = m_option.udp_send_interval; pItem->apdu_t2_max = m_option.interrogation_interval; pItem->Attach(uid, -1, 0, 0); } //upd广播等待下面设备链接 //UDPSend(TRUE); return TRUE; } int CHostSacNet103Process::GetAsdu10Length(BYTE* pData, int nLength) { BYTE i; int nRet = ASDUHEAD_DAT + 2; if ( nLength < nRet ) return 0; BYTE btTotal = pData[ASDUHEAD_DAT + 1] & 0xFF; for (i = 0; i < btTotal; i++) { if (nLength < nRet + GIN_LEN + KOD_LEN + GDD_LEN) return 0; int nDataLen = pData[nRet + GIN_LEN + KOD_LEN + 1] * (pData[nRet + GIN_LEN + KOD_LEN + 2] & 0x7F); nRet += GIN_LEN + KOD_LEN + GDD_LEN + nDataLen; } if (nLength < (nRet - 1)) return 0; return nRet; } int CHostSacNet103Process::GetAsdu23Length(BYTE* pData, int nLength) { int nRet = ASDUHEAD_DAT + (pData[ASDUHEAD_VSQ] & 0x7F) * 10; if (nLength < nRet) return 0; return nRet; } int CHostSacNet103Process::GetAsdu29Length(BYTE* pData, int nLength) { int nRet = ASDUHEAD_DAT + 3 + pData[ASDUHEAD_DAT + 2] * 5; if (nLength < nRet) return 0; return nRet; } int CHostSacNet103Process::GetAsdu30Length(BYTE* pData, int nLength) { int nRet = ASDUHEAD_DAT + 9 + MAKEWORD(pData[ASDUHEAD_DAT + 5], pData[ASDUHEAD_DAT + 6]) * 2; if (nLength < nRet) return 0; return nRet; } BOOLEAN CHostSacNet103Process::Run(void) { if (!CNetProcess::Run()) return FALSE; FeedDog(); return TRUE; } BOOLEAN CHostSacNet103Process::OnTimer(void) { int uid; int i, j; int time_gap; CHostSacNet103Item *pItem; BOOLEAN sec_changed = FALSE; BOOLEAN bSetTime = FALSE; if (!CNetProcess::OnTimer()) return FALSE; if (last_sec != (time_t)system32.timers) { last_sec = system32.timers; sec_changed = TRUE; } time_gap = GetSetTimeGap(); if (time_gap != 0 &&(system32.timers % time_gap) == 0 && sec_changed) { bSetTime = TRUE; } for (i = 0; i < PROCESS_UNIT_NUM; i++) { pItem = (CHostSacNet103Item *)GetItem(i); if (NULL == pItem) continue; uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) continue; //网络没有连接 if (pItem->GetSock() < 0) { if (pItem->apdu_t0_begin > 0 && system32.timers > (pItem->apdu_t0_begin + pItem->apdu_t0_max)) { pItem->apdu_t0_begin = system32.timers; UDPSend(bSetTime, FALSE, pItem->m_addr); } continue; } //TCP连接就表示该单元通讯正常 UnitFeedDog(uid); //遥控报文 if (GetYKFrame(pItem, i)) continue; if (sec_changed) { if (pItem->apdu_t1_begin > 0 && system32.timers > (pItem->apdu_t1_begin + pItem->apdu_t1_max)) { pItem->apdu_t1_begin = system32.timers; UDPSend(bSetTime, FALSE, pItem->m_addr); } if (pItem->apdu_t2_begin > 0 && system32.timers > (pItem->apdu_t2_begin + pItem->apdu_t2_max)) { pItem->apdu_t2_begin = system32.timers; if (!orgAsdu7(pItem, 0xff, i)) { vLog(LOG_ERROR, "Unit(%d) send IGI error.\n", uid); } #if 0 for (j = 0; j < pItem->m_option.cpu_count; j++) { if (!orgAsdu7(pItem, pItem->m_option.comm_addr[j], i)) { vLog(LOG_ERROR, "Unit(%d) send IGI error.\n", uid); } } #endif } } } return TRUE; } int CHostSacNet103Process::OnPackageReceived(BYTE* pBuf, int count, int ord) { int uid; int len = 0; CHostSacNet103Item* pItem; pItem = (CHostSacNet103Item *)GetItem(ord); if (NULL == pItem) return -1; uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return -1; if (count < 5) return 0; //处理接收到的报文 switch (pBuf[0]) { case M_IRC_NA_3: len = ASDU_5_SIZE; break; case M_GD_NA_3: len = GetAsdu10Length(pBuf, count); break; case M_LRD_TA_3: //被记录的扰动表ASDU23 len = GetAsdu23Length(pBuf, count); break; case M_RTD_TA_3: //扰动数据传输准备就绪ASDU26 len = ASDU_26_SIZE; break; case M_RTC_NA_3: //被记录的通道传输准备就绪ASDU27 len = ASDU_27_SIZE; break; case M_RTT_NA_3: //带标志的状态变位传输准备就绪ASDU28 len = ASDU_28_SIZE; break; case M_TDT_TA_3: // 传送带标志的状态变位ASDU29 len = GetAsdu29Length(pBuf, count); break; case M_TDN_NA_3: // 传送扰动值ASDU30 len = GetAsdu30Length(pBuf, count); break; case M_EOT_NA_3: //传送结束ASDU31 len = ASDU_31_SIZE; break; default: //不是ASDU报文,清除所有报文 return count; } if (len <= 0 || count < len) { //长度不足 vLog(LOG_DEBUG, "Unit(%d) recv(%02x %02x %02x) buffer is not enough(%d,%d)!\n", uid, pBuf[0], pBuf[1], pBuf[2], len, count); return 0; } SacNet103AsduProc(pItem, pBuf, ord); DisplayRxData(pBuf, len, TRUE, uid); UnitFeedDog(uid); return (len); } void CHostSacNet103Process::SacNet103AsduProc(CHostSacNet103Item* pItem, BYTE* buffer, int ord) { BYTE COT, INF, fun1, inf1, prop; BYTE Datalen, state; BYTE NGD1,Datalen1; BYTE comm_addr; BYTE param[4]; WORD pp; short YcValue = 0; int yxno, ycno, ykno; int i; DWORD dwValue = 0; float fValue = 0.0f; unionCP56Time st; if (NULL == pItem) return; int uid = pItem->GetUnitID(); if (uid < 0) return; memcpy(&st, &system32.now, sizeof(st)); COT = buffer[2]; comm_addr = buffer[3]; NGD1 = buffer[7]; param[0] = comm_addr; switch (buffer[0]) {//w1 case M_GD_NA_3://通用分类 pp = 7; for (i = 0; i < NGD1; i++) {//w2 fun1 = buffer[pp + 1]; param[1] = fun1; switch (fun1) //GIN { case 0x00: break; case 0x01: break;//printf("system process\n"); case 0x03://定值 break; case 0x04://动作 case 0x05://告警 { inf1 = buffer[pp + 2]; Datalen = buffer[pp + 5]; param[2] = inf1; yxno = GetUnitYXPointByParam(uid, param, 3); if ((buffer[pp + 7] & 0x03) == DPI_ON) state = SPI_ON; else state = SPI_OFF; if (yxno >= 0) { if ((COT == IEC103_COT_SPONT) || (COT == IEC103_COT_LOOP)) { st.millisecond = (buffer[pp + 8] + (buffer[pp + 9] << 8)); st.minute = buffer[pp + 10] & 0x7f; st.hour = buffer[pp + 11] & 0x1f; SetUnitSOE(uid, yxno, state, st); SetUnitYX(uid, yxno, state); } } } break; case 0x08://带时标的遥信类(如刀闸、开关、信号、状态等)soe case 0x18: case 0x0e: if (COT == IEC103_COT_SPONT) //处理遥信量变位报文 { inf1 = buffer[pp + 2]; Datalen = buffer[pp + 5]; if (fun1 == 0x18) param[1] = param[1] - 0x10; param[2] = inf1; yxno = GetUnitYXPointByParam(uid, param, 3); if ((buffer[pp + 7] & 0x03) == DPI_ON) state = SPI_ON; else state = SPI_OFF; if (yxno >= 0) { if (fun1 == 0x18) //只处理带时标的遥信报文 { st.millisecond = (buffer[pp + 8] + (buffer[pp + 9] << 8)); st.minute = buffer[pp + 10] & 0x7f; st.hour = buffer[pp + 11] & 0x1f; SetUnitSOE(uid, yxno, state, st); SetUnitYX(uid, yxno, state); } else { SetUnitYX(uid, yxno, state); } } } if ((COT == IEC103_COT_LOOP) || (COT == IEC103_COT_IGI)) //处理总召或循环数据的报文 { inf1 = buffer[pp + 2]; Datalen = buffer[pp + 5]; param[2] = inf1; if ((fun1 == 0x08) || (fun1 == 0x0e)) //遥信及软压板 { yxno = GetUnitYXPointByParam(uid, param, 3); if ((buffer[pp + 7] & 0x03) == DPI_ON) state = SPI_ON; else state = SPI_OFF; if (yxno >= 0) { SetUnitYX(uid, yxno, state); } } if (fun1 == 0x07) //遥测 { vLog(LOG_ERROR, "never be here.\n"); ycno = GetUnitYCPointByParam(uid, param, 3); if (ycno >= 0) { if (Datalen == 4) { dwValue = (DWORD)((buffer[pp + 10] << 24) | (buffer[pp + 9] << 16) | (buffer[pp + 8] << 8) | buffer[pp + 7]); memcpy(&fValue, &dwValue, Datalen); SetUnitYC(uid, ycno, fValue); } if (Datalen == 2) { YcValue = (buffer[pp + 7] + (buffer[pp + 8] << 8)); if (YcValue & 0x1000) { YcValue = (((~YcValue & 0xffff) | 0x1000) + 1); } if (YcValue > 16380) YcValue = 0; SetUnitYC(uid, ycno, (LONG)YcValue); } if (Datalen == 1) { YcValue = buffer[pp + 7]; SetUnitYC(uid, ycno, (LONG)YcValue); } } } } break; case 0x06: //遥测类(保护测量值) break; case 0x07: //遥测类(如电流、电压、功率、频率、水位、温度等) inf1 = buffer[pp + 2]; Datalen = buffer[pp + 5]; param[2] = inf1; ycno = GetUnitYCPointByParam(uid, param, 3); if (ycno >= 0) { if (Datalen == 4) { dwValue = (DWORD)((buffer[pp + 10] << 24) | (buffer[pp + 9] << 16) | (buffer[pp + 8] << 8) | buffer[pp + 7]); memcpy(&fValue, &dwValue, Datalen); SetUnitYC(uid, ycno, fValue); } if (Datalen == 2) { YcValue = (buffer[pp + 7] + (buffer[pp + 8] << 8)); if (YcValue & 0x1000) { YcValue = (((~YcValue & 0xffff) | 0x1000) + 1); } if (YcValue > 16380) YcValue = 0; SetUnitYC(uid, ycno, (LONG)YcValue); } if (Datalen == 1) { YcValue = buffer[pp + 7]; SetUnitYC(uid, ycno, (LONG)YcValue); } } break; case 0x09://遥信类 break; case 0x0a: break; //电量类 case 0x0b: /*遥控操作*/ INF = buffer[5]; inf1 = buffer[9]; //条目号 prop = buffer[14]; //数据(1:分 2:合) param[2] = inf1; ykno = GetUnitYKPointByParam(uid, param, 3); if (ykno >= 0) { switch (INF) { case 249:/*遥控选择*/ { BOOLEAN value = (prop == 0x02) ? TRUE : FALSE; SetUnitYK(uid, ykno, value, YKS_SELED, YKR_SUCC); vLog(LOG_WARN, "Unit(%d) yk(%d) %s state is YKS_SELED result is YKR_SUCC.\r\n", uid, ykno, (value ? "CLOSE" : "TRIP")); } break; case 250:/*遥控执行*/ { BOOLEAN value = (prop == 0x02) ? TRUE : FALSE; SetUnitYK(uid, ykno, value, YKS_EXEED, YKR_SUCC); vLog(LOG_WARN, "Unit(%d) yk(%d) %s state is YKS_EXEED result is YKR_SUCC.\r\n", uid, ykno, (value ? "CLOSE" : "TRIP")); } break; case 251:/*遥控撤消*/ { BOOLEAN value = (prop == 0x02) ? TRUE : FALSE; SetUnitYK(uid, ykno, value, YKS_ABRED, YKR_SUCC); vLog(LOG_WARN, "Unit(%d) yk(%d) %s state is YKS_ABRED result is YKR_SUCC.\r\n", uid, ykno, (value ? "CLOSE" : "TRIP")); } break; default: break; } } break; case 0x0d: break;//遥控分头类(升/降) default: break; } Datalen1 = buffer[pp + 5]; pp = pp + Datalen1 + 6; }//w2 break; /*扰动数据传输包括asdu23、asdu26、asdu27、asdu28、asdu29、asdu30、asdu31*/ case M_LRD_TA_3: //被记录的扰动表ASDU23 break; case M_RTD_TA_3: //扰动数据传输准备就绪ASDU26 break; case M_RTC_NA_3: //被记录的通道传输准备就绪ASDU27 break; case M_RTT_NA_3: //带标志的状态变位传输准备就绪ASDU28 break; case M_TDT_TA_3: // 传送带标志的状态变位ASDU29 break; case M_TDN_NA_3: // 传送扰动值ASDU30 break; case M_EOT_NA_3: //传送结束ASDU31 break; default: break; }//w1 } BOOLEAN CHostSacNet103Process::GetYKFrame(CHostSacNet103Item* pItem, int ord) { int uid, order; BYTE value, state, result; BYTE buffer[64]; if (NULL == pItem) return FALSE; memset(buffer, 0, sizeof(buffer)); uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return FALSE; if (!GetUnitYK(uid, order, value, state, result)) return FALSE; vLog(LOG_WARN, "Unit(%d) yk(%d) %s state is %s result is %s.\r\n", uid, order, (value ? "CLOSE" : "TRIP"), val_to_str( state, yk_state, "STATE= %d" ), val_to_str( result, yk_result, "RESULT= %d")); //获取遥控信息 BYTE* pParam = GetUnitYKParamByPoint(uid, order); if (NULL == pParam) return FALSE; BYTE comm_addr; BYTE groupno, itemno, prop, inf = 0; comm_addr = pParam[0]; groupno = pParam[1]; itemno = pParam[2]; if (value) prop = 2; else prop = 1; if (YKS_SELREQ == state) { inf = 249; } else if (YKS_EXEREQ == state) { inf = 250; } else if ((YKS_ABRREQ == state) || ((YKS_SELING == state || YKS_SELED == state) && YKR_OVER == result)) { inf = 251; } buffer[0] = 0x0a; buffer[1] = 0x81; buffer[2] = 40; buffer[3] = comm_addr; buffer[4] = 254; buffer[5] = inf; buffer[6] = 0; buffer[7] = 1; buffer[8] = groupno; buffer[9] = itemno; buffer[10] = 1; buffer[11] = 9; buffer[12] = 1; buffer[13] = 1; buffer[14] = prop; return sendToSacDev(pItem, buffer, 15, ord); } BOOLEAN CHostSacNet103Process::orgAsdu7(CHostSacNet103Item* pItem, BYTE comm_addr, int ord) { BYTE buffer[8]; if (NULL == pItem) return FALSE; memset(buffer, 0, sizeof(buffer)); buffer[0] = 0x07; //TYP buffer[1] = 0x81; // buffer[2] = 0x09; buffer[3] = comm_addr; buffer[4] = 0xff; //FUN buffer[5] = 0x00; buffer[6] = pItem->m_scn++; return sendToSacDev(pItem, buffer, 7, ord); } BOOLEAN CHostSacNet103Process::sendToSacDev(CHostSacNet103Item* pItem, BYTE* pBuf, int len, int ord) { if (NULL == pItem) return FALSE; if (!WriteData(pBuf, len, ord)) { vLog(LOG_ERROR, "Unit(%d) Send Frame Write Data Error.\r\n", pItem->GetUnitID()); return FALSE; } DisplayTxData(pBuf, len, TRUE); return TRUE; }