增加Modbus协议,实现了协议解析,部分从机,未实现主机
This commit is contained in:
parent
3a7dd0feb2
commit
f93f352d5b
|
@ -0,0 +1,65 @@
|
||||||
|
#include "Modbus.h"
|
||||||
|
|
||||||
|
Modbus::Modbus()
|
||||||
|
{
|
||||||
|
Address = 0;
|
||||||
|
Code = 0;
|
||||||
|
Error = 0;
|
||||||
|
Length = 0;
|
||||||
|
|
||||||
|
Crc = 0;
|
||||||
|
Crc2 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Modbus::Read(MemoryStream& ms)
|
||||||
|
{
|
||||||
|
if(ms.Remain() < 4) return false;
|
||||||
|
|
||||||
|
byte* buf = ms.Current();
|
||||||
|
assert_ptr(buf);
|
||||||
|
uint p = ms.Position();
|
||||||
|
|
||||||
|
Address = ms.ReadByte();
|
||||||
|
Code = ms.ReadByte();
|
||||||
|
|
||||||
|
if(Code & 0x80)
|
||||||
|
{
|
||||||
|
Code &= 0x7F;
|
||||||
|
Error = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Length = ms.Remain() - 2;
|
||||||
|
ms.Read(&Data, 0, Length);
|
||||||
|
|
||||||
|
Crc = ms.Read<ushort>();
|
||||||
|
|
||||||
|
// 直接计算Crc16
|
||||||
|
Crc2 = Sys.Crc16(buf, ms.Position() - p - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Modbus::Write(MemoryStream& ms)
|
||||||
|
{
|
||||||
|
uint p = ms.Position();
|
||||||
|
|
||||||
|
ms.Write(Address);
|
||||||
|
|
||||||
|
byte code = Code;
|
||||||
|
if(Error) code |= 0x80;
|
||||||
|
ms.Write(code);
|
||||||
|
|
||||||
|
if(Length > 0) ms.Write(Data, 0, Length);
|
||||||
|
|
||||||
|
byte* buf = ms.Current();
|
||||||
|
byte len = ms.Position() - p;
|
||||||
|
// 直接计算Crc16
|
||||||
|
Crc = Crc2 = Sys.Crc16(buf - len, len);
|
||||||
|
|
||||||
|
ms.Write(Crc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Modbus::SetError(ModbusErrors::Errors error)
|
||||||
|
{
|
||||||
|
Code |= 0x80;
|
||||||
|
Length = 1;
|
||||||
|
Data[0] = error;
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
#ifndef __Slave_H__
|
||||||
|
#define __Slave_H__
|
||||||
|
|
||||||
|
#include "Sys.h"
|
||||||
|
#include "Stream.h"
|
||||||
|
|
||||||
|
class ModbusErrors
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// 错误代码
|
||||||
|
enum Errors
|
||||||
|
{
|
||||||
|
// 错误的功能代码
|
||||||
|
Code = 1,
|
||||||
|
|
||||||
|
// 错误的数据地址
|
||||||
|
Address = 2,
|
||||||
|
|
||||||
|
// 错误的数据值
|
||||||
|
Value = 3,
|
||||||
|
|
||||||
|
// 错误的个数
|
||||||
|
Count,
|
||||||
|
|
||||||
|
// 处理出错
|
||||||
|
Process,
|
||||||
|
|
||||||
|
// 错误的数据长度
|
||||||
|
Length,
|
||||||
|
|
||||||
|
// Crc校验错误
|
||||||
|
Crc
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Modbus消息实体
|
||||||
|
class Modbus
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
public:
|
||||||
|
byte Address; // 地址
|
||||||
|
byte Code; // 功能码
|
||||||
|
byte Error; // 是否异常
|
||||||
|
|
||||||
|
byte Length; // 数据长度
|
||||||
|
byte Data[32]; // 数据
|
||||||
|
|
||||||
|
ushort Crc; // 校验码
|
||||||
|
ushort Crc2; // 动态计算得到的校验码
|
||||||
|
|
||||||
|
Modbus();
|
||||||
|
|
||||||
|
bool Read(MemoryStream& ms);
|
||||||
|
void Write(MemoryStream& ms);
|
||||||
|
|
||||||
|
void SetError(ModbusErrors::Errors error);
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GB/T 19582.1-2008 基于Modbus协议的工业自动化网络规范
|
||||||
|
* 请求响应:1字节功能码|n字节数据|2字节CRC校验
|
||||||
|
* 异常响应:1字节功能码+0x80|1字节异常码
|
||||||
|
*
|
||||||
|
* Modbus数据模型基本表
|
||||||
|
* 基本表 对象类型 访问类型 注释
|
||||||
|
* 离散量输入 单个位 只读 I/O系统可提供这种类型的数据
|
||||||
|
* 线圈 单个位 读写 通过应用程序可改变这种类型的数据
|
||||||
|
* 输入寄存器 16位字 只读 I/O系统可提供这种类型的数据
|
||||||
|
* 保持寄存器 16位字 读写 通过应用程序可改变这种类型的数据
|
||||||
|
*
|
||||||
|
*/
|
|
@ -0,0 +1,43 @@
|
||||||
|
#include "Slave.h"
|
||||||
|
|
||||||
|
Slave(ITransport* port)
|
||||||
|
{
|
||||||
|
_port = port;
|
||||||
|
|
||||||
|
Address = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Slave::~Slave()
|
||||||
|
{
|
||||||
|
delete _port;
|
||||||
|
_port = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Slave::OnReceive(ITransport* transport, byte* buf, uint len, void* param)
|
||||||
|
{
|
||||||
|
assert_ptr(param);
|
||||||
|
|
||||||
|
Slave* slave = (Slave*)param;
|
||||||
|
|
||||||
|
MemoryStream ms(buf, len);
|
||||||
|
Modbus entity;
|
||||||
|
if(!entity.Read(ms)) return;
|
||||||
|
|
||||||
|
slave->Dispatch(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分发处理消息。返回值决定是否响应
|
||||||
|
bool Slave::Dispatch(Modbus& entity)
|
||||||
|
{
|
||||||
|
// 是否本地地址,或者本地是否0接收所有消息
|
||||||
|
if(Address && Address != entity.Address) return false;
|
||||||
|
|
||||||
|
// 检查Crc
|
||||||
|
if(entity.Crc != enable.Crc2)
|
||||||
|
{
|
||||||
|
entity.SetError(ModbusErrors::Crc);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef __Slave_H__
|
||||||
|
#define __Slave_H__
|
||||||
|
|
||||||
|
#include "Sys.h"
|
||||||
|
|
||||||
|
// Modbus从机
|
||||||
|
class Slave
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
ITransport* _port; // 传输口
|
||||||
|
|
||||||
|
public:
|
||||||
|
byte Address; // 地址
|
||||||
|
|
||||||
|
Slave(ITransport* port);
|
||||||
|
~Slave();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void OnReceive(ITransport* transport, byte* buf, uint len, void* param);
|
||||||
|
|
||||||
|
// 分发处理消息。返回值决定是否响应
|
||||||
|
bool Dispatch(Modbus& entity);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -1 +0,0 @@
|
||||||
#include "Slave.h"
|
|
|
@ -1,15 +0,0 @@
|
||||||
#ifndef __Slave_H__
|
|
||||||
#define __Slave_H__
|
|
||||||
|
|
||||||
#include "Sys.h"
|
|
||||||
|
|
||||||
// Modbus从机
|
|
||||||
class Slave
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
public:
|
|
||||||
private:
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
Loading…
Reference in New Issue