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