C++做从机Modbus服务器范例

11 篇文章 0 订阅
3 篇文章 0 订阅

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开始的

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值