1181 lines
35 KiB
C
1181 lines
35 KiB
C
/*
|
|
*
|
|
* 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 occurred */
|
|
|
|
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 coming 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;
|
|
}
|