/*
 *
 *  BlueZ - Bluetooth protocol stack for Linux
 *
 *  Copyright (C) 2000-2005  CSR Ltd.
 *
 *
 *  Permission is hereby granted, free of charge, to any person obtaining
 *  a copy of this software and associated documentation files (the
 *  "Software"), to deal in the Software without restriction, including
 *  without limitation the rights to use, copy, modify, merge, publish,
 *  distribute, sublicense, and/or sell copies of the Software, and to
 *  permit persons to whom the Software is furnished to do so, subject to
 *  the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included
 *  in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/**                                                                         **/
/** ubcsp,c                                                                 **/
/**                                                                         **/
/** MicroBCSP - a very low cost implementation of the BCSP protocol         **/
/**                                                                         **/
/*****************************************************************************/

#include "ubcsp.h"

#if SHOW_PACKET_ERRORS || SHOW_LE_STATES
#include <stdio.h>
#include <windows.h>
#endif

static uint16 ubcsp_calc_crc (uint8 ch, uint16 crc);
static uint16 ubcsp_crc_reverse (uint16);

/*****************************************************************************/
/**                                                                         **/
/** Constant Data - ROM                                                     **/
/**                                                                         **/
/*****************************************************************************/

/* This is the storage for the link establishment messages */

static const uint8 ubcsp_le_buffer[4][4] =
	{
		{ 0xDA, 0xDC, 0xED, 0xED },
		{ 0xAC, 0xAF, 0xEF, 0xEE },
		{ 0xAD, 0xEF, 0xAC, 0xED },
		{ 0xDE, 0xAD, 0xD0, 0xD0 },
	};

/* These are the link establishment headers */
/* The two version are for the CRC and non-CRC varients */

#if UBCSP_CRC
static const uint8 ubcsp_send_le_header[4] = 
	{
		0x40, 0x41, 0x00, 0x7E
	};
#else
static const uint8 ubcsp_send_le_header[4] = 
	{
		0x00, 0x41, 0x00, 0xBE
	};
#endif

/*****************************************************************************/
/**                                                                         **/
/** Static Data - RAM                                                       **/
/**                                                                         **/
/*****************************************************************************/

/* This is the storage for all state data for ubcsp */

static struct ubcsp_configuration ubcsp_config;

/* This is the ACK packet header - this will be overwritten when
   we create an ack packet */

static uint8 ubcsp_send_ack_header[4] = 
	{
		0x00, 0x00, 0x00, 0x00
	};

/* This is the deslip lookup table */

static const uint8 ubcsp_deslip[2] =
	{
		SLIP_FRAME, SLIP_ESCAPE,
	};

/* This is a state machine table for link establishment */

static uint8 next_le_packet[16] =
	{
		ubcsp_le_sync,			// uninit
		ubcsp_le_conf,			// init
		ubcsp_le_none,			// active
		ubcsp_le_none,
		ubcsp_le_sync_resp,		// sync_resp
		ubcsp_le_sync_resp,
		ubcsp_le_none,
		ubcsp_le_none,
		ubcsp_le_none,			// conf_resp
		ubcsp_le_conf_resp,
		ubcsp_le_conf_resp,
		ubcsp_le_none,
	};

/* This is the storage required for building send and crc data */

static uint8 ubcsp_send_header[4];
static uint8 ubcsp_send_crc[2];

/* This is where the receive header is stored before the payload arrives */

static uint8 ubcsp_receive_header[4];

/*****************************************************************************/
/**                                                                         **/
/** Code - ROM or RAM                                                       **/
/**                                                                         **/
/*****************************************************************************/

/*****************************************************************************/
/**                                                                         **/
/** ubcsp_initialize                                                        **/
/**                                                                         **/
/** This initializes the state of the ubcsp engine to a known values        **/
/**                                                                         **/
/*****************************************************************************/

void ubcsp_initialize (void)
{
	ubcsp_config.ack_number = 0;
	ubcsp_config.sequence_number = 0;
	ubcsp_config.send_ptr = 0;
	ubcsp_config.send_size = 0;
	ubcsp_config.receive_index = -4;

	ubcsp_config.delay = 0;

#if SHOW_LE_STATES
	printf ("Hello Link Uninitialized\n");
#endif

	ubcsp_config.link_establishment_state = ubcsp_le_uninitialized;
	ubcsp_config.link_establishment_packet = ubcsp_le_sync;
}

/*****************************************************************************/
/**                                                                         **/
/** ubcsp_send_packet                                                       **/
/**                                                                         **/
/** This sends a packet structure for sending to the ubcsp engine           **/
/** This can only be called when the activity indication from ubcsp_poll    **/
/** indicates that a packet can be sent with UBCSP_PACKET_SENT              **/
/**                                                                         **/
/*****************************************************************************/

void ubcsp_send_packet (struct ubcsp_packet *send_packet)
{
	/* Initialize the send data to the packet we want to send */

	ubcsp_config.send_packet = send_packet;

	/* we cannot send the packet at the moment
	   when we can at the moment, just set things to 0 */

	ubcsp_config.send_size = 0;
	ubcsp_config.send_ptr = 0;
}

/*****************************************************************************/
/**                                                                         **/
/** ubcsp_receive_packet                                                    **/
/**                                                                         **/
/** This sends a packet structure for receiving to the ubcsp engine         **/
/** This can only be called when the activity indication from ubcsp_poll    **/
/** indicates that a packet can be sent with UBCSP_PACKET_RECEIVED          **/
/**                                                                         **/
/*****************************************************************************/

void ubcsp_receive_packet (struct ubcsp_packet *receive_packet)
{
	/* Initialize the receive data to the packet we want to receive */

	ubcsp_config.receive_packet = receive_packet;

	/* setup to receive the header first */

	ubcsp_config.receive_index = -4;
}

/*****************************************************************************/
/**                                                                         **/
/** ubcsp_calc_crc                                                          **/
/**                                                                         **/
/** Takes the next 8 bit value ch, and updates the crc with this value      **/
/**                                                                         **/
/*****************************************************************************/


#ifdef UBCSP_CRC

static uint16 ubcsp_calc_crc (uint8 ch, uint16 crc)
{
	/* Calculate the CRC using the above 16 entry lookup table */

	static const uint16 crc_table[] =
		{
			0x0000, 0x1081, 0x2102, 0x3183,
			0x4204, 0x5285, 0x6306, 0x7387,
			0x8408, 0x9489, 0xa50a, 0xb58b,
			0xc60c, 0xd68d, 0xe70e, 0xf78f
		};

	/* Do this four bits at a time - more code, less space */

    crc = (crc >> 4) ^ crc_table[(crc ^ ch) & 0x000f];
    crc = (crc >> 4) ^ crc_table[(crc ^ (ch >> 4)) & 0x000f];

	return crc;
}

/*****************************************************************************/
/**                                                                         **/
/** ubcsp_crc_reverse                                                       **/
/**                                                                         **/
/** Reserves the bits in crc and returns the new value                      **/
/**                                                                         **/
/*****************************************************************************/

static uint16 ubcsp_crc_reverse (uint16 crc)
{
	int32
		b,
		rev;

	/* Reserse the bits to compute the actual CRC value */

	for (b = 0, rev=0; b < 16; b++)
	{
		rev = rev << 1;
		rev |= (crc & 1);
		crc = crc >> 1;
	}

	return rev;
}

#endif

/*****************************************************************************/
/**                                                                         **/
/** ubcsp_put_slip_uart                                                     **/
/**                                                                         **/
/** Outputs a single octet to the uart                                      **/
/** If the octet needs to be escaped, then output the escape value          **/
/** and then store the second octet to be output later                      **/
/**                                                                         **/
/*****************************************************************************/

static void ubcsp_put_slip_uart (uint8 ch)
{
	/* output a single UART octet */

	/* If it needs to be escaped, then output the escape octet
	   and set the send_slip_escape so that the next time we
	   output the second octet for the escape correctly.
	   This is done right at the top of ubcsp_poll */

	if (ch == SLIP_FRAME)
	{
		put_uart (SLIP_ESCAPE);
		ubcsp_config.send_slip_escape = SLIP_ESCAPE_FRAME;
	}
	else if (ch == SLIP_ESCAPE)
	{
		put_uart (SLIP_ESCAPE);
		ubcsp_config.send_slip_escape = SLIP_ESCAPE_ESCAPE;
	}
	else
	{
		/* Not escaped, so just output octet */

		put_uart (ch);
	}
}

/*****************************************************************************/
/**                                                                         **/
/** ubcsp_which_le_payload                                                  **/
/**                                                                         **/
/** Check the payload of this packet, and determine which of the four       **/
/** link establishment packets this was.                                    **/
/** Can return 5 if it is not a valid link establishment packet             **/
/**                                                                         **/
/*****************************************************************************/

static uint32 ubcsp_which_le_payload (const uint8 *payload)
{
	static int32
		octet,
		loop;

	/* Search through the various link establishment payloads to find
	   which one we have received */

	for (loop = 0; loop < 4; loop ++)
	{
		for (octet = 0; octet < 4; octet ++)
		{
			if (payload[octet] != ubcsp_le_buffer[loop][octet])
			{
				/* Bad match, just to loop again */
				goto bad_match_loop;
			}
		}

		/* All the octets matched, return the value */

		return loop;

		/* Jumps out of octet loop if we got a bad match */
bad_match_loop:
		{}
	}

	/* Non of the link establishment payloads matched - return invalid value */

	return 5;
}

/*****************************************************************************/
/**                                                                         **/
/** ubcsp_recevied_packet                                                   **/
/**                                                                         **/
/** This function is called when we have a SLIP END octet and a full        **/
/** packet header and possibly data in the receive packet                   **/
/**                                                                         **/
/*****************************************************************************/

static uint8 ubcsp_recevied_packet (void)
{
	static uint8
		receive_crc,
		receive_seq,
		receive_ack,
		activity;

#if UBCSP_CRC
	static int32
		loop;

	static uint16
		crc;
#endif

	static uint16
		length;

	/* Keep track of what activity this received packet will cause */

	activity = 0;

	/*** Do all error checks that we can ***/

	/* First check the header checksum */

	if (((ubcsp_receive_header[0] + ubcsp_receive_header[1] + ubcsp_receive_header[2] + ubcsp_receive_header[3]) & 0xff) != 0xff)
	{
		/* Header Checksum Error */

#if SHOW_PACKET_ERRORS
		printf ("\n######################## Header Checksum Error %02X %02X %02X %02X\n",
			ubcsp_receive_header[0],
			ubcsp_receive_header[1],
			ubcsp_receive_header[2],
			ubcsp_receive_header[3]);
#endif

		/* If we have a header checksum error, send an ack in return
		   this gets a packet to be resent as quickly as possible */

		ubcsp_config.send_ack = 1;

		return activity;
	}

	/* Decode the received packets header */

	ubcsp_config.receive_packet->reliable = (ubcsp_receive_header[0] & 0x80) >> 7;

	receive_crc = (ubcsp_receive_header[0] & 0x40) >> 6;
	receive_ack = (ubcsp_receive_header[0] & 0x38) >> 3;
	receive_seq = (ubcsp_receive_header[0] & 0x07);

	ubcsp_config.receive_packet->channel = (ubcsp_receive_header[1] & 0x0f);

	length =
		((ubcsp_receive_header[1] & 0xf0) >> 4) |
		(ubcsp_receive_header[2] << 4);

#if SHOW_PACKET_ERRORS
	if (ubcsp_config.receive_packet->reliable)
	{
		printf (" : %10d         Recv SEQ: %d ACK %d\n",
			GetTickCount () % 100000,
			receive_seq,
			receive_ack);
	}
	else if (ubcsp_config.receive_packet->channel != 1)
	{
		printf (" : %10d          Recv        ACK %d\n",
			GetTickCount () % 100000,
			receive_ack);
	}
#endif

	/* Check for length errors */

#if UBCSP_CRC
	if (receive_crc)
	{
		/* If this packet had a CRC, then the length of the payload 
		   should be 2 less than the received size of the payload */

		if (length + 2 != ubcsp_config.receive_index)
		{
			/* Slip Length Error */

#if SHOW_PACKET_ERRORS
			printf ("\n######################## Slip Length Error (With CRC) %d,%d\n", length, ubcsp_config.receive_index - 2);
#endif

			/* If we have a payload length error, send an ack in return
			   this gets a packet to be resent as quickly as possible */

			ubcsp_config.send_ack = 1;
			return activity;
		}

		/* We have a CRC at the end of this packet */

		ubcsp_config.receive_index -= 2;

		/* Calculate the packet CRC */

		crc = 0xffff;

		/* CRC the packet header */

		for (loop = 0; loop < 4; loop ++)
		{
			crc = ubcsp_calc_crc (ubcsp_receive_header[loop], crc);
		}

		/* CRC the packet payload - without the CRC bytes */

		for (loop = 0; loop < ubcsp_config.receive_index; loop ++)
		{
			crc = ubcsp_calc_crc (ubcsp_config.receive_packet->payload[loop], crc);
		}

		/* Reverse the CRC */

		crc = ubcsp_crc_reverse (crc);

		/* Check the CRC is correct */

		if
		(
			(((crc & 0xff00) >> 8) != ubcsp_config.receive_packet->payload[ubcsp_config.receive_index]) ||
			((crc & 0xff) != ubcsp_config.receive_packet->payload[ubcsp_config.receive_index + 1])
		)
		{
#if SHOW_PACKET_ERRORS
			printf ("\n######################## CRC Error\n");
#endif

			/* If we have a packet crc error, send an ack in return
			   this gets a packet to be resent as quickly as possible */

			ubcsp_config.send_ack = 1;
			return activity;
		}
	}
	else
	{
#endif
		/* No CRC present, so just check the length of payload with that received */

		if (length != ubcsp_config.receive_index)
		{
			/* Slip Length Error */

#if SHOW_PACKET_ERRORS
			printf ("\n######################## Slip Length Error (No CRC) %d,%d\n", length, ubcsp_config.receive_index);
#endif

			/* If we have a payload length error, send an ack in return
			   this gets a packet to be resent as quickly as possible */

			ubcsp_config.send_ack = 1;
			return activity;
		}
#if UBCSP_CRC
	}
#endif

	/*** We have a fully formed packet having passed all data integrity checks ***/

	/* Check if we have an ACK for the last packet we sent */

	if (receive_ack != ubcsp_config.sequence_number)
	{
		/* Since we only have a window size of 1, if the ACK is not equal to SEQ
		   then the packet was sent */

		if
		(
			(ubcsp_config.send_packet) &&
			(ubcsp_config.send_packet->reliable)
		)
		{
			/* We had sent a reliable packet, so clear this packet
			   Then increament the sequence number for the next packet */

			ubcsp_config.send_packet = 0;
			ubcsp_config.sequence_number ++;
			ubcsp_config.delay = 0;

			/* Notify the caller that we have SENT a packet */

			activity |= UBCSP_PACKET_SENT;
		}
	}

	/*** Now we can concentrate of the packet we have received ***/

	/* Check for Link Establishment packets */

	if (ubcsp_config.receive_packet->channel == 1)
	{
		/* Link Establishment */

		ubcsp_config.delay = 0;

		/* Find which link establishment packet this payload means
		   This could return 5, meaning none */

		switch (ubcsp_which_le_payload (ubcsp_config.receive_packet->payload))
		{
			case 0:
			{
				/* SYNC Recv'd */

#if SHOW_LE_STATES
				printf ("Recv SYNC\n");
#endif

				/* If we receive a SYNC, then we respond to it with a SYNC RESP
				   but only if we are not active.
				   If we are active, then we have a PEER RESET */

				if (ubcsp_config.link_establishment_state < ubcsp_le_active)
				{
					ubcsp_config.link_establishment_resp = 1;
				}
				else
				{
					/* Peer reset !!!! */

#if SHOW_LE_STATES
					printf ("\n\n\n\n\nPEER RESET\n\n");
#endif

					/* Reinitialize the link */

					ubcsp_initialize ();

					/* Tell the host what has happened */

					return UBCSP_PEER_RESET;
				}
				break;
			}

			case 1:
			{
				/* SYNC RESP Recv'd */

#if SHOW_LE_STATES
				printf ("Recv SYNC RESP\n");
#endif

				/* If we receive a SYNC RESP, push us into the initialized state */

				if (ubcsp_config.link_establishment_state < ubcsp_le_initialized)
				{
#if SHOW_LE_STATES
					printf ("Link Initialized\n");
#endif
					ubcsp_config.link_establishment_state = ubcsp_le_initialized;
				}

				break;
			}

			case 2:
			{
				/* CONF Recv'd */

#if SHOW_LE_STATES
				printf ("Recv CONF\n");
#endif

				/* If we receive a CONF, and we are initialized or active
				   then respond with a CONF RESP */

				if (ubcsp_config.link_establishment_state >= ubcsp_le_initialized)
				{
					ubcsp_config.link_establishment_resp = 2;
				}

				break;
			}

			case 3:
			{
				/* CONF RESP Recv'd */

#if SHOW_LE_STATES
				printf ("Recv CONF RESP\n");
#endif

				/* If we received a CONF RESP, then push us into the active state */

				if (ubcsp_config.link_establishment_state < ubcsp_le_active)
				{
#if SHOW_LE_STATES
					printf ("Link Active\n");
#endif

					ubcsp_config.link_establishment_state = ubcsp_le_active;
					ubcsp_config.send_size = 0;

					return activity | UBCSP_PACKET_SENT;
				}

				break;
			}
		}

		/* We have finished processing Link Establishment packets */
	}
	else if (ubcsp_config.receive_index)
	{
		/* We have some payload data we need to process
		   but only if we are active - otherwise, we just ignore it */

		if (ubcsp_config.link_establishment_state == ubcsp_le_active)
		{
			if (ubcsp_config.receive_packet->reliable)
			{
				/* If the packet we've just received was reliable
				   then send an ACK */

				ubcsp_config.send_ack = 1;

				/* We the sequence number we received is the same as 
				   the last ACK we sent, then we have received a packet in sequence */

				if (receive_seq == ubcsp_config.ack_number)
				{
					/* Increase the ACK number - which will be sent in the next ACK 
					   or normal packet we send */

					ubcsp_config.ack_number ++;

					/* Set the values in the receive_packet structure, so the caller
					   knows how much data we have */

					ubcsp_config.receive_packet->length = length;
					ubcsp_config.receive_packet = 0;

					/* Tell the caller that we have received a packet, and that it
					   will be ACK'ed */

					activity |= UBCSP_PACKET_RECEIVED | UBCSP_PACKET_ACK;
				}
			}
			else 
			{
				/* Set the values in the receive_packet structure, so the caller
				   knows how much data we have */

				ubcsp_config.receive_packet->length = length;
				ubcsp_config.receive_packet = 0;

				/* Tell the caller that we have received a packet */

				activity |= UBCSP_PACKET_RECEIVED;
			}
		}
	}

	/* Just return any activity that occured */

	return activity;
}

/*****************************************************************************/
/**                                                                         **/
/** ubcsp_setup_packet                                                      **/
/**                                                                         **/
/** This function is called to setup a packet to be sent                    **/
/** This allows just a header, or a header and payload to be sent           **/
/** It also allows the header checksum to be precalcuated                   **/
/** or calculated here                                                      **/
/** part1 is always 4 bytes                                                 **/
/**                                                                         **/
/*****************************************************************************/

static void ubcsp_setup_packet (uint8 *part1, uint8 calc, uint8 *part2, uint16 len2)
{
	/* If we need to calculate the checksum, do that now */

	if (calc)
	{
		part1[3] =
			~(part1[0] + part1[1] + part1[2]);
	}

	/* Setup the header send pointer and size so we can clock this out */

	ubcsp_config.send_ptr = part1;
	ubcsp_config.send_size = 4;

	/* Setup the payload send pointer and size */

	ubcsp_config.next_send_ptr = part2;
	ubcsp_config.next_send_size = len2;

#if UBCSP_CRC
	/* Initialize the crc as required */

	ubcsp_config.send_crc = -1;

	ubcsp_config.need_send_crc = 1;
#endif
}

/*****************************************************************************/
/**                                                                         **/
/** ubcsp_sent_packet                                                       **/
/**                                                                         **/
/** Called when we have finished sending a packet                           **/
/** If this packet was unreliable, then notify caller, and clear the data   **/
/**                                                                         **/
/*****************************************************************************/

static uint8 ubcsp_sent_packet (void)
{
	if (ubcsp_config.send_packet)
	{
		if (!ubcsp_config.send_packet->reliable)
		{
			/* We had a packet sent that was unreliable */

			/* Forget about this packet */

			ubcsp_config.send_packet = 0;

			/* Notify caller that they can send another one */

			return UBCSP_PACKET_SENT;
		}
	}

	/* We didn't have a packet, or it was reliable
	   Must wait for ACK before allowing another packet to be sent */

	return 0;
}

/*****************************************************************************/
/**                                                                         **/
/** ubcsp_poll                                                              **/
/**                                                                         **/
/** This is the main function for ubcsp                                     **/
/** It performs a number of tasks                                           **/
/**                                                                         **/
/** 1) Send another octet to the UART - escaping as required                **/
/** 2) Setup the payload to be sent after the header has been sent          **/
/** 3) Send the CRC for the packet if required                              **/
/**                                                                         **/
/** 4) Calculate the next Link Establishment State                          **/
/** 5) Send a Link Establishment packet                                     **/
/** 6) Send a normal packet if available                                    **/
/** 7) Send an ACK packet if required                                       **/
/**                                                                         **/
/** 8) Receive octets from UART and deslip them as required                 **/
/** 9) Place received octets into receive header or receive payload buffer  **/
/** 10) Process received packet when SLIP_END is received                   **/
/**                                                                         **/
/** 11) Keep track of ability of caller to delay recalling                  **/
/**                                                                         **/
/*****************************************************************************/

uint8 ubcsp_poll (uint8 *activity)
{
	uint8
		delay = UBCSP_POLL_TIME_IMMEDIATE;

	uint8
		value;

	/* Assume no activity to start with */

	*activity = 0;

	/* If we don't have to delay, then send something if we can */

	if (!ubcsp_config.delay)
	{
		/* Do we have something we are sending to send */

		if (ubcsp_config.send_size)
		{
			/* We have something to send so send it */

			if (ubcsp_config.send_slip_escape)
			{
				/* Last time we send a SLIP_ESCAPE octet
				   this time send the second escape code */

				put_uart (ubcsp_config.send_slip_escape);

				ubcsp_config.send_slip_escape = 0;
			}
			else
			{
#if UBCSP_CRC
				/* get the value to send, and calculate CRC as we go */

				value = *ubcsp_config.send_ptr ++;

				ubcsp_config.send_crc = ubcsp_calc_crc (value, ubcsp_config.send_crc);

				/* Output the octet */

				ubcsp_put_slip_uart (value);
#else
				/* Just output the octet*/

				ubcsp_put_slip_uart (*ubcsp_config.send_ptr ++);
#endif
			}

			/* If we did output a SLIP_ESCAPE, then don't process the end of a block */

			if ((!ubcsp_config.send_slip_escape) && ((ubcsp_config.send_size = ubcsp_config.send_size - 1) == 0))
			{
				/*** We are at the end of a block - either header or payload ***/

				/* setup the next block */

				ubcsp_config.send_ptr = ubcsp_config.next_send_ptr;
				ubcsp_config.send_size = ubcsp_config.next_send_size;
				ubcsp_config.next_send_ptr = 0;
				ubcsp_config.next_send_size = 0;

#if UBCSP_CRC
				/* If we have no successor block
				   then we might need to send the CRC */

				if (!ubcsp_config.send_ptr)
				{
					if (ubcsp_config.need_send_crc)
					{
						/* reverse the CRC from what we computed along the way */

						ubcsp_config.need_send_crc = 0;

						ubcsp_config.send_crc = ubcsp_crc_reverse (ubcsp_config.send_crc);

						/* Save in the send_crc buffer */

						ubcsp_send_crc[0] = (uint8) (ubcsp_config.send_crc >> 8);
						ubcsp_send_crc[1] = (uint8) ubcsp_config.send_crc;

						/* Setup to send this buffer */

						ubcsp_config.send_ptr = ubcsp_send_crc;
						ubcsp_config.send_size = 2;
					}
					else
					{
						/* We don't need to send the crc
						   either we just have, or this packet doesn't include it */

						/* Output the end of FRAME marker */

						put_uart (SLIP_FRAME);

						/* Check if this is an unreliable packet */

						*activity |= ubcsp_sent_packet ();

						/* We've sent the packet, so don't need to have be called quickly soon */

						delay = UBCSP_POLL_TIME_DELAY;
					}
				}
#else
				/* If we have no successor block
				   then we might need to send the CRC */

				if (!ubcsp_config.send_ptr)
				{
					/* Output the end of FRAME marker */

					put_uart (SLIP_FRAME);

					/* Check if this is an unreliable packet */

					*activity |= ubcsp_sent_packet ();

					/* We've sent the packet, so don't need to have be called quickly soon */

					delay = UBCSP_POLL_TIME_DELAY;
				}
#endif
			}
		}
		else if (ubcsp_config.link_establishment_packet == ubcsp_le_none)
		{
			/* We didn't have something to send
			   AND we have no Link Establishment packet to send */

			if (ubcsp_config.link_establishment_resp & 2)
			{
				/* Send the start of FRAME packet */

				put_uart (SLIP_FRAME);

				/* We did require a RESP packet - so setup the send */

				ubcsp_setup_packet ((uint8*) ubcsp_send_le_header, 0, (uint8*) ubcsp_le_buffer[ubcsp_le_conf_resp], 4);

				/* We have now "sent" this packet */

				ubcsp_config.link_establishment_resp = 0;
			}
			else if (ubcsp_config.send_packet)
			{
				/* There is a packet ready to be sent */

				/* Send the start of FRAME packet */

				put_uart (SLIP_FRAME);

				/* Encode up the packet header using ACK and SEQ numbers */

				ubcsp_send_header[0] =
					(ubcsp_config.send_packet->reliable << 7) |
#if UBCSP_CRC
					0x40 |	/* Always use CRC's */
#endif
					(ubcsp_config.ack_number << 3) | 
					(ubcsp_config.sequence_number);

				/* Encode up the packet header's channel and length */
				ubcsp_send_header[1] =
					(ubcsp_config.send_packet->channel & 0x0f) |
					((ubcsp_config.send_packet->length << 4) & 0xf0);

				ubcsp_send_header[2] =
					(ubcsp_config.send_packet->length >> 4) & 0xff;

				/* Let the ubcsp_setup_packet function calculate the header checksum */

				ubcsp_setup_packet ((uint8*) ubcsp_send_header, 1, ubcsp_config.send_packet->payload, ubcsp_config.send_packet->length);

				/* Don't need to send an ACK - we just place on in this packet */

				ubcsp_config.send_ack = 0;
				
#if SHOW_PACKET_ERRORS
				printf (" : %10d Send %d Ack %d\n",
					GetTickCount () % 100000,
					ubcsp_config.sequence_number,
					ubcsp_config.ack_number);
#endif
			}
			else if (ubcsp_config.send_ack)
			{
				/* Send the start of FRAME packet */

				put_uart (SLIP_FRAME);

#if SHOW_PACKET_ERRORS
				printf (" : %10d Send ACK %d\n",
					GetTickCount () % 100000,
					ubcsp_config.ack_number);
#endif

				/* The ack packet is already computed apart from the first octet */

				ubcsp_send_ack_header[0] =
#if UBCSP_CRC
					0x40 | 
#endif
					(ubcsp_config.ack_number << 3);

				/* Let the ubcsp_setup_packet function calculate the header checksum */

				ubcsp_setup_packet (ubcsp_send_ack_header, 1, 0, 0);

				/* We've now sent the ack */

				ubcsp_config.send_ack = 0;
			}
			else
			{
				/* We didn't have a Link Establishment response packet,
				   a normal packet or an ACK packet to send */

				delay = UBCSP_POLL_TIME_DELAY;
			}
		}
		else
		{
#if SHOW_PACKET_ERRORS
//			printf (" : %10d Send LE %d\n",
//				GetTickCount () % 100000,
//				ubcsp_config.link_establishment_packet);
#endif

			/* Send A Link Establishment Message */

			put_uart (SLIP_FRAME);

			/* Send the Link Establishment header followed by the 
			   Link Establishment packet */

			ubcsp_setup_packet ((uint8*) ubcsp_send_le_header, 0, (uint8*) ubcsp_le_buffer[ubcsp_config.link_establishment_packet], 4);

			/* start sending immediately */

			ubcsp_config.delay = 0;

			/* workout what the next link establishment packet should be */

			ubcsp_config.link_establishment_packet = next_le_packet[ubcsp_config.link_establishment_state + ubcsp_config.link_establishment_resp * 4];

			/* We have now delt with any response packet that we needed */

			ubcsp_config.link_establishment_resp = 0;

			return 0;
		}
	}

	/* We now need to receive any octets from the UART */

	while ((ubcsp_config.receive_packet) && (get_uart (&value)))
	{
		/* If the last octet was SLIP_ESCAPE, then special processing is required */

		if (ubcsp_config.receive_slip_escape)
		{
			/* WARNING - out of range values are not detected !!!
			   This will probably be caught with the checksum or CRC check */

			value = ubcsp_deslip[value - SLIP_ESCAPE_FRAME];

			ubcsp_config.receive_slip_escape = 0;
		}
		else
		{
			/* Check for the SLIP_FRAME octet - must be start or end of packet */
			if (value == SLIP_FRAME)
			{
				/* If we had a full header then we have a packet */

				if (ubcsp_config.receive_index >= 0)
				{
					/* process the received packet */

					*activity |= ubcsp_recevied_packet ();

					if (*activity & UBCSP_PACKET_ACK)
					{
						/* We need to ACK this packet, then don't delay its sending */
						ubcsp_config.delay = 0;
					}
				}

				/* Setup to receive the next packet */

				ubcsp_config.receive_index = -4;

				/* Ok, next octet */

				goto finished_receive;
			}
			else if (value == SLIP_ESCAPE)
			{
				/* If we receive a SLIP_ESCAPE,
				   then remember to process the next special octet */

				ubcsp_config.receive_slip_escape = 1;

				goto finished_receive;
			}
		}

		if (ubcsp_config.receive_index < 0)
		{
			/* We are still receiving the header */

			ubcsp_receive_header[ubcsp_config.receive_index + 4] = value;

			ubcsp_config.receive_index ++;
		}
		else if (ubcsp_config.receive_index < ubcsp_config.receive_packet->length)
		{
			/* We are receiving the payload */
			/* We might stop comming here if we are receiving a
			   packet which is longer than the receive_packet->length
			   given by the host */

			ubcsp_config.receive_packet->payload[ubcsp_config.receive_index] = value;

			ubcsp_config.receive_index ++;
		}

finished_receive:
		{
		}
	}

	if (ubcsp_config.delay > 0)
	{
		/* We were delayed so delay some more
		   this could be cancelled if we received something */

		ubcsp_config.delay --;
	}
	else
	{
		/* We had no delay, so use the delay we just decided to us */

		ubcsp_config.delay = delay;
	}

	/* Report the current delay to the user */

	return ubcsp_config.delay;
}