C++做从机Modbus服务器范例
.cpp
CModbusTCP::CModbusTCP()
{
DWORD exitflag = 0;
GetExitCodeThread(MonitorThread, &exitflag);
if (exitflag == STILL_ACTIVE)
{
pMonitorThread->ResumeThread();
}
else
{
m_bMonitorThreadStart = 1;
pMonitorThread = AfxBeginThread(MonitorThread, this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
pMonitorThread->m_bAutoDelete = TRUE;
pMonitorThread->ResumeThread();
}
}
const unsigned char chCRCHTalbe[] = // CRC 高位字节值表
{
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40 };
const unsigned char chCRCLTalbe[] = // CRC 低位字节值表
{
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7,
0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E,
0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9,
0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32,
0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D,
0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,
0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF,
0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1,
0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB,
0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97,
0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E,
0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89,
0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83,
0x41, 0x81, 0x80, 0x40 };
UINT16 MODBUS_CRC16(unsigned char *pchMsg, UINT16 wDataLen, UINT16 crc)
{
unsigned char chCRCHi = (crc >> 8) & 0xFF; // 高CRC字节初始化
unsigned char chCRCLo = crc & 0xFF; // 低CRC字节初始化
UINT16 wIndex; // CRC循环中的索引
while (wDataLen--)
{
// 计算CRC
wIndex = chCRCLo ^ *pchMsg++;
chCRCLo = chCRCHi ^ chCRCHTalbe[wIndex];
chCRCHi = chCRCLTalbe[wIndex];
}
return ((chCRCHi << 8) | chCRCLo);
}
//CModbusTCP::CModbusTCP()
//{
// memset(modbusReg.reg, 0, sizeof(UINT16)*REG_N);
//}
unsigned char CModbusTCP::ModbusParse(char *rxBuf, unsigned char rxLen)
{
unsigned char ret = 0;
/*if (rxLen > 5)
{
UINT16 crc;
crc = MODBUS_CRC16((unsigned char*)rxBuf, rxLen - 2, 0xFFFF);
char crc_h = ((crc >> 8) & 0xff);
char crc_l = (crc & 0xff);
if ((rxBuf[rxLen - 1] != crc_h) || (rxBuf[rxLen - 2] != crc_l))
return -1;
}*/
switch (rxBuf[1]) { //命令码筛选
case 1://读线圈
//ret = ReadCoil(rxBuf,rxLen, arg);
break;
case 2://读输入线圈
//ret = ReadInCoil(rxBuf,rxLen, arg);
break;
case 3://读寄存器
ret = ReadRegister(rxBuf, rxLen);
break;
case 4://读输入寄存器
//ret = ReadInRegister(rxBuf,rxLen, arg);
break;
case 5://写单线圈
//ret = WriteCoil(rxBuf,rxLen, arg);
break;
case 6://预置单寄存器
ret = WriteRegister(rxBuf, rxLen);
break;
case 7://读取异常状态
break;
case 8://回送诊断校验
break;
case 9://编程
break;
case 10://控询
break;
case 11://读取事件计数
break;
case 12://读取通信事件记录
break;
case 15://写多线圈
//ret = WriteMultiCoil(rxBuf,rxLen, arg);
break;
case 16://预置多寄存器
ret = WriteMultiRegister(rxBuf,rxLen);
break;
case 17://报告从机标志
break;
case 22://扩展功能------CDV功能
break;
case 65://扩展功能------CDV功能
break;
case 0xfe://自定义读
break;
default: //命令码无效不应答
ModbusRequest(rxBuf[1], 1);
break;
}
return ret;
}
unsigned char CModbusTCP::ReadRegister(char *rxBuf, unsigned char rxLen)
{
UINT16 i, len;
UINT16 addr, num;
unsigned char *txBuf = NULL;
UINT16 *reg = modbusReg.reg;
addr = (rxBuf[2] << 8) + rxBuf[3];
num = (rxBuf[4] << 8) + rxBuf[5];
//#if USE_SYS_REG == 1u
// if(addr >= SYS_REG_OFFSET && addr + num < SYS_REG_MAX) {
// reg = SYS_REG;
// addr -= SYS_REG_OFFSET;
// } else
//#endif
if (0x0001 > num || num > 0x007D) {
ModbusRequest(rxBuf[1], 3);
return 3;
}
//else if (addr > REG_N || addr + num > REG_N) {
// ModbusRequest(rxBuf[1], 2);
// return 2;
//}
if (addr < 40000 || addr > 41000) {
//ModbusRequest(rxBuf[1], 2);
return 2;
}
len = 5 + (num << 1) - 2;//tx总长度
addr -= 40000;
txBuf = new unsigned char[len];
txBuf[0] = rxBuf[0];
txBuf[1] = rxBuf[1];
txBuf[2] = num << 1;
//所处字节
for (i = 0; i < num; i++) {
txBuf[3 + (i << 1)] = HIGH16U(reg[addr + i]);
txBuf[3 + (i << 1) + 1] = LOW16U(reg[addr + i]);
}
//AddTxNoHeadPlus((char*)txBuf, len);
memset(&rxBuf[100], 0, 5);
rxBuf[105] = len;
memcpy(&rxBuf[106], txBuf, len);//回复报文从第106个位置开始
delete[](txBuf);
return len+6;
}
unsigned char CModbusTCP::WriteRegister(char *rxBuf, unsigned char rxLen)
{
UINT16 addr, num;
UINT16 *reg = modbusReg.reg;
addr = (rxBuf[2] << 8) + rxBuf[3];
num = (rxBuf[4] << 8) + rxBuf[5];
//if (addr > REG_N) {
// ModbusRequest(rxBuf[1], 2);
// return 2;
//}
if (addr < 40000 || addr > 41000) {
//ModbusRequest(rxBuf[1], 2);
return 2;
}
addr -= 40000;
reg[addr] = num;
//AddTxNoHeadPlus(rxBuf, rxLen - 2);
memset(&rxBuf[100], 0, 5);
rxBuf[105] = rxLen;
memcpy(&rxBuf[106], rxBuf, rxLen);//回复报文从第106个位置开始
//delete[](rxBuf);
return rxLen + 6;
//return 0;
}
unsigned char CModbusTCP::WriteMultiRegister(char *rxBuf, unsigned char rxLen)
{
UINT16 addr, num, data;
UINT16 *reg = modbusReg.reg;
addr = (rxBuf[2] << 8) + rxBuf[3];
num = (rxBuf[4] << 8) + rxBuf[5];
//if (addr > REG_N) {
// ModbusRequest(rxBuf[1], 2);
// return 2;
//}
if (addr < 40000 || addr > 41000) {
//ModbusRequest(rxBuf[1], 2);
return 2;
}
addr -= 40000;
reg[addr] = num;
for (int i = 0; i < num; i++) {
data = (rxBuf[7 + 2 * i] << 8) + rxBuf[8 + 2 * i];
reg[addr + i] = data;
}
//AddTxNoHeadPlus(rxBuf, rxLen - 2);
memset(&rxBuf[100], 0, 5);
rxBuf[105] = rxLen;
memcpy(&rxBuf[106], rxBuf, rxLen);//回复报文从第106个位置开始
//delete[](rxBuf);
return rxLen + 6;
//return 0;
}
void CModbusTCP::ModbusRequest(unsigned char no, unsigned char errNo)
{
unsigned char len, *txBuf = NULL;
// OS_ERR err;
switch (no)
{
case 65:
len = 6; //tx总长度=8
txBuf = new unsigned char[len];
txBuf[0] = CDV_ID;
txBuf[1] = 0x41 + 0x80;
txBuf[2] = 00;
txBuf[3] = 00;
// txBuf[4] = g_scriptInfo.no;
txBuf[5] = errNo;
break;
default:
len = 3; //tx总长度=5
txBuf = new unsigned char[len];
txBuf[0] = CDV_ID;
txBuf[1] = no + 0x80;
txBuf[2] = errNo;
break;
}
//AddTxNoHeadPlus((char*)txBuf, len);
delete[](txBuf);
}
void CModbusTCP::AddTxNoHeadPlus(char *txBuf, UINT16 txLen)
{
UINT16 crc;
assert(txBuf && txLen);
if (NULL == txBuf || 0 == txLen)
return;
crc = MODBUS_CRC16((unsigned char*)txBuf, txLen, 0xFFFF);
//QByteArray Data = QByteArray((const char *)txBuf, txLen);
//Data.append((const char*)&crc,2);
//qDebug() << "out:" << Data.toHex();
//arg->write(Data);
}
void CModbusTCP::ServerStartListen()
{
WSADATA wsaData;
WORD wVersion;
wVersion = MAKEWORD(2, 2);
WSAStartup(wVersion, &wsaData);
// WSAStartup(0x0202, &wsaData);
SOCKADDR_IN local_addr;
SOCKADDR_IN client_addr;
int iaddrSize = sizeof(SOCKADDR_IN);
int res;
char msg[1024];
//CsFileDlg * dlg = (CsFileDlg *)AfxGetApp()->GetMainWnd();
local_addr.sin_family = AF_INET;
local_addr.sin_port = htons(8000);
local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
if ((listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
{
AfxMessageBox(_T("创建监听失败"));
}
if (bind(listen_sock, (struct sockaddr*) &local_addr, sizeof(SOCKADDR_IN)))
{
AfxMessageBox(_T("绑定错误"));
}
listen(listen_sock, 5);//最大用户数
if ((sock = accept(listen_sock, (struct sockaddr *)&client_addr, &iaddrSize)) == INVALID_SOCKET)
{
AfxMessageBox(_T("接收失败!"));
}
else
{
CString port;
port.Format(_T("%d"), int(ntohs(client_addr.sin_port)));
AfxMessageBox(_T("已连接来自:") + CString(inet_ntoa(client_addr.sin_addr)) + _T("\n 端口:") +
port);
while (1)
{
if ((res = recv(sock, msg, 1024, 0)) <= 0)
{
AfxMessageBox(_T("失去连接"));
break;
}
else
{
msg[res] = '\0';
int nlen = ModbusParse(msg + 6, res - 6);
if (nlen > 0)
{
msg[106] = msg[0];
msg[107] = msg[1];
res = ::send(sock, msg + 106, nlen, 0);
}
//AfxMessageBox(_T("client:") + CString(msg));
}
}
}
接收数据
closesocket(sock);
return;
}
.h
#ifndef MODBUS_H
#define MODBUS_H
#define REG_N 1000
#define CDV_ID 1
#define HIGH16U(A) (((UINT16)(A) & 0xff00) >> 8)
#define LOW16U(A) ((UINT16)(A) & 0x00ff)
#define REG32(reg) (*((UINT32*)(&(reg))))
#define REG32F(reg) (*((float*)(&(reg))))
class XXX
{
public:
CModbusTCP();
unsigned char ModbusParse(char * rxBuf, unsigned char rxLen);
unsigned char ReadRegister(char * rxBuf, unsigned char rxLen);
unsigned char WriteRegister(char * rxBuf, unsigned char rxLen);
unsigned char WriteMultiRegister(char * rxBuf, unsigned char rxLen);
void ModbusRequest(unsigned char no, unsigned char errNo);
void AddTxNoHeadPlus(char * txBuf, UINT16 txLen);
void ServerStartListen();
SOCKET listen_sock;
SOCKET sock;
public:
typedef struct
{ /*!< Structure used for resource access */
UINT16 reg[REG_N]; /*!< Type used for word access */
} MODBUS_Register;
MODBUS_Register modbusReg;
}
备注:寄存器地址减40000,是因为我这边寄存器地址是从40000开始的