样例工程目录结构
WQiang authored at 2021-12-01 10:47:56
9.96 KiB
microCLib

#include "ModbusRtuCodec.h"
#include "Crc.h"

#include "Debug.h"

// 特别注意,modbusrtu 数据域是大端,crc 是小端。


static bool Check(byte* data, int len)
{
	if (data == NULL)return false;

	ushort crc = CaclcCRC16_MODBUS(data, len - 2);
	ushort pktcrc = data[len - 2] * 256 + data[len - 1];
	if (crc == pktcrc)return true;
	ushort pktcrc2 = data[len - 1] * 256 + data[len - 2];
	if (crc == pktcrc2)return true;

	// DebugPrintf("%04X  %04X", crc, pktcrc);

	return false;
}

int MrcSlaveGetLength(byte* p, int len)
{
	if (p == NULL)return 0;
	if (len < 8)return 0;

	byte cmd = p[1];
	switch (cmd)
	{
		// 读指令长度都是 8 字节。
		// 写单个寄存器长度也是 8字节。
	case 1: // 读线圈 
	case 2:	// 读离散输入 
	case 3: // 读多个保持寄存器 
	case 4: // 读输入寄存器  
	case 5: // 写单个线圈 
	case 6: // 写单个寄存器 
	{
		if (Check(p, 8))return 8;
		return -1;
	}

	case 0x0f:	// 写多个线圈 
	case 0x10:	// 写多个寄存器
	{
		// addr,cmd,regaddr2+regcnt2+len+ dataXlen +crc
		ushort bytelen = p[6];
		if (bytelen > 122)return -2;
		// 固定长度是 9 字节
		ushort pglen = bytelen + 9;
		if(len < pglen)return 0;

		if (Check(p, pglen))return pglen;
		return -1;
	}

	default: return -1;
	}
}

int MrcSlaveGetLenCircularQueue(CircularQueue_t* queue)
{
	if (queue == NULL)return 0;
	int remain = CircularQueueGetLength(queue);
	if (remain < 8)return 0;

	// 拿到 cmd
	byte cache[8];
	CircularQueueReads(queue, cache, sizeof(cache), true);
	byte cmd = cache[1];

	switch (cmd)
	{
	case 1:
	case 2:
	case 3:
	case 4:
	case 5:
	case 6:
	{
		if (Check(cache, 8))return 8;
		return -1;
	}

	case 0x0f:
	case 0x10:
	{
		// addr,cmd,regaddr2+regcnt2+len+ dataXlen +crc
		ushort len = cache[6];
		if (len > 122)
		{
			// DebugPrintf("len > 122\r\n");
			return -2;
		}
		ushort pglen = len + 9;
		if(remain < pglen) return 0;

		// 10 数据包不会大于 130 字节。
		byte pgcache[130];
		CircularQueueReads(queue, pgcache, pglen, true);

		if (Check(pgcache, pglen))return pglen;
		// DebugPrintf("check fail len %d remain %d plen %d\r\n",len, remain, pglen);
		return -1;
	}

	default: 
	// DebugPrintf("CMD 0x%02X\r\n", cmd);
	return -1;
	}
}

int MrcSlaveGetLenStream(Stream_t* st)
{
	int remain = st->Size - st->Position;
	byte* p = &st->MemStart[st->Position];

	return MrcSlaveGetLength(p, remain);
}

/**
 * @brief 通过包头计算数据长度,不校验
 * @param p 最少给3个字节的数组
 * @return 理论上包长。-1 数据包类型不对,0 p为null
 */
static int _masterCalcRxLen(byte* p)
{
	if (p == NULL)return 0;

	byte cmd = p[1];
	switch (cmd)
	{
	case 1:
	case 2:
	{
		byte bitlen = p[2];
		byte bytelen = (bitlen + 7) / 8;
		// addr+cmd+bitcnt + 2crc * 5
		int pklen = 5 + bytelen;

		return pklen;
	}
	case 3:
	case 4:
	{
		byte bytelen = p[2];
		// addr+cmd+bytelen+2crc = 5
		int pklen = 5 + bytelen;

		return pklen;
	}

	case 5:
	case 6:
	case 0xf:
	case 0x10:
	{
		return 8;
	}

	default: return -1;
	}
}

int MrcMasterGetRxLength(byte* p, int len)
{
	if (p == NULL)return 0;
	if (len < 5)return 0;

	int pklen = _masterCalcRxLen(p);

	// 数据包类型不对
	if (pklen < 0)return -1;
	// 长度超出
	if (pklen > 130)return -2;
	// 长度不够
	if (pklen > len)return 0;

	if (Check(p, pklen))return pklen;
	// 校验失败
	return -1;
}

int MrcMasterGetRxLenCircularQueue(CircularQueue_t* queue)
{
	if (queue == NULL)return 0;
	int remain = CircularQueueGetLength(queue);
	if (remain < 6)return 0;

	// 缓冲
	byte cache[130];
	// 读3个字节判断长度
	CircularQueueReads(queue, cache, 3, true);
	int pklen = _masterCalcRxLen(cache);
	// 数据包类型不对
	if (pklen < 0)return -1;
	// 长度超出
	if (pklen > 130)return -2;
	// 数据包长度
	if (pklen > remain)return 0;
		
	// if (sizeof(cache) >= pklen)
	// {

	// 直接使用缓冲区读出来判断
	CircularQueueReads(queue, cache, pklen, true);	
	if (Check(cache, pklen))return pklen;
	// 校验失败
	return -1;

	// }
	// else
	// {
	// 	// 再弄一个缓冲区使用
	// 	byte* p = (byte*)GlobleMalloc(pklen);
	// 	if (p == NULL)return -1;
	// 
	// 	// 读出来校验一下
	// 	CircularQueueReads(queue, p, pklen, true);
	// 	bool crcok = Check(p, pklen);
	// 	GlobleFree(p);
	// 
	// 	if (crcok)return pklen;
	// 	// 校验失败
	// 	return -1;
	// }
}

int MrcMasterGetRxLenStream(Stream_t* st)
{
	int remain = st->Size - st->Position;
	byte* p = &st->MemStart[st->Position];

	return MrcMasterGetRxLength(p, remain);
}

/**
 * @brief 获取应答消息内负载数据的偏移量
 * @param pkt 已经校验通过的数据包
 * @return 返回偏移量,-1 消息类型错误,0 无负载数据
 */
int MrcMasterGetRxPyOffset(byte* pkt)
{
	if (pkt == NULL)return 0;

	byte cmd = pkt[1];
	switch (cmd)
	{
	case 1:
	case 2:
	case 3:
	case 4:
	{
		return 3;
	}
	case 5:
	case 6:
	{
		return 4;
	}
	case 0x0f:
	case 0x10:
	{
		return 0;
	}
	default: return -1;
	}
}

// 01 02 请求指令。 len = 8
int Mrc01a02(byte addr, byte cmd, ushort regaddr, ushort bitlen, byte* data, int len)
{
	if (data == NULL)return -1;
	if (len < 8)return -1;

	Stream_t st;
	StreamInit(&st, data, len);

	StreamWriteByte(&st, addr);
	StreamWriteByte(&st, cmd);
	ushort temp = __REV16x(regaddr);
	StreamWriteBytes(&st, (byte*)&temp, 2);
	temp = __REV16x(bitlen);
	StreamWriteBytes(&st, (byte*)&temp, 2);

	ushort crc = CaclcCRC16_MODBUS(st.MemStart, st.Position);
	temp = (crc);
	StreamWriteBytes(&st, (byte*)&temp, 2);

	return st.Position;
}

// 01 02 指令的回复。 len > (bitlen+7)/8 + 5;
int MrcResult01a02(byte addr, byte cmd, byte* bits, ushort bitlen, byte* data, int len)
{
	if (cmd < 1)return -1;
	if (cmd > 2)return -1;
	if (data == NULL)return -1;
	int bytelen = (bitlen + 7) / 8;
	if (len < bytelen + 5)return -1;

	Stream_t st;
	StreamInit(&st, data, len);

	StreamWriteByte(&st, addr);
	StreamWriteByte(&st, cmd);
	StreamWriteByte(&st, bitlen);

	StreamWriteBytes(&st, bits, bytelen);

	ushort crc = CaclcCRC16_MODBUS(st.MemStart, st.Position);
	ushort temp = (crc);
	StreamWriteBytes(&st, (byte*)&temp, 2);

	return st.Position;
}

// 03 04 请求指令。 len = 8
int Mrc03a04(byte addr, byte cmd, ushort regaddr, ushort regcnt, byte* data, int len)
{
	return Mrc01a02(addr, cmd, regaddr, regcnt, data, len);
}

// 03 指令回复。 len > regcnt * 2 + 5
int MrcResult03a04(byte addr, byte cmd, byte* reg, ushort regcnt, byte* data, int len)
{
	if (data == NULL)return -1;
	if (len < regcnt * 2 + 5)return -1;

	Stream_t st;
	StreamInit(&st, data, len);

	StreamWriteByte(&st, addr);
	StreamWriteByte(&st, cmd);
	StreamWriteByte(&st, regcnt * 2);
	StreamWriteBytes(&st, reg, regcnt * 2);

	ushort crc = CaclcCRC16_MODBUS(st.MemStart, st.Position);
	ushort temp = (crc);
	StreamWriteBytes(&st, (byte*)&temp, 2);

	return st.Position;
}

// 05 06 请求指令  len = 8
int Mrc05a06(byte addr, byte cmd, ushort regaddr, ushort reg, byte* data, int len)
{
	if (data == NULL)return -1;
	if (len < 8)return -1;

	Stream_t st;
	StreamInit(&st, data, len);

	StreamWriteByte(&st, addr);
	StreamWriteByte(&st, cmd);
	ushort temp = __REV16x(regaddr);
	StreamWriteBytes(&st, (byte*)&temp, 2);
	temp = __REV16x(reg);
	StreamWriteBytes(&st, (byte*)&temp, 2);

	ushort crc = CaclcCRC16_MODBUS(st.MemStart, st.Position);
	temp = (crc);
	StreamWriteBytes(&st, (byte*)&temp, 2);

	return st.Position;
}

int Mrc0f(byte addr, ushort regaddr, byte* bitdata, ushort bitcnt, byte bytelen, byte* data, int len)
{
	if (data == NULL)return -1;
	if (len < bytelen + 9)return -1;

	Stream_t st;
	StreamInit(&st, data, len);

	StreamWriteByte(&st, addr);
	StreamWriteByte(&st, 0x0f);
	ushort temp = __REV16x(regaddr);
	StreamWriteBytes(&st, (byte*)&temp, 2);
	temp = __REV16x(bitcnt);
	StreamWriteBytes(&st, (byte*)&temp, 2);
	StreamWriteByte(&st, bytelen);
	StreamWriteBytes(&st, bitdata, bytelen);

	ushort crc = CaclcCRC16_MODBUS(st.MemStart, st.Position);
	temp = (crc);
	StreamWriteBytes(&st, (byte*)&temp, 2);

	return st.Position;
}

// 0f 指令回复
int MrcResult0f(byte addr, ushort regaddr, ushort bitcnt, byte* data, int len)
{
	if (data == NULL)return -1;
	if (len < 8)return -1;

	Stream_t st;
	StreamInit(&st, data, len);

	StreamWriteByte(&st, addr);
	StreamWriteByte(&st, 0x0f);

	ushort temp = __REV16x(regaddr);
	StreamWriteBytes(&st, (byte*)&temp, 2);
	temp = __REV16x(bitcnt);
	StreamWriteBytes(&st, (byte*)&temp, 2);

	ushort crc = CaclcCRC16_MODBUS(st.MemStart, st.Position);
	temp = (crc);
	StreamWriteBytes(&st, (byte*)&temp, 2);

	return st.Position;
}

int Mrc10(byte addr, ushort regaddr, byte* regdata, ushort regcnt, byte* data, int len)
{
	if (data == NULL)return -1;
	if (len < regcnt * 2 + 9)return -1;

	Stream_t st;
	StreamInit(&st, data, len);

	StreamWriteByte(&st, addr);
	StreamWriteByte(&st, 0x10);
	ushort temp = __REV16x(regaddr);
	StreamWriteBytes(&st, (byte*)&temp, 2);
	temp = __REV16x(regcnt);
	StreamWriteBytes(&st, (byte*)&temp, 2);
	StreamWriteByte(&st, regcnt * 2);
	StreamWriteBytes(&st, regdata, regcnt * 2);

	ushort crc = CaclcCRC16_MODBUS(st.MemStart, st.Position);
	temp = (crc);
	StreamWriteBytes(&st, (byte*)&temp, 2);

	return st.Position;
}

// 10 指令回复
int MrcResult10(byte addr, ushort regaddr, ushort regcnt, byte* data, int len)
{
	if (data == NULL)return -1;
	if (len < 8)return -1;

	Stream_t st;
	StreamInit(&st, data, len);

	StreamWriteByte(&st, addr);
	StreamWriteByte(&st, 0x10);

	ushort temp = __REV16x(regaddr);
	StreamWriteBytes(&st, (byte*)&temp, 2);
	temp = __REV16x(regcnt);
	StreamWriteBytes(&st, (byte*)&temp, 2);

	ushort crc = CaclcCRC16_MODBUS(st.MemStart, st.Position);
	temp = (crc);
	StreamWriteBytes(&st, (byte*)&temp, 2);

	return st.Position;
}