📄 gprscomm.cs
字号:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.IO;
using System.Windows.Forms;
using System.Threading;
using System.Collections;
namespace GPRSDrvWinApp.gprs
{
#region 基础数据结构
//Gprs实时数据结构
public struct GprsData
{
public uint m_DeviceID; //设备号
public uint m_ChannelCount; //通道数
public uint[] m_ChannelData; //通道数据集
}
#endregion
#region GprsComm公共类
/// <summary>
/// GprsComm 的摘要说明。
/// </summary>
public class GprsComm
{
#region 成员变量
private GprsData gprsData;
private string errorMsg = "";
private uint validCount = 0; //有效包计数器
private uint invalidCount = 0; //无效包计数器
private uint totalCount = 0; //总接收包计数器
//RTU物理通道配置信息
public Hashtable htRtuPackage;
//Socket:从GPRS接收实时数据
public Socket SocketRecvFromGprs = null;
public EndPoint EndPointRecvFromGprs = null;
//Socket:发送实时数据到中控
public Socket SocketSendToCenter = null;
public EndPoint EndPointSendToCenter = null;
public string DebugFileName;
public uint ExceptionCount = 0;
public StreamWriter swDebugFile = null;
public System.Windows.Forms.StatusBar sbStatistic;
public System.Windows.Forms.ListBox lbData;
#region GPRS通讯包协议定义
//数据包的长度
public const uint GPRS_DATAPACK_WIDTH=512;
// GPRS包标志符位置和长度
public const uint GPRS_PACKID_INDEX = 0;
public const uint GPRS_PACKID_WIDTH = 4;
//GPRS的IP地址
public const uint GPRS_IP_INDEX = 4;
public const uint GPRS_IP_WIDTH = 4;
// GPRS包中设备号的位置和长度
public const uint GPRS_DEVICEID_INDEX=8;
public const uint GPRS_DEVICEID_WIDTH=4;
//包的数据类型
public const uint GPRS_DATA_RECV_TYPE_INDEX = 12;
//通道数据的起始位置
public const uint GPRS_CHANNEL_DATA_INDEX=13;
#endregion
#region 驱动程序 → 中控程序 通讯包协议定义
//包头代码168
public const byte CENTER_HEAD_IDENTIFIER = 0xA8; // 168
//包头索引号、字节数
public const uint CENTER_HEAD_INDEX = 0;
public const uint CENTER_HEAD_WIDTH = 1;
//包类型索引号、字节数
public const uint CENTER_TYPE_INDEX = 1;
public const uint CENTER_TYPE_WIDTH = 1;
//包总长度索引号、字节数
public const uint CENTER_LEN_INDEX = 2;
public const uint CENTER_LEN_WIDTH = 4;
//设备号索引号、字节数
public const uint CENTER_DEVICEID_INDEX = 6;
public const uint CENTER_DEVICEID_WIDTH = 4;
//包尾字节数、包尾代码169
public const uint CENTER_END_WIDTH = 1;
public const byte CENTER_END_IDENTIFIER = 0xA9; // 169
#endregion
#region 驱动程序 → 中控程序 中控实时数据包特有格式
//1:实时数据表类型为
public const byte CENTER_SEND_NORMALDATA_TYPE = 0x01;
// 包含通道个数
public const uint CENTER_SEND_NORMALDATA_NUM_INDEX = 10;
public const uint CENTER_SEND_NORMALDATA_NUM_WIDTH = 1;
// 实时数据开始
public const uint CENTER_SEND_NORMALDATA_INDEX = 11;
// 通道数据组织
public const uint CENTER_SEND_NORMALDATA_CHANNELKEY_WIDTH = 1;
public const uint CENTER_SEND_NORMALDATA_CHANNELVALUE_WIDTH = 4;
public const uint CENTER_SEND_NORMALDATA_CHANNELTOTAL_WIDTH = 5;
#endregion
#endregion
public delegate void showInfo_sub_delegate(string strInfo);
public delegate void showStatistic_sub_delegate(uint nTotal, uint nValid, uint nInvalid);
#region 构造函数
public GprsComm()
{
//TODO: 在此处添加构造函数逻辑
}
public GprsComm(DriverConfig driverCfg,String DebugFileName,ListBox lbData,StatusBar sbStatistic, Hashtable htRtuPackage)
{
gprsData = new GprsData();
//Socket:从GPRS接收实时数据
SocketRecvFromGprs = CreateBindedSocket(driverCfg.IpRecvFromGprs, driverCfg.PortRecvFromGprs.ToString());
EndPointRecvFromGprs = (EndPoint) new IPEndPoint(IPAddress.Any, 0);
//Socket:发送实时数据到中控
SocketSendToCenter = CreateBindedSocket(IPAddress.Any.ToString(), "0");
EndPointSendToCenter = (EndPoint) new IPEndPoint(IPAddress.Parse(driverCfg.IpSendToCenter), driverCfg.PortSendToCenter);
this.DebugFileName=DebugFileName;
this.lbData=lbData;
this.sbStatistic=sbStatistic;
//RTU物理通道配置信息
this.htRtuPackage = htRtuPackage;
}
#endregion
/// <summary>
/// 组中控的数据包
/// </summary>
/// <param name="kind">1:实时数据包 2:历史数据包 3:校时数据包</param>
/// <param name="nDeviceID">设备号</param>
/// <param name="bytesRecv">原始包</param>
/// <returns></returns>
private byte[] CreateCenterPackage(string kind, uint nDeviceID, byte[] bytesRecv)
{
byte[] SendToCenterBytes;
uint nSendBytesLength = 0;
byte[] FourBytesBuffer=new byte[4];
SendToCenterBytes=new byte[GPRS_DATAPACK_WIDTH];
switch(kind)
{
#region 实时数据
case "1":
if(SetNormalData(ref gprsData, nDeviceID, bytesRecv))
{
// 计算中控实时数据包的总长度,包含包头定义、通道数据和包尾
nSendBytesLength = CENTER_HEAD_WIDTH +
CENTER_TYPE_WIDTH +
CENTER_LEN_WIDTH +
CENTER_DEVICEID_WIDTH +
CENTER_SEND_NORMALDATA_NUM_WIDTH +
Convert.ToUInt16(gprsData.m_ChannelCount) * CENTER_SEND_NORMALDATA_CHANNELTOTAL_WIDTH +
CENTER_END_WIDTH;
SendToCenterBytes = new byte[nSendBytesLength];
SendToCenterBytes[CENTER_HEAD_INDEX] = CENTER_HEAD_IDENTIFIER;
SendToCenterBytes[CENTER_TYPE_INDEX] = CENTER_SEND_NORMALDATA_TYPE;
bool bBytesNumberFlag = MyTypeTranslator.UintToFourBytes(nSendBytesLength,ref FourBytesBuffer);
if(bBytesNumberFlag)
{
//设置长度
for(int i=0; i<CENTER_LEN_WIDTH; i++)
{
SendToCenterBytes[CENTER_LEN_INDEX+i] = FourBytesBuffer[i];
}
//设置实时包的设备号
bool bDeviceIDFlag=MyTypeTranslator.UintToFourBytes(gprsData.m_DeviceID,ref FourBytesBuffer);//
if(bDeviceIDFlag)
{
for(int i=0; i<CENTER_DEVICEID_WIDTH; i++)
{
SendToCenterBytes[CENTER_DEVICEID_INDEX+i]=FourBytesBuffer[i];
}
SendToCenterBytes[CENTER_SEND_NORMALDATA_NUM_INDEX] = Convert.ToByte(gprsData.m_ChannelCount);
for (int i = 0; i < gprsData.m_ChannelCount; i++)
{
SendToCenterBytes[CENTER_SEND_NORMALDATA_INDEX + i * 5] = Convert.ToByte(i + 1);//通道号是从1开始计算,故加1
bool bRTUChannelDataFlag=MyTypeTranslator.UintToFourBytes(gprsData.m_ChannelData[i],ref FourBytesBuffer);
if(bRTUChannelDataFlag)
{
for(int j=0; j < CENTER_SEND_NORMALDATA_CHANNELVALUE_WIDTH; j++)
{
SendToCenterBytes[CENTER_SEND_NORMALDATA_INDEX + i * 5 + j + 1]=FourBytesBuffer[j];
}
}
}
SendToCenterBytes[SendToCenterBytes.Length - 1] = CENTER_END_IDENTIFIER;
}
}
}
break;
#endregion
case "2":
#region 历史数据
break;
#endregion
case "3":
#region 终端时钟
#endregion
break;
default:
break;
}
return SendToCenterBytes;
}
#region 实时数据
/// <summary>
/// 设置实时数据
/// </summary>
/// <param name="gprsData"></param>
/// <param name="pString"></param>
/// <returns></returns>
private bool SetNormalData(ref GprsData gprsData, uint nDeviceID, byte[] bytesRecv)
{
try
{
gprsData.m_DeviceID = nDeviceID;
//判断RTU通道配置信息里是否包含此rtu设备
if (htRtuPackage.Contains(nDeviceID))
{
RtuPackage rtuPackage = (RtuPackage) htRtuPackage[nDeviceID];
//有效通道个数
gprsData.m_ChannelCount = (uint)rtuPackage.m_ValidChannelIndex.Length;
//填充通道数据
gprsData.m_ChannelData=FillChannel(rtuPackage, bytesRecv);
}
else
{
return false;
}
}
catch
{
return false;
}
return true;
}
#endregion
#region 填充RTU通道数据
/// <summary>
/// 填充通道
/// </summary>
/// <param name="strdata"></param>
/// <param name="channelcount"></param>
/// <returns></returns>
private uint[] FillChannel(RtuPackage rtuPackage, byte[] bytesRecv)
{
//有效通道个数
int channelCount = rtuPackage.m_ValidChannelIndex.Length;
uint[] arrChannelData = new uint[channelCount];
byte[] TwoBytesArray = new byte[2];
byte[] ThreeBytesArray = new byte[3];
byte[] FourBytesArray = new byte[4];
uint ChannelIndexBuf=GPRS_CHANNEL_DATA_INDEX;
uint ChannelValue=0;
//循环提取有效通道数据
for( int k=0; k<channelCount; k++)
{
bool bFlag = false;
switch(rtuPackage.m_ValidChannelWidth[k])
{
case 1:
ChannelValue = (uint)bytesRecv[ChannelIndexBuf + rtuPackage.m_ValidChannelIndex[k]];
arrChannelData[k] = ChannelValue;
ChannelValue=0;
break;
case 2:
for(int i=0;i<TwoBytesArray.Length;i++)
{
TwoBytesArray[i] = bytesRecv[ChannelIndexBuf + rtuPackage.m_ValidChannelIndex[k] + i];
}
bFlag=MyTypeTranslator.TwoBytesToUint(TwoBytesArray,ref ChannelValue);
if(bFlag)
arrChannelData[k] = ChannelValue;
ChannelValue=0;
break;
case 3:
for(int i=0;i<ThreeBytesArray.Length;i++)
{
ThreeBytesArray[i] = bytesRecv[ChannelIndexBuf + rtuPackage.m_ValidChannelIndex[k] + i];
}
bFlag=MyTypeTranslator.ThreeBytesToUint(ThreeBytesArray,ref ChannelValue);
if(bFlag)
arrChannelData[k] = ChannelValue;
ChannelValue=0;
break;
case 4:
for(int i=0;i<FourBytesArray.Length;i++)
{
FourBytesArray[i] = bytesRecv[ChannelIndexBuf + rtuPackage.m_ValidChannelIndex[k] + i];
}
bFlag=MyTypeTranslator.FourBytesToUint(FourBytesArray,ref ChannelValue);
if(bFlag)
arrChannelData[k] = ChannelValue;
ChannelValue=0;
break;
default:break;
}
}
return arrChannelData;
}
#endregion
/// <summary>
/// 返回一个已绑定的SOCKET对象
/// </summary>
/// <param name="ip">IP地址</param>
/// <param name="port">绑定的端口</param>
/// <returns></returns>
private Socket CreateBindedSocket(string ip,string port)
{
IPEndPoint ipepoint=new IPEndPoint(IPAddress.Parse(ip.Trim()),int.Parse(port.Trim()));
Socket socket=new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.Bind(ipepoint);
return socket;
}
#endregion
#region 公有方法
/// <summary>
/// 线程:接收来自GPRS设备的实时数据,并重新组包发送到中控
/// </summary>
public void StartRecvGPRSSendCenter()
{
Socket SocketRecvFromGprsBuffer = SocketRecvFromGprs;
EndPoint EndPointRecvFromGprsBuffer = EndPointRecvFromGprs;
Socket SocketSendToCenterBuffer = SocketSendToCenter;
EndPoint EndPointSendToCenterBuffer = EndPointSendToCenter;
System.Windows.Forms.ListBox listBox1Buffer = lbData;
System.Windows.Forms.StatusBar statusBar1Buffer = sbStatistic;
String DebugFileNameBuffer=DebugFileName;
uint ExceptionCountBuffer=ExceptionCount;
StreamWriter swDebugFileBuffer=null;
uint GPRS_DATAPACK_WIDTH_BUFFER=GPRS_DATAPACK_WIDTH; //包长度 512
uint GPRS_DEVICEID_INDEX_BUFFER=GPRS_DEVICEID_INDEX; //设备号位置
uint GPRS_DEVICEID_WIDTH_BUFFER=GPRS_DEVICEID_WIDTH; //设备号长度
int GPRS_CHANNEL_DATA_INDEX_BUFFER=(int)GPRS_CHANNEL_DATA_INDEX; //通道数据位置
// uint GPRS_DATA_RECV_TYPE_INDEX_BUFFER=GPRS_DATA_RECV_TYPE_INDEX; //数据包类型
byte[] bytesRecv = new byte[GPRS_DATAPACK_WIDTH_BUFFER];
byte[] bytesSendToCenter=new byte[GPRS_DATAPACK_WIDTH_BUFFER];
int nRecvCount=0;
string strInfo = "";
string Recvpackage="";
while(true)
{
try
{
for(int i=0; i<bytesRecv.Length; i++)
bytesRecv[i]=0;
// 接收来自GPRS的数据,没有数据则阻塞。
nRecvCount=SocketRecvFromGprsBuffer.ReceiveFrom(bytesRecv, ref EndPointRecvFromGprsBuffer);
Recvpackage=Encoding.ASCII.GetString(bytesRecv);
//保存数据包成文本文件
// WriteToTxt(swDebugFileBuffer,Recvpackage);
byte DatapackID=bytesRecv[GPRS_DATA_RECV_TYPE_INDEX];
if(listBox1Buffer.Items.Count==100)
{
listBox1Buffer.Items.Clear();
}
// 计算接收到的数据包个数
totalCount++;
if(totalCount==UInt32.MaxValue)
{
totalCount=0;
invalidCount=0;
validCount=0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -