//..............................................................................
//
// Packet header definitions for Modbus
//

import "io_Modbus.jnc"
import "crc16.jnc"

//! \addtogroup packets-modbus
//! @{

alignment(1);

//..............................................................................

struct ModbusReadFrame
{
	uint8_t m_deviceAddress;
	io.ModbusReadPdu m_read;
	uint16_t m_crc;

	[ packetTemplateAction ]
	initialize()
	{
		*this = null;
		m_deviceAddress = 1;
		m_read.m_func = io.ModbusFunc.ReadHoldingRegisters;
		m_read.m_count = 1;
	}

	[ packetTemplateAction ]
	calcChecksum()
	{
		updateModbusChecksum(this);
	}
}

// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

struct ModbusWriteFrame
{
	uint8_t m_deviceAddress;
	io.ModbusWritePdu m_write;
	uint16_t m_crc;

	[ packetTemplateAction ]
	initialize()
	{
		*this = null;
		m_deviceAddress = 1;
		m_write.m_func = io.ModbusFunc.WriteRegister;
	}

	[ packetTemplateAction ]
	calcChecksum()
	{
		updateModbusChecksum(this);
	}
}

// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

struct ModbusWriteMultipleFrame
{
	uint8_t m_deviceAddress;
	io.ModbusWriteMultiplePdu m_write;

	[ packetTemplateAction ]
	initialize()
	{
		*this = null;
		m_deviceAddress = 1;
		m_write.m_func = io.ModbusFunc.WriteMultipleRegisters;
	}

	[ packetTemplateAction ]
	updateSize()
	{
		m_write.m_count = getWriteMultipleCount(this, sizeof(ModbusWriteMultipleFrame));
		m_write.m_size = m_write.m_count * sizeof(uint16_t);
	}

	[ packetTemplateAction ]
	calcChecksum()
	{
		updateModbusChecksum(this);
	}
}

// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

struct ModbusReadWriteMultipleFrame
{
	uint8_t m_deviceAddress;
	io.ModbusReadWriteMultiplePdu m_readWrite;

	[ packetTemplateAction ]
	initialize()
	{
		*this = null;
		m_deviceAddress = 1;
		m_readWrite.m_func = io.ModbusFunc.ReadWriteMultipleRegisters;
		m_readWrite.m_readCount = 1;
	}

	[ packetTemplateAction ]
	updateSize()
	{
		m_readWrite.m_writeCount = getWriteMultipleCount(this, sizeof(ModbusReadWriteMultipleFrame));
		m_readWrite.m_writeSize = m_readWrite.m_writeCount * sizeof(uint16_t);
	}

	[ packetTemplateAction ]
	calcChecksum()
	{
		updateModbusChecksum(this);
	}
}

//..............................................................................

size_t getWriteMultipleCount(
	void* p,
	size_t baseSize
	)
{
	size_t extra = dynamic sizeof(p) - baseSize;
	return extra > sizeof(uint16_t) ? (extra - sizeof(uint16_t)) / sizeof(uint16_t) : 0;
}

updateModbusChecksum(void* p)
{
	size_t size = dynamic sizeof(p);
	if (size < 2)
		return;

	size -= 2;
	*(uint16_t*)(p + size) = crc16_ansi(p, size, 0xffff);
}

//..............................................................................

alignment(default);

//! @}
