/*
 * Copyright (C) 2002 Gary Jennejohn (gj@denx.de)
 *
 * Include file for RS485 on the TRAB
 */

#ifndef _TRAB_RS485_H_
#define _TRAB_RS485_H_

/*
 * An RS485 packet looks lik this:
 *	preamble - 1 byte (MS: 2 bits count: 6 bits)
 *	command - 1 byte (command: 3 bits, target: 5 bits)
 *	data - variable number of bytes
 *	CRC16 - 2 bytes
 */

/* Defined in Besprechungsprotokoll dated 23.07.2002 */
#define MAX_BYTES 64
/*
 * This structure contains information to be passed between the kernel
 * and an application for read/write.
 * NOTE: the kernel calculates the CRC !!
 */
struct rs485_data
{
	/* NOTE: The first five are filled in by the user !! */
	char target_node; /* number of the node on the bus */
	char command_byte; /* the command to send */
	int tx_count; /* how many data bytes to send */
	int rx_expected; /* how many data bytes are expected to be received */
	unsigned char tx_data[MAX_BYTES]; /* bytes to send */
	/* these are filled in by the driver */
	unsigned char rx_data[MAX_BYTES]; /* bytes received */
#define RESULT_OK 0 /* no error */
#define RESULT_TO 1 /* timeout while reading */
#define RESULT_CRC 2 /* bad CRC */
#define RESULT_CNT 3 /* read count incorrect */
#define RESULT_SER 4 /* read count incorrect */
	int result; /* error code - 0 means no error */
};

/*
 * Structure used to control periodic accesses to the nodes to
 * prevent a watchdog timeout.
 *
 * One of these must be passed using the RS485_SET_WDOG ioctl _before_
 * accessing  a node, otherwise the driver will not do periodic acesses. The
 * application can read the data using the RS485_GET_STATUS ioctl.
 *
 * Since the driver has no knowledge of the various protocols supported
 * by the various nodes it is the responsibility of the application to
 * supply a command in this structure which can be used periodically.
 */
struct rs485_wdog {
	int timo; /* maximum timeout in milliseconds */
	struct rs485_data rs485_wdog_data;
#ifdef __KERNEL__
	/* time left until the next access is required */
	unsigned long jiffies;
	/* status bytes changed */
	int statch;
	/* we use a simple linked list */
	struct rs485_wdog *next;
#else
#define DUMMY_BYTES (sizeof(unsigned long) + sizeof(int) + sizeof(struct rs485_wdog *))
	/* to make the size match */
	char dummy[DUMMY_BYTES];
#endif
};

#ifdef __KERNEL__
/* This includes 2 bytes for the CRC */
#define MAX_BYTES_PLUS_CRC (MAX_BYTES + 2)
/* Telegramm layout - used for both transmit and receive */
struct rs485_packet
{
	unsigned char	preamble;
	unsigned char	command;
	unsigned char	data[MAX_BYTES_PLUS_CRC];
	/*
	 * This is either:
	 *  o howe many bytes are left to send or
	 *  o how many bytes total were really received
	 *    including preamble, command and CRC bytes !
	 */
	int count;
	/* offset into data in case more than 1 pass is required */
	int offset;
};

/*
 * NOTE: SET_MSR _must_ be used _before_ SET_COUNT !
 * NOTE: SET_COMMAND _must_ be used _before_ SET_NODE !
 */
/* ptr = &rs485_packet */
#define SET_MS(ptr) (ptr)->preamble = 0x80;
/* ptr1 = &rs485_data, ptr2 = &rs485_packet */
#define SET_COUNT(ptr1, ptr2) (ptr2)->preamble |= ((ptr1)->tx_count & 0x3f);
/* ptr1 = &rs485_data, ptr2 = &rs485_packet */
#define SET_COMMAND(ptr1, ptr2) (ptr2)->command = ((ptr1)->command_byte & 7) << 5;
/* ptr1 = &rs485_data, ptr2 = &rs485_packet */
#define SET_NODE(ptr1, ptr2) (ptr2)->command |= ((ptr1)->target_node & 0x1f);
/* ptr1 = &rs485_data, ptr2 = &rs485_packet */
/* The high byte of the CRC comes first */
#define SET_CRC(crc, ptr1, ptr2) \
			(ptr2)->data[(ptr1)->tx_count + 1] = (crc & 0xff); \
			(ptr2)->data[(ptr1)->tx_count] = (crc >> 8) & 0xff;
/* ptr1 = &rs485_data, ptr2 = &rs485_packet */
/* The CRC is at the end of the data */
#define RCV_OK(ptr1, ptr2) \
		((((ptr2)->preamble & 0x80) == 0) && \
		(((ptr2)->command & 0x1f) == (ptr1)->target_node) && \
		((((ptr2)->command >> 5) & 7) == (ptr1)->command_byte) && \
		((ptr1)->rx_expected == (ptr2)->offset - 4))
/* ptr1 = &rs485_data, ptr2 = &rs485_packet */
#define CRC_OK(crc, ptr1, ptr2) \
		(((ptr2)->data[((ptr1)->rx_expected + 1)] == (crc & 0xff)) && \
		((ptr2)->data[(ptr1)->rx_expected] == ((crc >> 8) & 0xff)))
#endif /* __KERNEL__ */

/* IOCTLs for RS485 on TRAB */
/*
 * Add a new node and its timeout -
 * This uses the rs485_wdog structure defined above.
 * This only goes user -> kernel.
 */
#define RS485_SET_WDOG _IOW('R', 254, struct rs485_wdog)
/*
 * Set timeout period in which the application must re-trigger
 * the watchdogs else the driver removes all watchdogs. This is
 * a safety feature. The period is in seconds.
 */
#define RS485_WDOG_PERIOD _IOW('R', 257, int)
/*
 * Trigger the watchdogs in the driver.
 */
#define RS485_WDOG_TRIGGER _IO('R', 258)
/* returns how many nodes had a status change so the */
/* application can read all results in a loop. */
#define RS485_GET_COUNT _IOR('R', 255, int)
/*
 * Read the new status bytes reported via select().
 * This is only goes kernel -> user.
 * NB: This only copies out 1 structure ! The application must
 * do multiple calls using this ioctl to get the new status
 * values for all affected nodes.
 */
#define RS485_GET_STATUS _IOR('R', 255, struct rs485_data)
#ifdef GJDEBUG
/* reset the state of the driver - for TESTs only ! */
#define RS485_RESET_STATE _IO('R', 256)
#endif
#endif /* _TRAB_RS485_H_ */
