Commit 156b8a7b authored by 潘栩锋's avatar 潘栩锋 🚴

添加 ModbusServer 支持 04功能包

parent 8e26f37f
...@@ -24,7 +24,8 @@ namespace GeneralGommunication ...@@ -24,7 +24,8 @@ namespace GeneralGommunication
MBA_STATUS_0A = 2 MBA_STATUS_0A = 2
} }
ModbusAsciiStatus status; ModbusAsciiStatus status;
ModbusRegReadWriteHandler regRead; ModbusRegReadWriteHandler regRead_Holding;
ModbusRegReadWriteHandler regRead_Input;
ModbusRegReadWriteHandler regWrite; ModbusRegReadWriteHandler regWrite;
Action<IEnumerable<byte>> sendMsg; Action<IEnumerable<byte>> sendMsg;
...@@ -34,10 +35,14 @@ namespace GeneralGommunication ...@@ -34,10 +35,14 @@ namespace GeneralGommunication
//上一次接收数据的时间 //上一次接收数据的时间
DateTime lastRecMsgTime; DateTime lastRecMsgTime;
public void Init(ModbusRegReadWriteHandler regRead, ModbusRegReadWriteHandler regWrite, public void Init(
ModbusRegReadWriteHandler regRead_Holding,
ModbusRegReadWriteHandler regRead_Input,
ModbusRegReadWriteHandler regWrite,
Action<IEnumerable<byte>> sendMsg, out Action<IEnumerable<byte>> recMsg) Action<IEnumerable<byte>> sendMsg, out Action<IEnumerable<byte>> recMsg)
{ {
this.regRead = regRead; this.regRead_Holding = regRead_Holding;
this.regRead_Input = regRead_Input;
this.regWrite = regWrite; this.regWrite = regWrite;
this.sendMsg = sendMsg; this.sendMsg = sendMsg;
recMsg = RecMsg; recMsg = RecMsg;
...@@ -54,7 +59,7 @@ namespace GeneralGommunication ...@@ -54,7 +59,7 @@ namespace GeneralGommunication
/// <summary> /// <summary>
/// Read REGs /// Read Holding REGs
/// </summary> /// </summary>
/// <param name="buf">传入通讯字元</param> /// <param name="buf">传入通讯字元</param>
/// <param name="startIndex"></param> /// <param name="startIndex"></param>
...@@ -118,7 +123,12 @@ namespace GeneralGommunication ...@@ -118,7 +123,12 @@ namespace GeneralGommunication
midBuf.Add((byte)(number * 2)); midBuf.Add((byte)(number * 2));
UInt16[] regValues = new UInt16[number]; UInt16[] regValues = new UInt16[number];
bool ret = this.regRead(deviceNo, startAddr, regValues); if (this.regRead_Holding == null)
{
//读取失败,没有设备,不用回复
return;
}
bool ret = this.regRead_Holding(deviceNo, startAddr, regValues);
if (!ret) if (!ret)
{ {
//读取失败,没有设备,不用回复 //读取失败,没有设备,不用回复
...@@ -133,7 +143,90 @@ namespace GeneralGommunication ...@@ -133,7 +143,90 @@ namespace GeneralGommunication
Modbus_AddLrcAndSend(midBuf); Modbus_AddLrcAndSend(midBuf);
} }
/// <summary>
/// Read Input REGs
/// </summary>
/// <param name="buf">传入通讯字元</param>
/// <param name="startIndex"></param>
/// <param name="len">buf长度</param>
void Modbus_Func04(IEnumerable<byte> buf, int startIndex, int len)
{
//请求
//0. ':' 0x3A
//1. slave address : 2bytes ascii
//2. Function : 2bytes ascii
//3. Starting Address Hi : 2bytes ascii
//4. Starting Address Lo : 2bytes ascii
//5. Number of Register Hi : 2bytes ascii
//6. Number of Register Lo : 2bytes ascii
//7. LRC : 2bytes ascii
//8. 0x0D 0x0A
//响应
//0. ':' 0x3A
//1. slave address : 2bytes ascii
//2. Function : 2bytes ascii
//3. Number * 2 : 2bytes ascii
//下面重复 Number 次
//4. Data Hi : 2bytes ascii
//5. Data Lo : 2bytes ascii
//6. LRC : 2bytes ascii
//7. 0x0D 0x0A
//example: 下面为 ASCII
//请求
//: 01 03 00 01 00 01 ?? (0X0D) (0X0A)
//响应
//: 01 03 02 12 34 ?? (0X0D) (0X0A)
//buf 已经是 ascii转hex 后结果。 从 slave address 开始,没有LRC
if (len < 6)
{
Modbus_DefaultCallback(buf, startIndex, MB_ERR_LEN);//指令异常
return;
}
byte deviceNo = buf.ElementAt(startIndex);
UInt16 startAddr = buf.ToUInt16_Big_Endian(startIndex + 2);
UInt16 number = buf.ToUInt16_Big_Endian(startIndex + 4);
if (number == 0)
{
Modbus_DefaultCallback(buf, startIndex, MB_ERR_NUM_0);//指令异常
return;
}
if (number > 50)//限制数量,因为缓存区不够大
number = 50;
List<byte> midBuf = new List<byte>();
midBuf.Add(deviceNo);
midBuf.Add(0x04);
midBuf.Add((byte)(number * 2));
UInt16[] regValues = new UInt16[number];
if (this.regRead_Input == null)
{
//读取失败,没有设备,不用回复
return;
}
bool ret = this.regRead_Input(deviceNo, startAddr, regValues);
if (!ret)
{
//读取失败,没有设备,不用回复
return;
}
for (int i = 0; i < number; i++)
{
midBuf.AddRange(regValues[i].GetBytes_Big_endian());
}
Modbus_AddLrcAndSend(midBuf);
}
/// <summary> /// <summary>
/// Write Single REG /// Write Single REG
/// </summary> /// </summary>
...@@ -183,6 +276,8 @@ namespace GeneralGommunication ...@@ -183,6 +276,8 @@ namespace GeneralGommunication
UInt16 regValue = buf.ToUInt16_Big_Endian(startIndex + 4); UInt16 regValue = buf.ToUInt16_Big_Endian(startIndex + 4);
UInt16[] regValues = new UInt16[] { regValue }; UInt16[] regValues = new UInt16[] { regValue };
if (this.regWrite == null)
return;//写入失败,没有设备,不用回复
bool ret = this.regWrite(deviceNo, startAddr, regValues); bool ret = this.regWrite(deviceNo, startAddr, regValues);
if (!ret) if (!ret)
{ {
...@@ -282,6 +377,8 @@ namespace GeneralGommunication ...@@ -282,6 +377,8 @@ namespace GeneralGommunication
index += 2; index += 2;
regValues[i] = regValue; regValues[i] = regValue;
} }
if (this.regWrite == null)
return;//写入失败,没有设备,不用回复
bool ret = this.regWrite(deviceNo, startAddr, regValues); bool ret = this.regWrite(deviceNo, startAddr, regValues);
if (!ret) if (!ret)
...@@ -470,6 +567,9 @@ namespace GeneralGommunication ...@@ -470,6 +567,9 @@ namespace GeneralGommunication
case 0x03: case 0x03:
Modbus_Func03(midBuf, 0, adu_len); Modbus_Func03(midBuf, 0, adu_len);
break; break;
case 0x04:
Modbus_Func04(midBuf, 0, adu_len);
break;
//case 0x05: //case 0x05:
// Modbus_Func05(buf, adu_len); // Modbus_Func05(buf, adu_len);
// break; // break;
......
...@@ -19,7 +19,7 @@ namespace GeneralGommunication ...@@ -19,7 +19,7 @@ namespace GeneralGommunication
const byte MB_ERR_CNT = 0x03;//字节数!=寄存器数量*2 const byte MB_ERR_CNT = 0x03;//字节数!=寄存器数量*2
const byte MB_ERR_NOFUNC = 0x05;//没有这个func const byte MB_ERR_NOFUNC = 0x05;//没有这个func
ModbusRegReadWriteHandler regRead_Input;
ModbusRegReadWriteHandler regRead; ModbusRegReadWriteHandler regRead;
ModbusRegReadWriteHandler regWrite; ModbusRegReadWriteHandler regWrite;
Action<IEnumerable<byte>> sendMsg; Action<IEnumerable<byte>> sendMsg;
...@@ -30,10 +30,11 @@ namespace GeneralGommunication ...@@ -30,10 +30,11 @@ namespace GeneralGommunication
System.Threading.Timer timer3d5t;//通讯包的 3.5T 时间间隔。 实际只是 15ms定时而已 System.Threading.Timer timer3d5t;//通讯包的 3.5T 时间间隔。 实际只是 15ms定时而已
public void Init(ModbusRegReadWriteHandler regRead, ModbusRegReadWriteHandler regWrite, public void Init(ModbusRegReadWriteHandler regRead, ModbusRegReadWriteHandler regRead_Input, ModbusRegReadWriteHandler regWrite,
Action<IEnumerable<byte>> sendMsg, out Action<IEnumerable<byte>> recMsg) Action<IEnumerable<byte>> sendMsg, out Action<IEnumerable<byte>> recMsg)
{ {
this.regRead = regRead; this.regRead = regRead;
this.regRead_Input = regRead_Input;
this.regWrite = regWrite; this.regWrite = regWrite;
this.sendMsg = sendMsg; this.sendMsg = sendMsg;
recMsg = RecMsg; recMsg = RecMsg;
...@@ -135,6 +136,13 @@ namespace GeneralGommunication ...@@ -135,6 +136,13 @@ namespace GeneralGommunication
midBuf.Add((byte)(number * 2)); midBuf.Add((byte)(number * 2));
UInt16[] regValues = new UInt16[number]; UInt16[] regValues = new UInt16[number];
if (this.regRead == null)
{
//读取失败,没有设备,不用回复
logger.Debug($"REQ 读取失败,没有设置regRead,不用回复");
sendBuf = null;
return req_len;
}
bool ret = this.regRead(deviceNo, startAddr, regValues); bool ret = this.regRead(deviceNo, startAddr, regValues);
if (!ret) if (!ret)
{ {
...@@ -154,7 +162,109 @@ namespace GeneralGommunication ...@@ -154,7 +162,109 @@ namespace GeneralGommunication
//Modbus_AddCrcAndSend(midBuf); //Modbus_AddCrcAndSend(midBuf);
} }
/// <summary>
/// 读寄存器, 返回已经处理的长度
/// </summary>
/// <param name="buf">接收缓冲</param>
/// <param name="startIndex">数据开始序号</param>
/// <param name="len">数据长度</param>
/// <returns></returns>
int Modbus_Func04(IEnumerable<byte> buf, int startIndex, int len, out byte[] sendBuf)
{
//请求
//1. slave address : 1byte
//2. Function : 1byte
//3. Starting Address Hi : 1byte
//4. Starting Address Lo : 1byte
//5. Number of Register Hi : 1byte
//6. Number of Register Lo : 1byte
//7. CRC16 : 2bytes
//响应
//1. slave address : 1byte
//2. Function : 1byte
//3. Number * 2 : 1byte
//下面重复 Number 次
//4. Data Hi : 1byte
//5. Data Lo : 1byte
//6. CRC16 : 2bytes
//example:
//请求
//01 03 00 01 00 01 ?? ??
//响应
//01 03 02 12 34 ?? ??
int req_len = 8;
//buf 从 slave address 开始
if (len < req_len)
{
logger.Error($"REQ 指令字节数不足");
sendBuf = Modbus_DefaultCallback(buf, startIndex, MB_ERR_LEN);//指令异常
return len;
}
//CRC
int adu_len = req_len - 2;//去除crc后的数据包长
UInt16 crc = buf.CRC16(startIndex, req_len - 2);
UInt16 rec_crc = buf.ToUInt16_Little_Endian(startIndex + req_len - 2);//CRC 是 小端模式
if (crc != rec_crc)
{
logger.Error($"REQ CRC 校验出错 接收:{rec_crc:X4} 计算:{crc:X4}");
sendBuf = Modbus_DefaultCallback(buf, startIndex, MB_ERR_LRC);//指令异常
return len;//指令异常,应该全部删除
}
byte deviceNo = recBuf[0];
UInt16 startAddr = buf.ToUInt16_Big_Endian(startIndex + 2);
UInt16 number = buf.ToUInt16_Big_Endian(startIndex + 4);
if (number == 0)
{
logger.Error($"REQ 没有任何寄存器");
sendBuf = Modbus_DefaultCallback(buf, startIndex, MB_ERR_NUM_0);//指令异常
return req_len;
}
if (number > 50)//限制数量,因为缓存区不够大
number = 50;
List<byte> midBuf = new List<byte>();
midBuf.Add(deviceNo);
midBuf.Add(0x04);
midBuf.Add((byte)(number * 2));
UInt16[] regValues = new UInt16[number];
if (this.regRead_Input == null)
{
//读取失败,没有设备,不用回复
logger.Debug($"REQ 读取失败,没有设置regRead,不用回复");
sendBuf = null;
return req_len;
}
bool ret = this.regRead_Input(deviceNo, startAddr, regValues);
if (!ret)
{
//读取失败,没有设备,不用回复
logger.Debug($"REQ 读取失败,没有设备,不用回复");
sendBuf = null;
return req_len;
}
for (int i = 0; i < number; i++)
{
midBuf.AddRange(regValues[i].GetBytes_Big_endian());
}
sendBuf = midBuf.ToArray();
return req_len;
//Modbus_AddCrcAndSend(midBuf);
}
/// <summary> /// <summary>
/// Write Single REG /// Write Single REG
/// </summary> /// </summary>
......
...@@ -8,7 +8,9 @@ namespace GeneralGommunication ...@@ -8,7 +8,9 @@ namespace GeneralGommunication
{ {
public interface IModbusServer public interface IModbusServer
{ {
void Init(ModbusRegReadWriteHandler regRead, ModbusRegReadWriteHandler regWrite, void Init(ModbusRegReadWriteHandler regRead_Holding,
ModbusRegReadWriteHandler regRead_Input,
ModbusRegReadWriteHandler regWrite,
Action<IEnumerable<byte>> sendMsg, out Action<IEnumerable<byte>> recMsg); Action<IEnumerable<byte>> sendMsg, out Action<IEnumerable<byte>> recMsg);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment