/************************************************************************/
/* Copyright 2009 MBARI													*/
/************************************************************************/
/* Summary	: Definitions for ModBus on Respirometer controller (O4)	*/
/* Filename : modbus.h													*/
/* Author	: Robert Herlien (rah)										*/
/* Project	: Respirometers												*/
/* Revision: 1.0														*/
/* Created	: 03/03/2009												*/
/*																			*/
/* MBARI provides this documentation and code "as is", with no warranty,	*/
/* express or implied, of its quality or consistency. It is provided without*/
/* support and without obligation on the part of the Monterey Bay Aquarium	*/
/* Research Institute to assist in its use, correction, modification, or	*/
/* enhancement. This information should not be published or distributed to	*/
/* third parties without specific written permission from MBARI.			*/
/*																			*/
/************************************************************************/
/* Modification History:												*/
/* 3mar2009 rah - created												*/
/************************************************************************/

#ifndef INCmodbush
#define INCmodbush		1

#include <oasis.h>
#include <serial.h>

/********************************/
/* Misc Defines					*/
/********************************/

#define BACKUP_MODLOG_FILES		5

#define DEFAULT_BAUD			57600
#define DEFAULT_MODE			(NO_PTY | BIT8 | STOP1)
#define DEFAULT_SER_TMOUT		(TICKS_PER_SECOND/10)
#define RCV_TMOUT_HEADER		(TICKS_PER_SECOND/2)
#define DEFAULT_TURNAROUND_USECS 500
#define MIN_INTERMSG_USECS		1750
#define INTERMSG_RTC_TICKS		70				/* 1.75 ms in 40 khz ticks */

#define MAX_MSG_LEN				256
#define BASE_QUERY_LEN			6
#define BASE_RESPONSE_LEN		5
#define MAX_BITS				2000
#define MAX_REGS				125
#define IDENT					0x3cf1
#define MAX_SLAVES				16

/****************************************************************/
/* Flag bits													*/
/* Bits 0,1 define power to Modbus when no one has bus open		*/
/****************************************************************/
#define PWROFF_BITS		   3
#define KEEP_PWR		   0	/* 00 = Keep pwr on, even after close	*/
#define PWROFF_IF_NO_PWR   1	/* 01 = Pwr off on close if no pwr bits set*/
#define PWROFF_IF_NO_PWRIO 2	/* 10 = Pwr off on close if no pwr or I/O bits*/
#define PWROFF_ALWAYS	   3	/* 11 = Pwr off on close despite pwr or I/O bits*/


typedef struct					/****************************************/
{								/* Struct to count msgs/errors for one slave*/
	Nat16		slaveID;		/* Slave ID								*/
	Nat32		msgs;			/* Message count for this slave			*/
	Nat32		errs;			/* Error count for this slave			*/
} SlaveCntr;					/****************************************/

typedef struct					/****************************************/
{								/* Struct to describe one Modbus bus	*/
	Nat16		serport;		/* Physical serial port					*/
	Nat32		flags;			/* Flag bits							*/
	Nat32		baud;			/* Baud rate to use						*/
	Nat32		sermode;		/* Serial mode, default N81				*/
	Nat32		surgeDelayMs;	/* Surge delay in msecs for power on	*/
	Int32		serTmout;		/* Ticks to send/receive 256 bytes		*/
	Int32		openCount;		/* Number of times opened				*/
	Nat32		turnaroundUsecs; /* Usecs to wait to turn around line	*/
	TimeOfDay	rcvTime;		/* Time of last msg rcv					*/
	MBool		is485;			/* TRUE if running RS485				*/
	MBool		busIsPowered;	/* TRUE if bus is powered				*/
	Nat16		rcvTick;		/* RTC Tick offset of last msg rcv		*/
	Nat16		rcvLen;			/* Length of valid msg in rcvBuf		*/
	Nat16		ident;			/* Ident field to catch errors			*/
								/* Send and receive buffers				*/
	Nat32		totMsgs;		/* Total message count					*/
	Nat32		totErrs;		/* Total error count for this bus		*/
	SlaveCntr	slaveCnt[MAX_SLAVES]; /* Msg/Error counts for slaves	*/
	Byte		sndBuf[MAX_MSG_LEN];
	Byte		rcvBuf[MAX_MSG_LEN];
} ModBusStruct;					/****************************************/

typedef ModBusStruct *ModBusHandle;


/********************************/
/* Function Codes				*/
/********************************/
#define FC_READ_COILS			 1
#define FC_READ_INPUTS			 2
#define FC_READ_HOLDING_REGS	 3	
#define FC_READ_INPUT_REGS		 4
#define FC_WRITE_ONE_COIL		 5
#define FC_WRITE_ONE_REG		 6
#define FC_WRITE_MULT_COILS		15
#define FC_WRITE_MULT_REGS		16
#define FC_REPORT_SLAVE_ID		17
#define FC_WRITE_READ_MULT_REGS 23
#define FC_READ_FIFO_QUEUE		24


/********************************/
/* Exception Return Codes		*/
/* OK defined as 0 in oasis.h	*/
/********************************/
/* Exception codes defined by standard */
#define ILLEGAL_FUNCTION		-1
#define ILLEGAL_DATA_ADDRESS	-2
#define ILLEGAL_DATA_VALUE		-3
#define SLAVE_DEVICE_FAILURE	-4
#define ACKNOWLEDGE				-5
#define SLAVE_DEVICE_BUSY		-6
#define NEGATIVE_ACKNOWLEDGE	-7
#define MEMORY_PARITY_ERROR		-8
#define GATEWAY_PROBLEM_PATH	-10
#define GATEWAY_PROBLEM_TARGET	-11

/* Local failure codes			*/
#define SEND_FAILURE			-12
#define COMM_TIME_OUT			-13
#define INVALID_CRC				-14
#define ILLEGAL_RESPONSE		-15
#define INVALID_EXCEPTION_CODE	-16
#define ILLEGAL_PORT			-17
#define DATA_SIZE_ERROR			-18
#define PORT_ERROR				-19
#define RCV_TIMEOUT				-20
#define SLAVE_ID_MISMATCH		-21
#define FUNC_CODE_MISMATCH		-22
#define PORT_CONFLICT			-23				/* Conflict in assigning port		*/
#define PORT_IN_USE				-24

#define NUM_ERR_CODES	24


/****************************************/
/* Function Declarations				*/
/****************************************/

Errno	readCoils(ModBusHandle mh, Nat16 slave, Nat16 startAddr,
				  Nat16 numCoils, Byte *result);
Errno	readInputs(ModBusHandle mh, Nat16 slave, Nat16 startAddr,
					Nat16 numInputs, Byte *result);
Errno	readHoldingRegs(ModBusHandle mh, Nat16 slave, Nat16 startAddr,
						Nat16 numRegs, Nat16 *result);
Errno	readInputRegs(ModBusHandle mh, Nat16 slave, Nat16 startAddr,
					  Nat16 numRegs, Nat16 *result);
Errno	writeOneCoil(ModBusHandle mh, Nat16 slave, Nat16 coilAddr,
					 MBool on);
Errno	writeOneReg(ModBusHandle mh, Nat16 slave, Nat16 regAddr,
					Nat16 value);
Errno	writeCoils(ModBusHandle mh, Nat16 slave, Nat16 startAddr,
				   Nat16 numCoils, const Byte *data);

Errno	writeRegs(ModBusHandle mh, Nat16 slave, Nat16 startAddr,
				  Nat16 numRegs, const Nat16 *data);
Errno	reportSlaveId(ModBusHandle mh, Nat16 slave, Byte *result);
Errno	writeReadRegs(ModBusHandle mh, Nat16 slave, Nat16 readAddr,
					  Nat16 numReads, Nat16 writeAddr, Nat16 numWrites,
					  const Nat16 *writeData, Nat16 *readData);
Errno	writeReadSpecial(ModBusHandle mh, Nat16 slave, Nat16 readAddr,
						 Nat16 numReads, Nat16 writeAddr, Nat16 numWrites1,
						 Byte *writeData1, Nat16 numWrites2, Byte *writeData2,
						 Nat16 *readData);

/* From modbuscrc.c */
Nat16	mod_crc16(Byte *buffer, Nat16 buffer_length);
Errno	check_mod_crc16(Byte *msg, const Nat16 msg_length);

/* From modbusio.c */
Void	initModBus(Void);
Void	getModbusPort(Nat16 serport);
Void	releaseModbusPort(Nat16 serport);
Errno	modBusConfigure(Nat16 port, Nat32 baud, Nat32 mode,
						Nat32 surgeDelayMs, Nat32 flags);
MBool	modBusConfigured(Nat16 port);
MBool	modBusIsPowered(Nat16 port);
Int16	usrModPower(Nat16 pmask, Parm_t port, Parm_t onoff);
ModBusHandle modBusOpen(Nat16 port);
Errno	modBusClose(ModBusHandle mh);
Errno	modBusIO(ModBusHandle mh, Nat16 sndLen);
Int16	showModBus(Void);
Errno	logModBus(Int32 argc, char **argv, MBool syntaxOnly);
SlaveCntr *findSlaveCntr(ModBusHandle mh, Nat16 slaveID);

/* From modbuserr.c */
const char *modBusErrString(Errno errno);
Void	logModResult(ModBusHandle mh, Errno rtnCode, Nat16 sndLen);

#endif	/* INCmodbush */
