//-------------------------------------------------------------------------- // // Collection of the bind functions for basic, sem-auto, and automatic bind. // //-------------------------------------------------------------------------- // $Archive: /WirelessUSB/WUSB Kits/CY4632 LS KBM RDK/DocSrc/CD_Root/Firmware/Source Code/RDK Keyboard/bind.c $ // $Modtime: 6/16/04 2:06p10/01/04 8:38a $ // $Revision: 89 $ //-------------------------------------------------------------------------- // // Copyright 2003-2004, Cypress Semiconductor Corporation. // // This software is owned by Cypress Semiconductor Corporation (Cypress) // and is protected by and subject to worldwide patent protection (United // States and foreign), United States copyright laws and international // treaty provisions. Cypress hereby grants to licensee a personal, // non-exclusive, non-transferable license to copy, use, modify, create // derivative works of, and compile the Cypress Source Code and derivative // works for the sole purpose of creating custom software in support of // licensee product to be used only in conjunction with a Cypress integrated // circuit as specified in the applicable agreement. Any reproduction, // modification, translation, compilation, or representation of this // software except as specified above is prohibited without the express // written permission of Cypress. // // Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND,EXPRESS OR IMPLIED, // WITH REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // Cypress reserves the right to make changes without further notice to the // materials described herein. Cypress does not assume any liability arising // out of the application or use of any product or circuit described herein. // Cypress does not authorize its products for use as critical components in // life-support systems where a malfunction or failure may reasonably be // expected to result in significant injury to the user. The inclusion of // Cypress’ product in a life-support systems application implies that the // manufacturer assumes all risk of such use and in doing so indemnifies // Cypress against all charges. // // Use may be limited by and subject to the applicable Cypress software // license agreement. // //-------------------------------------------------------------------------- #include "ls_config.h" #include "bind.h" #include "protocol.h" #include "radio.h" #ifdef BIND_BASIC /////////////////////////////////////////////////////////////////////////////// // // Function: protocol_bind_init // // Description: Perform the basic bind channel and PN Code setup // // Inputs: None // // Returns: Void // /////////////////////////////////////////////////////////////////////////////// void protocol_bind_init() // Bind Basic { // load pnCode define in application header file radio_set_pn_code(sysParams.networkId.pnCode); #ifdef SLEEP_ENABLED radio_sleepRADIO_SLEEP(); #endif } /////////////////////////////////////////////////////////////////////////////// // // Function: bind // // Description: // // Inputs: channel, pnCode // // Returns: Void // /////////////////////////////////////////////////////////////////////////////// void protocol_bind(UINT8 channel, UINT8 pnCode) // Bind Basic { sysParams.networkId.channel = channel; sysParams.networkId.pnCode = pnCode; } #endif // BIND_BASIC #ifdef BIND_AUTO UINT8 gBindMode = 0; /////////////////////////////////////////////////////////////////////////////// // // Function: get_next_channel // // Description: Perform the channel selection algorithm. Every sixth channel // will be used. // // Inputs: sysParams global for pid and channel variables // // Returns: Void // /////////////////////////////////////////////////////////////////////////////// void get_next_channel(void) { sysParams.networkId.channel += (6 * (sysParams.networkId.pin+1)); if(sysParams.networkId.channel >= (NUM_CHANNELS)) if((NUM_CHANNELS) - 1 < sysParams.networkId.channel) { sysParams.networkId.channel -= NUM_CHANNELS; } } /////////////////////////////////////////////////////////////////////////////// // // Function: init_channel // // Description: Initialize the channel selection algorithm to the top channel // in the channel subset // // Inputs: None // // Returns: Void // /////////////////////////////////////////////////////////////////////////////// void init_channel(void) { sysParams.networkId.channel = sysParams.networkId.baseChannel; while (sysParams.networkId.channel < NUM_CHANNELS- - 6) { sysParams.networkId.channel += 6; } } /////////////////////////////////////////////////////////////////////////////// // // Function: protocol_bind_init // // Description: Perform the basic bind channel and pnCode setup // // Inputs: None // // Returns: Void // /////////////////////////////////////////////////////////////////////////////// void protocol_bind_init() // Bind Auto { init_channel(); gBindMode = DISCONNECTED_STATE; #ifdef SLEEP_ENABLED radio_sleepRADIO_SLEEP(); #endif } /////////////////////////////////////////////////////////////////////////////// // // Function: protocol_bind // // Description: Perform the automatic bind function, get the bind parameters, // bind to a bridge, connect to the bridge, and then return // // Inputs: None // // Returns: Void // /////////////////////////////////////////////////////////////////////////////// UINT8 protocol_bind() // Bind Auto { UINT16 timeout; UINT16UINT8 chanTimeout; UINT8 rLength; UINT8 status = LS_STATUS_SUCCESS; UINT8 ackTimeout; UINT8 pktReceived; UINT8 txTimeout; UINT8 pa_setting; // Bind Operation #ifdef SLEEP_ENABLED radio_wakeup(); #endifRADIO_WAKEUP(); gBindMode = DISCONNECTED_STATE; // format the bind packet txPacket.bind.hdr.type = BIND_REQUEST; txPacket.bind.hdr.devType = DEVICE_TYPE; txPacket.bind.hdr.parity = protocol_gen_parity(txPacket.first.byte); #ifndef PROTOCOL_1_1 // read the radio ID SPI_RADIO_PUT( REG_ANALOG_CTL, (bAGC_RSSI_CTL | bPACTL_EN | bMID_READ_EN )); // read the Radio ID registers txPacket.bind.mid1 = radio_get_id(SPI_RADIO_GET( REG_MFG_ID_1 + RADIO_ID_1 ); txPacket.bind.mid2 = radio_get_id(SPI_RADIO_GET( REG_MFG_ID_1 + RADIO_ID_2 ); txPacket.bind.mid3 = radio_get_id(SPI_RADIO_GET( REG_MFG_ID_1 + RADIO_ID_3 ); txPacket.bind.mid4 = radio_get_id(SPI_RADIO_GET( REG_MFG_ID_1 + RADIO_ID_4 ); // disable the Radio ID registers SPI_RADIO_PUT( REG_ANALOG_CTL, (bAGC_RSSI_CTL | bPACTL_EN )); txPacket.bind.checkSum = protocol_calc_ck_sum((UINT8 *)&txPacket.bind, BIND_REQ_LEN-1, BIND_SEED); sysParams.networkId.pin = 0; #endif // PROTOCOL_1_1 // load the bind pnCode index radio_set_pn_code(BIND_PNCODE); chanTimeout = 0; // Read PA setting pa_setting = (SPI_RADIO_GET(REG_PA) & mPA_BIAS); // load Bind PA SPI_RADIO_PUT(REG_PA, BIND_PA); // seed the channel algorithm with bind parameters 0,0 sysParams.networkId.channel = 0; // send a bind request and wait for response, if no response change // the channel and try again while(chanTimeout++ < BIND_TIMEOUT) for( chanTimeout = 0; chanTimeout < BIND_TIMEOUT; chanTimeout++) { // setup TX loop control variables txTimeout = 0; pktReceived = NO_PACKET; // setup mode radio_transmit_onset_channel(sysParams.networkId.channel); radio_transmit_on(); // loop until ACK radio_received or TX retries exhausted while((pktReceived != BIND_RESPONSE) && (++txTimeout <= BIND_MAX_TRANSMITS)) while( (pktReceived != BIND_RESPONSE) && (++txTimeout <= BIND_MAX_TRANSMITS) ) { radio_switch_txtransmit_on(); radio_transmit(BIND_REQ_LEN, (UINT8 *)&txPacket); radio_switch_rxreceive_on(); // wait for Bind Response ackTimeout = 0; // reset the protocol_receive timeout pktReceived = protocol_receive(&rLength); while( (pktReceived != BIND_RESPONSE) && (++ackTimeout < BIND_ACK_TIMEOUT)) ) { TIMER_DELAY_50_USEC(); pktReceived = protocol_receive(&rLength); } if (pktReceived != BIND_RESPONSE) { // radio_off(); RADIO_SLEEP(); TIMER_DELAY_MSEC(8); RADIO_WAKEUP(); } } // check for Bind timeout if(txTimeout >= BIND_MAX_TRANSMITS) { // Clear Watchdog and Sleep Timer M8C_ClearWDTAndSleep; //try the next channel in the subset of channels get_next_channel(); } else if( (pktReceived == BIND_RESPONSE) && (rLength == BIND_RESP_LEN) ) // Good Ack { // Good Ack // send an ACK txPacket.first.byte = 0; txPacket.ack.hdr.type = ACK_PACKET; txPacket.ack.hdr.flag = GOOD_ACK; txPacket.ack.hdr.parity = protocol_gen_parity( (UINT8) txPacket.first.byte); #ifdef CHECKSUM_ALL_PACKETS txPacket.data.appPacket[0] = protocol_calc_ck_sum((UINT8 *)&txPacket, txPacket.data.appPacket[0] = 1, rxPacket.bind.checkSumSeed );protocol_calc_ck_sum((UINT8 *)&txPacket, 1, rxPacket.bind.checkSumSeed ); #endif // setup radio_transmit mode radio_switch_txtransmit_on(); // send the ACK to the bind response multiple times to // ensure delivery radio_transmit(ACK_LEN, (UINT8 *)&txPacket); radio_switch_txtransmit_on(); TIMER_DELAY_50_USEC(); TIMER_DELAY_50_USEC(); TIMER_DELAY_50_USEC(); TIMER_DELAY_50_USEC(); radio_transmit(ACK_LEN, (UINT8 *)&txPacket); radio_switch_txtransmit_on(); TIMER_DELAY_50_USEC(); TIMER_DELAY_50_USEC(); TIMER_DELAY_50_USEC(); TIMER_DELAY_50_USEC(); radio_transmit(ACK_LEN, (UINT8 *)&txPacket); #ifndef PROTOCOL_1_1 // extract the bind parameters and store them sysParams.networkId.pin = rxPacket.bind.hdr.pin; sysParams.networkId.baseChannel = rxPacket.bind.channel; sysParams.networkId.channel = rxPacket.bind.channel; sysParams.networkId.pnCode = rxPacket.bind.pnCode; sysParams.networkId.seed = rxPacket.bind.checkSumSeed; #else // extract Bridge MID from BIND_RESPONSE // calculate baseChannel, pnCode, etc. sysParams.bridgeMid.mid1 = rxPacket.bind.mid1; sysParams.bridgeMid.mid2 = rxPacket.bind.mid2; sysParams.bridgeMid.mid3 = rxPacket.bind.mid3; sysParams.bridgeMid.mid4 = rxPacket.bind.mid4; rLength = rxPacket.bind.mid4; // store sysParams #endif // PROTOCOL_1_1 break; // exit the whilefor loop } else if( pktReceived == BIND_RESPONSE ) //Failed previous test, bad length { //Failed previous test, bad length // reset loop control variable pktReceived = NO_PACKET; } } // while ~timeoutfor() // Restore PA setting SPI_RADIO_PUT(REG_PA, pa_setting); radio_off(); SPI_RADIO_OFF(); // check the results of the while loop if(chanTimeout >= BIND_TIMEOUT) if(BIND_TIMEOUT - 1 < chanTimeout) { // can't Bind, start over protocol_bind_init(); status = LS_STATUS_FAILED; } else if(pktReceived == BIND_RESPONSE) // ack sent OK { // store parameters in NVRAM NVRAM_WRITE( &sysParams ); #ifdef PROTOCOL_1_1 // calculate channel, PN code, etc. from the Bridge MID calculate_network_id(); #endif // PROTOCOL_1_1 // give the dongle time to ping before trying to reconnect TIMER_DELAY_MSEC(30); // RWW this should be #definedBRIDGE_PING_TIME); init_channel(); status = protocol_reconnect(); #ifdef ENCRYPT_DATA if (status == LS_STATUS_SUCCESS) { encrypt_request_key(); } #endif // ENCRYPT_DATA } #ifdef SLEEP_ENABLED radio_sleep(); #endifRADIO_SLEEP(); return status; } /////////////////////////////////////////////////////////////////////////////// // // Function: protocol_reconnect // // Description: Perform the reconnect phase of the automatic bind function. // bind to a bridge, connect to the bridge, and then return // // Inputs: None // // Returns: Void // /////////////////////////////////////////////////////////////////////////////// UINT8 protocol_reconnect() { UINT16UINT8 timeout; UINT8 rLength; UINT8 status; UINT8 txTimeout; UINT8 ackTimeout; UINT8 pktReceived; #ifdef DYNAMIC_PA_SUPPORT UINT8 pa_setting = mPA_BIAS; UINT8 channel_count = 0; #endif if (sysParams.networkId.baseChannel >= NUM_CHANNELS) { if (NUM_CHANNELS - 1 < sysParams.networkId.baseChannel) { // Turn off the radio radio_off(); #ifdef SLEEP_ENABLED radio_sleep(); #endif SPI_RADIO_OFF(); RADIO_SLEEP(); return LS_STATUS_FAILED; } // check for radio resetting due to a glitch on the nReset // pin. The TX Valids bit should be 0xff0xFF. If not that value the // radio is corrupted. if( SPI_RADIO_GET( REG_VALID_TX ) != 0xff0xFF ) { // reset the radio radio_init(); } // select a channel, send a connect request, and // wait for a connect response // format the bind packet txPacket.connect.hdr.type = CONN_REQUEST; #ifdef DYNAMIC_PA_SUPPORT txPacket.connect.hdr.pin = protocol_device_type; #else txPacket.connect.hdr.pin = sysParams.networkId.pin; #endif txPacket.connect.hdr.parity = protocol_gen_parity((UINT8) txPacket.first.byte); protocol_gen_parity((UINT8) txPacket.first.byte); #ifndef PROTOCOL_1_1 txPacket.connect.channel = sysParams.networkId.baseChannel; txPacket.connect.pnCode = sysParams.networkId.pnCode; // read the radio ID SPI_RADIO_PUT( REG_ANALOG_CTL, (bAGC_RSSI_CTL | bPACTL_EN | bMID_READ_EN )); // read the radio IDs txPacket.connect.mid1 = radio_get_id(SPI_RADIO_GET( REG_MFG_ID_1 + RADIO_ID_1 ); txPacket.connect.mid2 = radio_get_id(SPI_RADIO_GET( REG_MFG_ID_1 + RADIO_ID_2 ); txPacket.connect.mid3 = radio_get_id(SPI_RADIO_GET( REG_MFG_ID_1 + RADIO_ID_3 ); txPacket.connect.mid4 = radio_get_id(SPI_RADIO_GET( REG_MFG_ID_1 + RADIO_ID_4 ); // disable the Radio ID registers SPI_RADIO_PUT( REG_ANALOG_CTL, (bAGC_RSSI_CTL | bPACTL_EN )); #else // load Bridge MID from sysParams into the txPacket... // do I want to keep the bridge MID in sysParams, or should I move it somewhere else???? // it somewhere else???? NVRAM_READ( &txPacket.connect.mid1, 4 ); #endif #ifdef DYNAMIC_PA_SUPPORT // Set PA field txPacket.connect.pa = (SPI_RADIO_GET(REG_PA) & mPA_BIAS); #endif // calculate check sum txPacket.connect.checkSum = protocol_calc_ck_sum( (UINT8 *)&txPacket.connect, CONNECT_REQ_LEN-1, sysParams.networkId.seed ); // load the bind pnCode index radio_set_pn_code(sysParams.networkId.pnCode); timeout = 0; // send a bind request and wait for response, if no response change // the channel and try again while(timeout++ < CONNECT_TIMEOUT) for(timeout=0; timeout<CONNECT_TIMEOUT; timeout++) { #ifdef DYNAMIC_PA_SUPPORT if (SUBSET_CHANNELS - 1 < channel_count) { #ifdef AGC_SUPPORT // Clear Channel count if (timeout == (CONNECT_TIMEOUT/2)) channel_count = 0; // Adjust PA (1,3,5, or 7) if (pa_setting == mPA_BIAS) { pa_setting = 0x1; } else { // Read present AGC value pktReceived = SPI_RADIO_GET(REG_AGC_CTL); pa_setting += 2; } // Change PA setting SPI_RADIO_PUT(REG_PA, pa_setting); // Toggle AGC SPI_RADIO_PUT(REG_AGC_CTL, (pktReceived ^ bAGC_OFF)); // Set PA field txPacket.connect.pa = pa_setting; // calculate check sum txPacket.connect.checkSum = protocol_calc_ck_sum( (UINT8 *)&txPacket.connect, CONNECT_REQ_LEN-1, sysParams.networkId.seed ); } #endif //AGC // DYNAMIC_PA_SUPPORT // setup radio_transmit mode radio_transmit_onset_channel(sysParams.networkId.channel); radio_transmit_on(); radio_transmit(CONNECT_REQ_LEN, (UINT8 *)&txPacket); radio_switch_rxreceive_on(); // wait for Connect Response ackTimeout = 0; // reset the protocol_receive timeout pktReceived = protocol_receive(&rLength); while(for(ackTimeout = 0; (pktReceived != CONN_RESPONSE) && (ackTimeout < CONN_ACK_TIMEOUT); ++ackTimeout < CONN_ACK_TIMEOUT)) { //TIMER_DELAY_50_USEC(); // remove ebd ?? TIMER_DELAY_50_USEC(); pktReceived = protocol_receive(&rLength); } if(pktReceived == CONN_RESPONSE) { if ((rxPacket.connect.hdr.flag == GOOD_ACK ) && (rLength == CONNECT_RESP_LEN)) { // send an ACK for the connect response txPacket.first.byte = 0; txPacket.ack.hdr.type = ACK_PACKET; txPacket.ack.hdr.flag = GOOD_ACK; txPacket.ack.hdr.parity = protocol_gen_parity( (UINT8) txPacket.first.byte); #ifdef CHECKSUM_ALL_PACKETS txPacket.data.appPacket[0] = protocol_calc_ck_sum((UINT8 *)&txPacket, 1, sysParams.networkId.seed );txPacket.data.appPacket[0] = protocol_calc_ck_sum((UINT8 *)&txPacket, 1, sysParams.networkId.seed ); #endif // TIMER_DELAY_50_USEC(); // Remove EBD ?? TIMER_DELAY_50_USEC(); // setup radio_transmit mode radio_switch_txtransmit_on(); radio_transmit(ACK_LEN, (UINT8 *)&txPacket); radio_switch_rx(); radio_receive_on(); break; // exit the loop } else { // bad response, bump channel get_next_channel(); } } else if( CONN_ACK_TIMEOUT - 1 < ackTimeout >= CONN_ACK_TIMEOUT) { #ifdef APP_CALLBACK_FUNC APP_CALLBACK_FUNC(); #endif // Try a few times on the original channel if (ORIGINAL_CHAN_RECONNECT_COUNT < timeout > ORIGINAL_CHAN_RECONNECT_COUNT) { // timeout, bump channel get_next_channel(); #ifdef DYNAMIC_PA_SUPPORT ++channel_count; #endif } } } // end while } // end for(timeout = 0; timeout < CONNECT_TIMEOUT; timeout++) // check the result of the while loop if(pktReceived == CONN_RESPONSE) { // exit back to main() gBindMode = CONNECTED_STATE; // return a success status... status = LS_STATUS_SUCCESS; } else if(CONNECT_TIMEOUT - 1 < timeout >= CONNECT_TIMEOUT) { gBindMode = DISCONNECTED_STATE; status = LS_STATUS_FAILED; } else { status = LS_STATUS_FAILED; } radio_offSPI_RADIO_OFF(); #ifdef SLEEP_ENABLED radio_sleep(); #endif RADIO_SLEEP(); return status; } #endif // BIND_AUTO