Difference Analysis Generated by HtmlDiff on 10/26/2004 1:34 PM  

Base file: C:\CY4632_RDK_1_21\Firmware\Source Code\RDK Keyboard\protocol.c

Modified file: C:\CY4632_RDK_1_3\Firmware\Source Code\RDK Keyboard\protocol.c

//--------------------------------------------------------------------------
//
// Collection of functions which support the WSUB LS Protocol for 
// HID and HID like devices
//
//--------------------------------------------------------------------------
// $Archive: /WirelessUSB/WUSB Kits/CY4632 LS KBM RDK/DocSrc/CD_Root/Firmware/Source Code/RDK Keyboard/protocol.c $
// $Modtime: 6/16/04 3:32p9/29/04 2:19p $
// $Revision: 78 $
//--------------------------------------------------------------------------
//
// 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 "protocol.h"
#include "bind.h"
#include "radio.h"

const UINT8 checkMask[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};

UINT8  gDataToggle      = 0x55;  
LS_TX_PACKET txPacket;
UINT8 protocol_device_type = DEVICE_TYPE;

#if (defined TWO_WAY) || (defined RX_MODE)
LS_RX_PACKET rxPacket;
UINT8  gRxDataToggle      = 0x99;  
#endif

///////////////////////////////////////////////////////////////////////////////
//
//  Function:    protocol_init
//
//  Description: Initializes the LS Radio and bind protocol
//
//  Inputs:      None
//
//  Returns:     Void
//
///////////////////////////////////////////////////////////////////////////////

Status protocol_init()
{
    #ifndef TWO_WAY
    txPacket.first.byte = 0x50;    // Data packet
    #endif

    protocol_get_nvram()device_type = DEVICE_TYPE;
    
    // configure the Radio
    radio_init();

    // set up the channel and PN Code
    protocol_bind_init();
    
    return Sts_OK;// get nvram
}

///////////////////////////////////////////////////////////////////////////////
//
//  Function:    protocol_get_nvram
//
//  Description: Reads stored system parameters from NVRAM
//
//  Inputs:      None
//
//  Returns:     Void
//
///////////////////////////////////////////////////////////////////////////////

void protocol_get_nvram(void)
{
    NVRAM_READ( &sysParams, sizeof(sysParams) );

    // check for uninitialized parameters
    if (sysParams.networkId.signature != SIGNATURE_BYTE) 
    {
        // set channel and pnCode to a value that will allow the different
        // devices to coexist and interfere less with each other
        sysParams.networkId.signature   = SIGNATURE_BYTE;
        sysParams.networkId.channel     = DEFAULT_CHAN;
        sysParams.networkId.pnCode      = DEFAULT_PNCODE;
        sysParams.networkId.seed        = DEFAULT_SEED;
        sysParams.networkId.pin         = 0;
        sysParams.networkId.baseChannel = 0xff0xFF;

        #ifndef PROTOCOL_1_1
        NVRAM_WRITE( &sysParams );
        #endif // PROTOCOL_1_1
    }
    
    #ifdef PROTOCOL_1_1
    else
    {
        // calculate channel, PN code, etc. from Bridge MID and store values in sysParams
        // values in sysParams
        calculate_network_id();
    }
    #endif
}


    
    // configure the Radio
    radio_init();

    // set up the channel and PN Code
    protocol_bind_init();
    
    return Sts_OK;
}

///////////////////////////////////////////////////////////////////////////////
//
//  Function:    calculate_network_id
//
///////////////////////////////////////////////////////////////////////////////

#ifdef PROTOCOL_1_1
void calculate_network_id(void)
{
    UINT8 baseChannel, pnCode, seed;

    // calculate PN Code
    pnCode = sysParams.bridgeMid.mid1 ^ sysParams.bridgeMid.mid2 ^ sysParams.bridgeMid.mid3;
             sysParams.bridgeMid.mid3;

    while (pnCode >= NUM_PNCODES) 
    {
        pnCode -= NUM_PNCODES;
    }

    // calculate base channel
    baseChannel = sysParams.bridgeMid.mid1;

    while (baseChannel >= NUM_CHANNELS)
    {
        baseChannel -= NUM_CHANNELS;
    }

    seed = sysParams.bridgeMid.mid1 + sysParams.bridgeMid.mid2 + sysParams.bridgeMid.mid3 + 
           sysParams.bridgeMid.mid3 + sysParams.bridgeMid.mid4;

    sysParams.networkId.baseChannel     = baseChannel;
    sysParams.networkId.channel         = baseChannel;
    sysParams.networkId.pnCode          = pnCode;
    sysParams.networkId.seed            = seed;
    sysParams.networkId.pin             = 0;
}
#endif // PROTOCOL_1_1


///////////////////////////////////////////////////////////////////////////////
//
//  Function:    protocol_get_tx_pkt
//
//  Description: Returns a pointer to a radio_transmit buffer pool controlled by the
//               controlled by the protocol, currently in the PSoC only 1 buffer is used due to
//               1 buffer is used due to memory limitations
//
//  Inputs:      None
//
//  Returns:     void *
//
///////////////////////////////////////////////////////////////////////////////

void * protocol_get_tx_pkt(void)
{
    return &txPacket.data.appPacket;
}


#ifdef RETURN_TX_PACKET
///////////////////////////////////////////////////////////////////////////////
//
//  Function:    protocol_rtrn_tx_pkt
//
//  Description: Fress Frees a pointer to a radio_transmit buffer pool controlled by the
//               by the protocol, currently in the PSoC only 1 buffer is used due to
//               used due to memory limitations
//
//  Inputs:      void *
//
//  Returns:     Status
//
///////////////////////////////////////////////////////////////////////////////

Status protocol_rtrn_tx_pkt(void * pPacket)
{
    return Sts_OK;
}
#endif RETURN_TX_PACKET


#ifdef TWO_WAY

#ifdef USE_RX_PACKET
///////////////////////////////////////////////////////////////////////////////
//
//  Function:    protocol_get_rx_pkt
//
//  Description: Returns a pointer to a protocol_receive buffer pool controlled by the
//               controlled by the protocol, currently in the PSoC only 1 buffer is used due to
//               1 buffer is used due to memory limitations
//
//  Inputs:      None
//
//  Returns:     void *
//
///////////////////////////////////////////////////////////////////////////////

void * protocol_get_rx_pkt(void)
{
    return &rxPacket.data.appPacket;
}

///////////////////////////////////////////////////////////////////////////////
//
//  Function:    protocol_rtrn_rx_pkt
//
//  Description: Fress a pointer to a protocol_receive buffer pool controlled by the
//               by the protocol, currently in the PSoC only 1 buffer is used due to
//               due to memory limitations
//
//  Inputs:      void *
//
//  Returns:     Status
//
///////////////////////////////////////////////////////////////////////////////

Status protocol_rtrn_rx_pkt(void * pPacket)
{
    return Sts_OK;
}

#endif  // USE_RX_PACKET
#endif  // TWO_WAY


#ifndef TWO_WAY

///////////////////////////////////////////////////////////////////////////////
//
//  Function:    protocol_send_packet
//
//  Description: Transmit a packet out the LS Radio, using the One Way WUSB
//               LS Protocol 
//
//  Inputs:      None
//
//  Returns:     void *
//
///////////////////////////////////////////////////////////////////////////////

UINT8 protocol_send_packet(UINT8 dataLength)    // One Way
{
    UINT8 i, length, sequence;
    UINT8 length;
    
    #ifdef SLEEP_ENABLED
    radio_wakeupRADIO_WAKEUP();
    #endif

    // send a Null Packet to poll for back channel data or as a keep alive packet...
    // keep alive packet...
    if(dataLength == 0) 
    {
        // NULL packet from 2-way protocol, used as keep-alive
        txPacket.first.byte = 0x70; 
        length = 1;
    }
    
    // setup for a Data Packet and bump the data toggle
    else if (dataLength <=  APP_TX_PACKET_SIZE + 1) 
    {     
        txPacket.first.byte       = 0; 
        txPacket.data.hdr.type    = DATA_PACKET;
        txPacket.data.hdr.fill    = 0;
        txPacket.data.hdr.dt_data = gDataToggle++;
        txPacket.data.hdr.devId   = (DEVICE_TYPEprotocol_device_type & 0x01);
        txPacket.data.hdr.parity  = protocol_gen_parity(txPacket.first.byte);
    
        // calculate check sum, etc...
        txPacket.data.appPacket[dataLength] = 
            protocol_calc_ck_sum((UINT8 *)&txPacket, dataLength+1,
                                  sysParams.networkId.seed);
        length = dataLength + 2;
    }

        radio_transmit_onset_channel(sysParams.networkId.channel);
    radio_transmit_on();
    radio_transmit(length, (UINT8 *)&txPacket);
    radio_offSPI_RADIO_OFF();

    // perform retransmit, if TX_NUM_TRANS = 1 this 
    // loop doesn't execute
    for(i = 1; i < TX_NUM_TRANS - 1 >= i; i++)
    {
        // wait between packet retransmissions
        TIMER_DELAY_MSEC(GAP_DELAY);
            radio_transmit_onset_channel(sysParams.networkId.channel);
        radio_transmit_on();
        radio_transmit(length, (UINT8 *)&txPacket);
        radio_offSPI_RADIO_OFF();
    }
    
       RADIO_SLEEP();
    #ifdef SLEEP_ENABLED
    radio_sleep();
    #endif

    return DATA_SENT;
}

#endif // ifndef TWO_WAY


#ifdef TWO_WAY

///////////////////////////////////////////////////////////////////////////////
//
//  Function:    protocol_send_packet
//
//  Description: Transmit a packet out the LS Radio, using the Two Way WUSB
//               LS Protocol 
//
//  Inputs:      Length of packet, 0 = send NULL packet
//
//  Returns:     void *
//
///////////////////////////////////////////////////////////////////////////////

UINT8 protocol_send_packet( UINT8 dataLength )   // Two Way
{                
    UINT8  txTimeout;   
    UINT8  ackTimeout;  
    UINT8  pktReceived;
    UINT8  length;
    UINT8  rLength;
    

    #ifdef SLEEP_ENABLED
    radio_wakeupRADIO_WAKEUP();
    #endif
       
    // setup loop control variables
    txTimeout   = 0;
    pktReceived = NO_PACKET;

    if (gBindMode != CONNECTED_STATE) 
    {
        protocol_reconnect();
        return TX_TIMEOUT_ERR;
    }
       
    txPacket.first.byte = 0;            // clear the header byte

    // send a Null Packet to poll for back channel data or as a keep alive packet...
    // alive packet...
    if(dataLength == 0) 
    {
        txPacket.null.hdr.type   = NULL_PACKET;
        #ifdef NULL_PACKET_DATA
        txPacket.null.hdr.fill   = (txPacket.data.appPacket[0] & 0x03);
        #else
        txPacket.null.hdr.fill = 0;
        #endif
        
        #ifdef COMBO_DEVICE
        txPacket.null.hdr.devId  = (DEVICE_TYPE & 0x01);
        txPacket.null.hdr.devId  = (protocol_device_type & 0x01);
        #else
        txPacket.null.hdr.devId = 0;
        #endif // COMBO_DEVICE
        
        txPacket.null.hdr.parity = protocol_gen_parity(txPacket.first.byte);
        length = NULL_LEN;
        
        #ifdef CHECKSUM_ALL_PACKETS
        txPacket.data.appPacket[0] = 
            protocol_calc_ck_sum((UINT8 *)&txPacket, 1, 
        txPacket.data.appPacket[0] = protocol_calc_ck_sum((UINT8 *)&txPacket, 1,                                 sysParams.networkId.seed );
        #endif        
    }
    // setup for a Data Packet and bump the data toggle
    else if (dataLength <=  APP_TX_PACKET_SIZE + 1) 
    {            
        txPacket.data.hdr.type    = DATA_PACKET;
        
        #ifdef COMBO_DEVICE
        txPacket.data.hdr.devId   = (DEVICE_TYPEprotocol_device_type & 0x01);
        #else
        txPacket.data.hdr.devId   = 0;
        #endif // COMBO_DEVICE
        
        txPacket.data.hdr.dt_data = gDataToggle;
        
        //txPacket.data.hdr.fill    = 0;
        txPacket.data.hdr.parity  = protocol_gen_parity(txPacket.first.byte);
        
        // calculate check sum
        txPacket.data.appPacket[dataLength] = protocol_calc_ck_sum(
                                             (UINT8 *)&txPacket, dataLength+1,
                                              sysParams.networkId.seed );
        length = dataLength + 2;   // length = header + data + checksum
    }
    else 
    {
        return( INVALID_DATA );   
    }

    // setup radio_transmit mode, give more time to settle
    radio_transmit_onset_channel(sysParams.networkId.channel);
    
    // initialize loop control
    pktReceived = NO_PACKET;
    txTimeout   = 0;
    
    //loop until ACK radio_received or retries exhausted
    while((pktReceived == NO_PACKET) && (txTimeout++ < TX_TIMEOUT))
    {
        // Power Savings Initiative
    for(txTimeout = 0; (pktReceived == NO_PACKET) && (txTimeout < TX_TIMEOUT); 
        if (txTimeout != 1) txTimeout++)
        {
            radio_switch_txtransmit_on();
        }
        
        // send the packet
        radio_transmit(length, (UINT8 *)&txPacket);

        #ifdef SLEEP_ENABLED        
        // Power Savings Initiative
        // do not immediately switch into RX mode...
        TIMER_DELAY_50_USEC();
        TIMER_DELAY_50_USEC();
        TIMER_DELAY_50_USEC();
        TIMER_DELAY_10_USEC();
        TIMER_DELAY_10_USEC();
        #endif

        // setup receive mode
        radio_switch_rxreceive_on();                
       
        ackTimeout = 0;    // reset the ack timeout 

        // get an ACK 
        pktReceived = protocol_receive(&rLength);

        // verify packet is the expected type
        // reset the ack timeout 
        while(for(ackTimeout = 0; (pktReceived != ACK_PACKET) && 
               (pktReceived != DATA_ACK_PACKET) && 
               (+                  (ACK_TIMEOUT*5-1 >= ackTimeout); ++ackTimeout < ACK_TIMEOUT) )            
        {
            if( pktReceived != NO_PACKET )
            {
                pktReceived = NO_PACKET; // stay in ACK loop                
            }

            TIMER_DELAY_5010_USEC();  
            
            pktReceived = protocol_receive(&rLength);
        }

        RADIO_ISR_DISABLE();

        if (pktReceived == DATA_ACK_PACKET )
        {
            #ifdef DATA_ACK_FILTER_VALUE
            if( rxPacket.ackData.hdr.flag == GOOD_ACK &&
                rxPacket.data.appPacket[0] == DATA_ACK_FILTER_VALUE )
            #else
            if( rxPacket.ackData.hdr.flag == GOOD_ACK )
            #endif
            {
                #ifdef BACK_CHANNEL_DATA  
                radio_switch_txtransmit_on();
                protocol_send_ack();
                #ifndef SPI_RADIO_DEFAULT_ONOFF();
                radio_offRADIO_SLEEP();
                #endif
                #ifdef SLEEP_ENABLED
                radio_sleep();
                #endif
                if (txPacket.null.hdr.type != 0x07)
                {
                    // flip the data toggle bit to signal an acknowledged packet
                    // transmission
                    gDataToggle++;    
                }
                return( ACK_DATA );    
                #endif
            }
            else // NAK
            {
                // reset the control variables for retransmission
                pktReceived = NO_PACKET;
            }
        }
        else if(pktReceived == ACK_PACKET)
        {
            #ifdef COMBO_DEVICE        
            if( (rxPacket.ack.hdr.flag == GOOD_ACK) && (rLength == ACK_LEN) && 
               ((rxPacket.ack.hdr.devId & 0x01) == (DEVICE_TYPE & 0x01)) &&
                (protocol_device_type & 0x01)) &&
               (((txPacket.null.hdr.type != 0x07) &&
               (rxPacket.ack.hdr.dt_ack == (gDataToggle & 0x01))) || 
               (txPacket.null.hdr.type == 0x07)) )
            #else
            if( (rxPacket.ack.hdr.flag == GOOD_ACK ) && (rLength == ACK_LEN) && 
               (((txPacket.null.hdr.type != 0x07) &&
               (rxPacket.ack.hdr.dt_ack == (gDataToggle & 0x01))) || 
               (txPacket.null.hdr.type == 0x07)) )

            #endif // COMBO_DEVICE          
            {    
                #ifndef SPI_RADIO_DEFAULT_ONOFF();
                radio_off(); //turns off the synthesizer
                #endif
                
                #ifdef RADIO_SLEEP_ENABLED();
                radio_sleep();
                #endif

                if (txPacket.null.hdr.type != 0x07) 
                {
                    // flip the data toggle bit to signal an 
                    // acknowledged packet transmission
                    gDataToggle++;    
                }

                return( DATA_SENT );
            }
            else // NAK
            {
                // reset the control variables for retransmission
                pktReceived = NO_PACKET;
            }                    
        }               
        else if(ACK_TIMEOUT - 1 < ackTimeout >= ACK_TIMEOUT)
        {
            #ifdef ACK_BACKOFF_DELAY
            ACK_BACKOFF_DELAY();
            #endif
        }
    }    // while((pktReceived == NO_PACKET) && (txTimeout++ < TX_TIMEOUT_CNT))
    } // for()
    
    if(TX_TIMEOUT <= txTimeout > TX_TIMEOUT)
    {
        protocol_reconnect();
        #ifndef SPI_RADIO_DEFAULT_ONOFF();
        radio_offRADIO_SLEEP();
        #endif // RADIO_DEFAULT_ON
        #ifdef SLEEP_ENABLED
        radio_sleep();
        #endif // SLEEP_ENABLED
        return( TX_TIMEOUT_ERR );
    }

    #ifndef RADIO_DEFAULT_ON
    radio_off(); //turns off the synthesizer
    #endif
    SPI_RADIO_OFF();
    
    #ifdef SLEEP_ENABLED
    radio_sleepRADIO_SLEEP();
    #endif

    return( INVALID_DATA );   
}

#endif // TWO_WAY


///////////////////////////////////////////////////////////////////////////////
//
//  Function:    protocol_calc_ck_sum
//
//  Description: Calculate Packet Sum Check
//
//  Inputs:      Packet pointer
//               Length of packet
//               Check sum Seed
//
//  Returns:     Checksum
//
///////////////////////////////////////////////////////////////////////////////

UINT8 protocol_calc_ck_sum(UINT8 *data, UINT8 len, UINT8 seed)
                                   UINT8 seed)
{
    UINT8 sum;

    for(sum = seed; len > 0; len--, data++) 
    {
        sum ^= *data;
    }        
    return(sum);
}

///////////////////////////////////////////////////////////////////////////////
//
//  Function:    protocol_gen_parity
//
//  Description: calculate odd parity for a byte
//
//  Inputs:      byte
//
//  Returns:     1 or 0, based on input byte
//
///////////////////////////////////////////////////////////////////////////////

UINT8 protocol_gen_parity(UINT8 data)
{
    UINT8 count = 0;

    for (; data; )
    {
        data>>=1; // shift out the parity bit...

        // check for bits that are set
        if (data & 0x01)
        {
           ++count;
        }   
    }    

    // check for an odd number
    if( count & 0x01 )
        return 0;
    else
        return 1;
}


#ifdef TWO_WAY

///////////////////////////////////////////////////////////////////////////////
//
//  Function:    protocol_send_ack
//
//  Description: send an ACK
//
//  Inputs:      none
//
//  Returns:     N/A
//
///////////////////////////////////////////////////////////////////////////////
void protocol_send_ack(void)
{
    // create ACK packet
    txPacket.first.byte = 0;
    txPacket.ack.hdr.type = ACK_PACKET;
    txPacket.ack.hdr.flag = GOOD_ACK; 

    #ifdef COMBO_DEVICE
    txPacket.ack.hdr.devId = (DEVICE_TYPEprotocol_device_type & 0x01);
    #endif

    // the RX data toggle field is being mirrored back in the ACK
    txPacket.ack.hdr.dt_ack = rxPacket.data.hdr.dt_data;

    txPacket.ack.hdr.parity = protocol_gen_parity( 
                             (UINT8) txPacket.first.byte );        

    #ifdef CHECKSUM_ALL_PACKETS
    txPacket.data.appPacket[0] = 
    txPacket.data.appPacket[0] =        protocol_calc_ck_sum((UINT8 *)&txPacket, 1, sysParams.networkId.seed );
    #endif

    // send the packet
    radio_transmit( ACK_LEN, (UINT8 *)&txPacket );    
}    


///////////////////////////////////////////////////////////////////////////////
//
//  Function:    protocol_receive
//
//  Description: get packet data if available, and copy it to rxPacket
//
//  Inputs:      void
//
//  Returns:     0-f  = Type of Packet radio_received
//               0xff0xFF = nothing radio_received 
//
///////////////////////////////////////////////////////////////////////////////

UINT8 protocol_receive(UINT8 *pLength)
{   
    UINT8  i, j;
    UINT8  packetType;
    UINT8  numErasures; // track # of erasures per column
    UINT8  goodPacket;
    UINT8  checkSum;
    UINT8  badBit   = 0; 
    UINT8  badRow;
    UINT8  badBitCnt = 0;

    if(!gChannelEof)
    {
        return( NO_PACKET );
    }
    
    // initialize control variables 
    goodPacket = TRUE;

    // save off the length of the packet ?? TODO use a global like ???
    *pLength = gChannelBytes;
    if (*pLength == 0) 
    {
        gChannelBytes = 0;  
        gChannelEof = 0;
        return( NO_PACKET );
    }
    
    // check for perfect protocol bytes, requirement for bit correction
    if( (gChannelValid[0] != 0xff) || (gChannelValid[gChannelBytes-1] != 0xff) )
    {
        // packet protocol bytes invalid
        gChannelBytes = 0;  
        gChannelEof = 0;
        return( NO_PACKET );

    } // gChannelValid[0] != 0xff
    
    // blunder check the parity bit   
    if((protocol_gen_parity(rxPacket.first.byte) != (rxPacket.first.byte & 0x01)) ||
       (gChannelValid[0] != 0xff))
    {
        // bad parity in packet
        gChannelBytes = 0;  
        gChannelEof = 0;
        return( NO_PACKET );
    }
    
    // get the packet type, it is the upper nibble in the first byte
    packetType = rxPacket.ack.hdr.type;

    
    // check for perfect protocol bytes, requirement for bit correction AND
    // blunder check the packet typeparity bit  AND 
    if(packetType > MAX_NUM_TYPES)
    {
        // bad format in packet
        gChannelBytes = 0;  
        gChannelEof = 0;
        return( NO_PACKET );
    }

    // blunder check the packet type AND
    // blunder check the data types by length
    if ( (gChannelBytes == 0) || 
         (gChannelValid[0] != 0xFF) || 
         (gChannelValid[gChannelBytes-1] != 0xFF) ||
         ( (protocol_gen_parity(rxPacket.first.byte) != 
           (rxPacket.first.byte & 0x01)) ||
           (gChannelValid[0] != 0xFF) ) || 
         (packetType >= MAX_NUM_TYPES + 1) ||
    if     ( ((packetType == DATA_ACK_PACKET) || (packetType == DATA_PACKET)) && 
        (*pLength < 3) )
    {
        gChannelBytes = 0;  
        gChannelEof = 0;
        return( NO_PACKET );
    }

    if( packetType == ACK_PACKET && *pLength != ACK_LEN )
           (2 >= gChannelBytes) ) || 
         (packetType == ACK_PACKET && gChannelBytes != ACK_LEN) ) 
    {
        // packet protocol bytes invalid OR
        // bad parity in packet OR
        // bad format in packet
        gChannelBytes = 0;  
        gChannelEof = 0;
        return( NO_PACKET );
    }

    // only check/fix packets with checksums
    if((packetType == DATA_PACKET   ||
        packetType == BIND_RESPONSE ||
        packetType == DATA_ACK_PACKET) && goodPacket)
    {

        // quick test for bad bits
        badBit = 0xff0xFF;
        for(i = 1; i < *pLengthgChannelBytes; i++) 
        {
            // AND the colums togethers to find
            // bad bits
            badBit &= gChannelValid[i];
        }
        
        // check for any bad bits
        if(badBit != 0xff0xFF)
        {
            ////////////////////////////////////////////////////////////////////
            //
            //  The sumCheck can only be used to fix packets with a single error
            //  in a column. The sumCheck is always the last byte in the packet.
            //
            //                        0 1 2 3 4 5 6 7
            //                       +---------------+
            //  ChannelPacket[0]     |x|x|x|x|x|x|x|x|      First Byte 
            //                       +---------------+
            //                       +---------------+
            //  ChannelValid [0]     |1|1|0|0|0|1|1|1|      0=Bad bit  
            //                       +---------------+
            //
            //                       +---------------+
            //  ChannelPacket[1]     |x|x|x|x|x|x|x|x|      Data 
            //                       +---------------+
            //                       +---------------+
            //  ChannelValid [1]     |1|1|1|1|1|1|1|1|      0=Bad bit  
            //                       +---------------+
            //
            //                       +---------------+
            //  ChannelPacket[2]     |x|x|x|x|x|x|x|x|      CheckSum  
            //                       +---------------+
            //                       +---------------+
            //  ChannelValid [2]     |1|1|1|1|1|1|1|1|      0=Bad bit  
            //                       +---------------+ 
            //
            ///////////////////////////////////////////////////////////////////////             
            
            // process the data in the Packet by column
            for(        for(i = 0; i < 87 >= i; i++) 
            {
                numErasures = 0;
                
                // test for a column with a bad bit
                if(!(badBit & checkMask[i]))
                if(!(badBit & (1 << i)))
                {
                    if( packetType == BIND_RESPONSE )
                    {
                        checkSum = BIND_SEED;
                    }
                    else
                    {
                        checkSum = sysParams.networkId.seed;
                    }
                    
                    // Now that we have the bad column, figure out which row
                    // has the bad bit
                    for (j = 0; j < *pLength; j++) 
                    for (j = 0; j < gChannelBytes; j++) 
                    {
                        // This is only true if bit j of gChannelValid is 0, 
                        // This is only true if bit j of gChannelValid is 0,                    // an invalid bit
                        if ((gChannelValid[j] & checkMask[i]) == 0) 
                        if ((gChannelValid[j] & (1 << i)) == 0) 
                        {
                            badRow = j;
                    
                            // Using numErasures to tell when 2 bits in the
                            // same column are bad, but it could be used for 
                            // stats as well...
                            numErasures++;
                            badBitCnt++;
                            if( (numErasures > 1) || (badBitCnt > 3) ) 
                            if( (numErasures > 1) || (3 < badBitCnt) ) 
                            {
                                 goodPacket = FALSE;                             // discard the packet because
                                                    // we cannot recover from two
                                                    // erased bits in the same column or
                                                    // there are too many bad bits in
                                                    // general
                                 packetType = NO_PACKET;    
                                 break;
                             }
                        }  
                        else  // good data, calculate checksum
                        {  
                            checkSum ^= *((UINT8 *) (&rxPacket.first.byte) + j);
                        }
                    }  // for (j = 0; j < *pLength; j++)
                    if(goodPacket == FALSE) }  // for ()

                    if(packetType == NO_PACKET) 
                    {
                       break;
                    }
                        
                    if (checkSum & checkMask[i](1 << i))
                    {
                        *((UINT8 *) (&rxPacket.first.byte) + badRow) |= checkMask[i](1 << i);
                    }
                    else 
                    {
                        *((UINT8 *) (&rxPacket.first.byte) + badRow) &= ~checkMask[i];
                            ~(1 << i);
                    }
                } // if (gChannelValid[i] != 0xff)
            }  // for(i = 0; i < length; i++)
                } // if badBit != 0xff()
            } // for()
        } // if badBit != 0xFF

        // compare the checksum....
        if( packetType == BIND_RESPONSE )
        {
            checkSum = BIND_SEED;
        }
        else
        {
            checkSum = sysParams.networkId.seed;
        }

        // Comparing the received checksum with the calculated checksum    
        if (*((UINT8 *) (&rxPacket.first.byte) + ((*pLength)gChannelBytes)-1)) != protocol_calc_ck_sum((UINT8*)&rxPacket.first.byte, (*pLength)-1, checkSum ))
             protocol_calc_ck_sum((UINT8*)&rxPacket.first.byte, 
             (gChannelBytes)-1, checkSum ))
        {
            goodPacket = FALSE;// bad packet
            packetType = NO_PACKET;
        }

    } // if packetType == packet with sumcheck

    // Check for bad packet          
    if (goodPacket == FALSE)
    {
        packetType = NO_PACKET;
    }
    // return parameter
    *pLength = gChannelBytes;

    gChannelBytes = 0;  
    gChannelEof   = 0;
    
    return (packetType);
}

#endif // TWO_WAY