/* | |
* | |
* 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; | |
} |