关于电力行业104规约解析--固定帧程序解析

来源:互联网 发布:网络授课平台招收教师 编辑:程序博客网 时间:2024/06/05 10:03

很多朋友打开104规约要写程序了,但104规约文章很长,很难看,很难理解,对于初学的人员来说比较难理解:

其实104规约主要理解一下报头部分的控制报文。

如下:

 

//设置遥测APCI
void CMainFrame::SetYCAPCI()
{
 memset(byteAPDUYC,0,sizeof(byteAPDUYC));//初始化
 //计算报头字节  
 /////////////////////////////////APCI//////////////////////////////////////////////////////
 byteAPDUYC[0] = 0x68;//报头字
 byteAPDUYC[1] = 0xFA;//APDU长度,最大253 计算**
    
 byteAPDUYC[2] = 0x12;//1 8位控制域 低位  00000010
 byteAPDUYC[3] = 0x00;//2 8位控制域 高位  00000000  
    //                                      0000000000000010 I格式发送帧计数
 byteAPDUYC[4] = 0x02;//3 8位控制域 低位    00000010
 byteAPDUYC[5] = 0x00;//4 8位控制域 高位    00000000
    //                                       0000000000000010 I格式接收帧计数
 /////////////////////////////////ASDU//////////////////////////////////////////////////////
 byteAPDUYC[6] = 0x15;//标识符 遥测
 //可变帧限定词                          10111100 第一位1表示连续,如果为0表示非连续
 byteAPDUYC[7] = 0xBC;//计算**             0111100 60个数据
 //传送原因
 byteAPDUYC[8] = 0x14;//响应总召唤           传送原因
 byteAPDUYC[9] = 0x00;//响应总召唤           传送原因
}

 

理解了报头就知道了,我们在组包的时候就需要将数据加上,要计算数据的长度。

 

//发送遥信数据
void CMainFrame::SendYXData()
{
 //总遥信个数
 int iYXByteCout = dbm.yxsum;
 //APDU个数
 int iAPDUCout = 0;
 //最后一帧APDU字节数
 int iLastAPDUCout = 0;
 //最大遥信字节数
 int iMaxYx = 127;
 //得到APDU个数
 iAPDUCout = iYXByteCout / iMaxYx;
 //得到最后一帧APDU字节数
 iLastAPDUCout = iYXByteCout % iMaxYx;
    //循环组APDU
 for(int w=0;w<iAPDUCout;w++)
 {
  SetYXAPCI();
  //计算公共地址 ASDU地址
  BYTE *pXXTDZ = new byte[2]; 
  memcpy(pXXTDZ, &dbm.r_yx[w*iMaxYx].NU, 2);
  //给公共地址赋值
  byteAPDU[10] =pXXTDZ[0]; //ASDU地址 可能要累加计算** (低位在前,高位在后)2A 75
  byteAPDU[11] =pXXTDZ[1];
  //释放临存公共地址的空间
  free(pXXTDZ); 
  //信息体
  //如果SQ=0,表示非连续数据,一个三字节信息地址,一个一字节遥信数据
  //如果SQ=1,表示连续数据,用公用地址,然后连续一个字节遥信数据
  int iIndex = 0;//累加号
  for(int i=(w*iMaxYx);i<((w+1)*iMaxYx);i++)
  {
   byteAPDU[12+iIndex] = (BYTE)dbm.r_yx[i].val;
   iIndex++;
  }
  //校验和CS
  byteAPDU[12+iIndex] = 0x89;
  //结束标识
  byteAPDU[13+iIndex] = 0x16;
  //发送
  if(m_pMListenSocket->CheckpClientSocket(m_pMListenSocket->m_pClientSocket))
  {      
   //SetSendBufData(byteAPDU,sizeof(byteAPDU));
   m_pMListenSocket->m_pClientSocket->SendTo(byteAPDU,141,atoi(strPort),strIP);
   Sleep(100);
  }
 }
 //最后一个APDU组包
    SetYXAPCI();
 //计算APDU长度
 int ilastLen = iLastAPDUCout+10;
 BYTE *pAPDULEN = new byte[1];
 memcpy(pAPDULEN, &ilastLen, 1);
    byteAPDU[1] = pAPDULEN[0]; 
 //计算可变帧限定词
    BYTE *pAPDULENKB = new byte[1];
 memcpy(pAPDULENKB, &iLastAPDUCout, 1);
    byteAPDU[7] =(pAPDULENKB[0]|0x80);//高位补1
    free(pAPDULENKB);
    //计算公共地址 ASDU地址
 BYTE *pXXTDZ = new byte[2]; 
 memcpy(pXXTDZ, &dbm.r_yx[iAPDUCout*iMaxYx].NU, 2);
 //给公共地址赋值
 byteAPDU[10] =pXXTDZ[0]; //ASDU地址 可能要累加计算** (低位在前,高位在后)2A 75
 byteAPDU[11] =pXXTDZ[1];
 //释放临存公共地址的空间
 free(pXXTDZ);
 int iIndex = 0;//顺序号
 for(int i=(iAPDUCout*iMaxYx);i<iYXByteCout;i++)
 {
  byteAPDU[12+iIndex] = (BYTE)dbm.r_yx[i].val;
  iIndex++;
 }
 //校验和CS
    byteAPDU[12+iIndex] = pAPDULEN[0];//CS校验和 
 free(pAPDULEN);
 //结束标识
 byteAPDU[13+iIndex] =0x16;
 //发送
 if(m_pMListenSocket->CheckpClientSocket(m_pMListenSocket->m_pClientSocket))
 {
  //SetSendBufData(byteAPDU,sizeof(byteAPDU));
    m_pMListenSocket->m_pClientSocket->SendTo(byteAPDU,sizeof(byteAPDU),atoi(strPort),strIP);
  Sleep(100);
 }
}

原创粉丝点击