/*
 * ul_modbus.h
 *
 *  Created on: Mar 26, 2012
 *      Author: qwer1
 */

#ifndef UL_MODBUS_H_
#define UL_MODBUS_H_

//current mode (receive/transmit)
#define MODBUS_MO_RX 0
#define MODBUS_MO_TX 1

//Modbus command codes
#define MODBUS_CMD_READ_COIL_STATUS       1
#define MODBUS_CMD_READ_DISCRETE_INPUT    2
#define MODBUS_CMD_READ_HOLDING_REGISTERS 3
#define MODBUS_CMD_READ_INPUT_REGISTERS   4
#define MODBUS_CMD_WRITE_SINGLE_COIL      5
#define MODBUS_CMD_WRITE_SINGLE_REGISTER  6
#define MODBUS_CMD_WRITE_MULTI_COILS      15
#define MODBUS_CMD_WRITE_MULTI_REGISTERS  16

//timeout time, ms
#define MODBUS_TIMEOUT 10

//Modbus structure
struct modbus_struct {
	U8  master;    //slave/master mode (0=slave, 1=master)
	U8  addr;      //slave/master address
	U8  mode;      //current mode (RX/TX)
	U8  timeout;   //timeout counter

	U8  buf[MODBUS_BUF_SIZE]; //RX/TX buffer
	U8  buf_cnt;   //buffer counter

	U16 crc;       //current CRC

	U16 regs_addr; //first register address
	U16 regs_num;  //number of registers
	struct modbus_reg_struct *regs; //pointer to first register descriptor struct
};

//Modbus register type
#define MODBUS_REG_TY_BIT  0
#define MODBUS_REG_TY_U8   1
#define MODBUS_REG_TY_S8   2
#define MODBUS_REG_TY_U16  3
#define MODBUS_REG_TY_S16  4
#define MODBUS_REG_TY_U32L 5
#define MODBUS_REG_TY_U32H 6
#define MODBUS_REG_TY_S32L 7
#define MODBUS_REG_TY_S32H 8

//Modbus register descriptor structure
struct modbus_reg_struct {
	void *buf; //pointer to holding register
	U8 type;   //register type
	U8 wr;     //=0 if readonly
	U8 cb;     //=1 to call callback functions on read/write
};

//reset structure (on init or RX timeout)
void modbus_reset(struct modbus_struct *mb);
//reset CRC in structure
void modbus_reset_crc(struct modbus_struct *mb);
//calculare CRC of structure buffer
U16 modbus_crc(struct modbus_struct *mb, U8 size);

//receive 1 byte, returns TRUE if received valid packet and CRC
U8 modbus_slave_receive(struct modbus_struct *mb, U8 data);

//create slave response
U8 modbus_slave_respond(struct modbus_struct *mb);

//read register by its descriptor
S16 modbus_reg_rd(struct modbus_reg_struct *reg, U16 reg_num);
//read register by its descriptor
void modbus_reg_wr(struct modbus_reg_struct *reg, U16 reg_num, S16 reg_val);

//returns 16-bit word from buffer
#define modbus_get_U16(buf) (((U16)(*(buf)) << 8) + *((buf) + 1))
#define modbus_set_U16(buf, data) { *buf = (data) >> 8; *((buf)+1) = (data) & 0xFF; }

#endif /* UL_MODBUS_H_ */
