//----------------------------------------------------------------------------
//  One Way Audio Code
//
//  M J Burns
//  Texas Instruments, Rochester Design Center
//  March 2007
//  Version 2_5  10 July 2007  restructured to allow concurrent PLL calibration
//               24 July 2007  added a 'frametimer' (Timer B) and restructured to resolve the 'lost packet' problem   
//                             simplified the 'waiting for beacon' code
//               01 Sept 2007  added automatic gain adjustment (CC1101 only) 
//               03 Nov  2008  Mofifications for FCC 'narrow band' compliance
//               03 Dec  2008  'Clean Up' 
//                
//  For use with 'CC1150 Tx Rev D' and 'CC1101 Rx Rev B' cards
//
//----------------------------------------------------------------------------

#include "include.h"
#include "string.h"
#include "math.h"

extern char paTable[];
extern char paTableLen;

unsigned int i;
unsigned int m = 1;
unsigned int clktics = 0;         // increments every 125 usec
char pbstatus = 0;                // Push Button Status
unsigned short chan_index = 0;    // index into 'hopping_channels' table

// HOPPING_CHANNELS table. The sequence of these channels is pseudorandom, and includes 25 channels, seperated by 4 (0 to 96)
// The channels spacing is set to 250 kHz, so the channel seperation is .250*4 = 1 MHz.

const unsigned short hopping_channels[] = {20, 80, 12, 88, 24, 96, 48, 16, 64, 72, 84, 36, 52,
                                           44, 76, 60, 92, 40, 28, 4, 56, 8, 32, 68, 0};

// LCD 

extern char lcdtxt[26];
extern char txtstr[6];
extern char lcdline3[8];
extern unsigned short lcdbufrbusy;
extern unsigned short lcdbufrindx;
extern unsigned short lcdlen;

// Subroutine declarations

void MSPInit(void);
int writeLCD(void);
void short2ascii(char, unsigned int);
void int2ascii(unsigned int);

#define SAMPLEPKTS 10         // number of packets used to determine vpmax (Receiver)
#define W4BEACON 1000         // Waiting for Beacon timeout period - 1000*.125 = 125 msec

// The following defined refer to the state of the receiver 'State Machine'

#define SMIDLE      0x00      // Idle (initial) state
#define SMRXON      0x01      // RX On 
#define SMNOSYNC    0x02      // SYNC not detected within timeout period
#define SMNOPKT     0x03      // Packet not received within timeout period
#define SMPKTRCVD   0x04      // Packet was received

// The following DEFINE applies to the Monitor only. If defined, OMITPACKET will omit a packet every HOWOFTEN packets

//#define OMITPACKET
#define HOWOFTEN 500

// The following define allows the a card to be connected to a computer via JP201, using RS232 
// If ENRS232 is defined, \cr\lf will be added to each LCD display line

//#define ENRS232

#ifdef MONITOR
char txBuffer[64];
unsigned int adcbuf[4];           // Used to hold 10 bit ADC samples 
unsigned char adctxbuf[2][ADCTXBUFRLEN];   // ADC TX Buffers
unsigned short adctxptr = 0;      // Pointer into adctxbuf
unsigned short adcsample = 0;     // adcsample (0 - 3)
unsigned short sendpacket = 0;    // Set non zero to initiate TX of data packet
unsigned short activebufr = 0;    // active TX buffer
char locate = 0;                  // When non zero, the receiver should beep and flash
unsigned int adcvalue;
unsigned short agcsamples = 0; 
unsigned int macstate;
unsigned int packetnumber = 0;

#else     // Receiver
char rxBuffer[64];
unsigned short rcvpacket = 0;           // Set non zero when a data packet has been received
unsigned int pwmbufr[2][ADCSAMPLES];    // DAC buffers
unsigned short pwmbufrptr = 0;          // Pointer into DAC buffer (used in unpcaking code)
unsigned short pwmbfrptr = 0;           // Pointer into DAC buffer (used in interrupt code)
unsigned short rxactbufr = 0;           // 'active buffer' pointer used by the unpacking routine (following packet reception)
unsigned short pwmactbufr = 0;          // 'active buffer' pointer used by the PWM (Timer_A) intreeupt handler
unsigned short rx;                      // Pointer into RX buffer
unsigned short resetdacptr = 1;         // Signal to reset the DAC buffer pointer
unsigned short pktstatus = 0;           // Used to indicate when both A and B buffers have filled
unsigned short waitingforbeacon = 1;    // Set until beacon is detected
char attenuation = 0;                   // used to alternate RX gain while 'waiting for beacon'
unsigned int pwm;
char locate = 0;                        // When non zero, the receiver should beep and flash
char tone = 0x00;                       // locate tone
                                        // bit 0: Sound tone  
                                        // bit 1: load ram with tone pattern
                                        // bit 2: 0 = 444.44 Hz, 1 = mute
unsigned int stoptics;                  // used to time for 2.25 msec (18 clktics)
unsigned int adcvalue;
unsigned int adcmax;                    // largest ADC value reached in a packet
unsigned int pktmax = 0;                // maximum value reached in 'SAMPLEPKTS' packets
unsigned short pktsamples = 0;
unsigned short pktslost = 0;            // Conscutive packets lost - used to resync to Monitor
unsigned int macstate;
unsigned short timeractive = 0;
unsigned int timertics = 0;
unsigned int tmo;
unsigned int rssiavg = 0;
unsigned int lqisum = 0;
unsigned int lqiavg = 0;
unsigned short packets = 0;
extern int rssi;                        // Received Signal Strength Indication
extern unsigned short lqi;              // Link Quality Indication
int rssidbm, rssidbmn;
unsigned int pcktsper = 0;              // packet count for PER calculation
unsigned int pecount = 0;               // cumulative packet error count
unsigned int pe1024 = 0;                // number of packet errors in the last 1024 packets
unsigned short smstate = SMIDLE;        // receiver 'state machine' state
unsigned int frametics = 0;
unsigned int tbr = 0;

// Error counters

unsigned short nosync = 0;              // No SYNC was detected (frametimer > USECGDO0)
unsigned short nogdo0 = 0;              // SYNC was detected but GDO0 failed to drop before frametime reached 200 usec  
unsigned int crc = 0;                   // Packet received, but CRC failed
unsigned short wrongchan = 0;           // Packet was received on the wrong channel (frequency hopping algorithm)
unsigned int packeterrors = 0;          // Packet Errors
unsigned int lostpackets = 0;           // Lost Packets

unsigned short beaconchan;

const unsigned int tone444Hz[] = {
    512, 670, 808, 911, 966, 966, 911, 808, 670,
    512, 354, 216, 113, 58, 58, 113, 216, 354,
    512, 670, 808, 911, 966, 966, 911, 808, 670,
    512, 354, 216, 113, 58, 58, 113, 216, 354};

#endif
 
void main (void)
{
  WDTCTL = WDTPW + WDTHOLD;         // Stop WDT
    
  // Clock Configuration 
  
  BCSCTL1 = XT2OFF | XTS | DIVA_1 | RSEL2;                  
                                    // Leave XT2 Oscillator disabled; Set LFXT1 to High Frequency mode
                                    // Set ACLK divider to 2 (8.192 MHz)
                                    // Leave RSEL set to defualt value of 4
  BCSCTL3 = LFXT1S1;                // Select 3 - 16 MHz crystal range
  
  do
  {
    IFG1 &= ~OFIFG;                 // Clear OSCFault flag
    for (i = 0xFF; i > 0; i--);     // Time for flag to set
  }
  while (IFG1 & OFIFG);             // OSCFault flag still set?
  
#ifdef MONITOR

  BCSCTL2 = SELM_3 | DIVM_0 | SELS | DIVS_1;	// MCLK Source: LFXT1CLK (16.384 MHz); MCLK Divider: /1 (16.384 MHz)
                                                // SMCLK Source: LFXT1CLK (16.384 MHz); SMCLK Divider: /2 (8.192 MHz)
  
#else  
  
  BCSCTL2 = SELM_3 | DIVM_0 | SELS;   // MCLK Source: LFXT1CLK (16.384 MHz); MCLK Divider: /1 (16.384 MHz)
                                      // SMCLK Source: LFXT1CLK (16.384 MHz); SMCLK Divider: /1 (16.384 MHz)

#endif
   
  MSPInit();                          // Initilze the MSP I/O, ADC, Timers, and USART 
  lcdbufrbusy = 0;
  
// begin main program  
  
  __bis_SR_register(GIE);             // Enable interrupts
  
  TI_CC_SPISetup();                   // Initialize SPI port
  TI_CC_SPIStrobe(TI_CCxxx0_SRES);    // Send SRES Command Strobe
  writeRFSettings();                  // Write RF settings to configuration registers
  TI_CC_SPIWriteBurstReg(TI_CCxxx0_PATABLE, paTable, paTableLen);   // Write PATABLE
  
#ifdef MONITOR  
   
// Debug

  strcpy(lcdtxt, "L1TX  Single TX");
  writeLCD();
  
  P3OUT |= 0xC0;                      // Set VGA Gain to Maximum (P3.6 and P3.7 High)                  
  
  txBuffer[0] = PACKETLEN;            // Packet length
  txBuffer[1] = 0x01;                 // Packet address - MUST be set to 1 !!!
  
#ifdef CONTINOUS  
  
//  The following 3 lines place the CC1150 in continous transmit mode  
  
  TI_CC_SPIWriteReg(TI_CCxxx0_CHANNR, 0);           // Set Channel register to 0 (base frequency)
  TI_CC_SPIWriteReg(TI_CCxxx0_PKTCTRL0, 0x02);      // Set Packet Length to infinite
  TI_CC_SPIWriteReg(TI_CCxxx0_MDMCFG2, 0x02);       // Set Modulation to FSK
  TI_CC_SPIStrobe(TI_CCxxx0_STX);                   // Turn On TX
  
#else
  
  while (1) {   
    if (sendpacket > 0) {
      txBuffer[2] = locate | (hopping_channels[chan_index] << 1);    
      if (chan_index == 0)
        P4OUT |= 0x80;                      // Set P4_7 (JP102 pin 9)
      else
        P4OUT &= ~0x80;                     // Reset P4_7 (JP102 pin 9)
      TI_CC_SPIWriteReg(TI_CCxxx0_CHANNR, hopping_channels[chan_index++]);
      if (chan_index == TOTAL_NUM_CHANNELS)
        chan_index = 0;
      for (i = 0; i < ADCTXBUFRLEN; i++) {  
        if (activebufr == 0)
          txBuffer[i+3] = adctxbuf[1][i];   // ADC buffer 0 is active; send data in ADC buffer 1
        else
          txBuffer[i+3] = adctxbuf[0][i];   // ADC buffer 1 is active; send data in ADC buffer 0
      }
      
#ifdef OMITPACKET

      if (packetnumber == HOWOFTEN) {
        P4OUT |= 0x20;        // Set P4_5 (JP102 pin 1, TX card)
        packetnumber = 0;
        while (1) {                                           
          macstate = TI_CC_SPIReadStatus(0x35);       // read the CC1100 'Machine State'
          if (macstate == 0x01)                       // wait for calibration to complete (machine state = IDLE) 
            break;
        }
        sendpacket = 0;
        continue;             // break out of 'sendpacket > 0' if
      }
      else {
        P4OUT &= ~0x20;       // Reset P4_5 (JP102 pin 1, TX card)
        packetnumber++;
      }
        
#endif
      
      P4OUT |= 0x40;                                // Set P4_6 (JP102 pin 10, TX card)
      RFSendPacket(txBuffer, ADCTXBUFRLEN + 3);     // Send Packet
      P2IFG &= ~TI_CC_GDO0_PIN;                     // After pkt TX, this flag is set. Clear it.
      P4OUT &= ~0x40;                               // Reset P4_6 (JP102 pin 10, TX card) 
   
      sendpacket = 0;
    } 
  }

#endif    // end of CONTINOUS if  

#else     // card is configured as a RECEIVER
   
  strcpy(lcdtxt, "L1RX  Single TX");
  writeLCD();
     
// Enable receiver interrupts (from original code)   
     
  TI_CC_GDO0_PxIES |= TI_CC_GDO0_PIN;       // Int on falling edge (end of pkt)
  TI_CC_GDO0_PxIFG &= ~TI_CC_GDO0_PIN;      // Clear flag
  TI_CC_GDO0_PxIE |= TI_CC_GDO0_PIN;        // Enable int on end of packet
  
  rssiavg = 0;

  _BIS_SR(GIE);                             // Enable interrupts
   
  while (1) {
    smstate = SMIDLE;
    
    if (tone == 0x03)  {
      for (i = 0; i < ADCSAMPLES; i++)
        pwmbufr[0][i] = pwmbufr[1][i] = tone444Hz[i];
      
      tone &= 0x05;               // clear the 'load tone' bit
    }
    
    if (tone == 0x7) {
      for (i = 0; i < ADCSAMPLES; i++) 
        pwmbufr[0][i] = pwmbufr[1][i] = 512;
     
      tone &= 0x05;               // clear the 'load tone' bit   
    }
    
    if (waitingforbeacon == 1) {
      TI_CC_SPIStrobe(TI_CCxxx0_SIDLE);                   // Force the CC1100 into the idle state

// Tune to the first entry in the Hopping_Channels table

      TI_CC_SPIWriteReg(TI_CCxxx0_CHANNR, hopping_channels[0]);             
      TI_CC_SPIWriteReg(TI_CCxxx0_MCSM0 ,  0x18);         // Automatic Calibrate - IDLE to RX or TX
      chan_index = 1;                                     // The next channel will be hopping_channels[1]
          
      while (1) {                                         
        if (attenuation == 0)
          TI_CC_SPIWriteReg(TI_CCxxx0_FIFOTHR, 0x07);     // remove RX attenuator
        else
          TI_CC_SPIWriteReg(TI_CCxxx0_FIFOTHR, 0x37);     // add 18 dB of RX attenuation
        attenuation ^= 0x01;
            
        timeractive = 0;                                  // Stop the timer
        smstate = SMRXON;                                 // change state to SMRXON
        rcvpacket = 0;                                    // clear the 'Received Packet' flag
        TI_CC_SPIStrobe(TI_CCxxx0_SRX);                   // Enter RX mode
        timertics = 0;                                    // Reset and start the timer
        timeractive = 1;
        P2OUT |= LED_YELLOW;                              // Light the Yellow LED
 
// Wait for a beacon signal

        while ((rcvpacket == 0) && (timertics < W4BEACON));   

        if (rcvpacket == 1)   
          break;
      }   // end of 'while (1)' loop

      P2OUT &= ~LED_YELLOW;                               // Extinguish the Yellow LED
      smstate = SMPKTRCVD;
      TI_CC_SPIWriteReg(TI_CCxxx0_MCSM0 ,   0x08);        // Manual Calibration
     
// Reset and start the frametimer (Timer B). This avoids a potential 'latch up' problem on POR    
      
      TBCTL &= ~0x0010;                                   // Stop Timer B
      TBCTL |= TBCLR;                                     // Reset TBR
      TBCTL |= 0x0010;                                    // Start Timer B
    }     // end of 'waiting for beacon' case
  
    else {                                                // NOT waiting for a becaon ...
      while (1) {                                           
        macstate = TI_CC_SPIReadStatus(0x35);             // read the CC1100 'Machine State'
        if (macstate == 0x01)                             // wait for calibration to complete (machine state = IDLE) 
          break; 
      }
       
      P1OUT &= ~0x20;         // Reset P1_5 (JP200 pin 5)
      
      while (1) {
        tbr = (unsigned int) TBR;                  
        if ((tbr > USEC750) && (tbr < USEC900))           // don't turn on the receiver until the 750 > frametimer > 900 usec
        break;
      }
    
      smstate = SMRXON;                                   // change state to SMRXON
      rcvpacket = 0;                                      // clear the 'Received Packet' flag
      TI_CC_SPIStrobe(TI_CCxxx0_SRX);                     // Enter RX mode
      P1OUT |= 0x40;                                      // Set P1_6 (JP200 pin 3)
     
      while (1) {
        tbr = (unsigned int) TBR;    
        if ((tbr > USECGDO0) || ((P2IN & 0x02) > 0))      // Wait until either a time out has occurred or SYNC word is detected
          break;
      }
       
      if ((P2IN & 0x02) == 0) {                           // if SYNC was not detected ...
        smstate = SMNOSYNC;                               // set the state
        nosync++;
      }
      else {                                              // SYNC detected 
        while (1) {                                       // loop until      
          if (rcvpacket == 1)                             // either a packet is received
            break;                                    
          tbr = (unsigned int) TBR;
          if ((tbr > USEC190) && (tbr < USEC210)) {        // or 190 usec < frametimer < 210 usec 
            P1OUT |= 0x20;     // Set P1_5 (JP200 pin 5)
            break;
          }
        }
        if (rcvpacket == 0) {                             // if a packet was not received ...
          smstate = SMNOPKT;                              // set the state to SMNOPKT
          nogdo0++;
        }
        else                                              // if a packet was received ...
          smstate = SMPKTRCVD;                            // set the state to SMPKTRCVD
       }     // end of 'SYNC Detected' case
    }       // end of 'waitingforbeacon == 0' case
    
// At this point, the RX state will be one of these three
//
//    SMNOSYNC - SYNC word was not detected within the timeout period (missed packet)
//    SMNOPKT - SYNC Word was detected but a packet was not received within the timeout period (lost packet)
//    SMPKTRCVD - A packet was received       
    
    TI_CC_SPIStrobe(TI_CCxxx0_SIDLE);                           // Force the CC1100 into the idle state

    if (chan_index == 0)
      P1OUT |= 0x10;                                            // Setet P1_4 (JP200 pin 7)
    else
      P1OUT &= ~0x10;                                           // Reset P1_4 (JP200 pin 7)
    
    TI_CC_SPIWriteReg(TI_CCxxx0_CHANNR, hopping_channels[chan_index++]);    // Write the CHANNR (Channel number) register
    if (chan_index == TOTAL_NUM_CHANNELS)
        chan_index = 0;
    TI_CC_SPIStrobe(TI_CCxxx0_SCAL);                            // Start PLL calibration

    if ((smstate == SMNOSYNC) || (smstate == SMNOPKT)) {           
      P1OUT |= 0x80;                    // Set P1_7 (JP200 pin 1), to indicate a timeout error/lost packet
      P4OUT |= LED_ORANGE;              // Turn on the Orange LED (Packet Lost)
    
      if (lostpackets < 1000)            // 'lostpackets' is total number of lost packets since RESET (max value is 999)         
        lostpackets++;                  
      
      TI_CC_SPIStrobe(TI_CCxxx0_SFRX);  // Flush the RX FIFO
        
      if (rxactbufr == 0)               // Mark buffer A unavailable
        P4OUT &= ~0x40;
      else
        P4OUT &= ~0x80;                 // Mark buffer B unavailable
     
      if (pktslost < MAX_LOST_PACKETS) {
        pktslost++;                     // Increment the 'conscutive packets lost' counter
        pecount++;                      // include lost packets in 'PER' calculation
      }
      else  
        waitingforbeacon = 1;           // drop into the 'waiting for beacon' mode
    }     // end of timeout (SYNC not detected, packet not received)
    
    else {                                      // smstate = PKTRCVD (a packet was received)
      pktstatus = TI_CC_SPIReadStatus(0x38);    // Read the status register - bit 7 contains CRC status
      if ((pktstatus & 0x80) > 0) {             // if CRC is O.K., reset the Frame Counter (Timer B)
        TBCTL &= ~0x0010;                       // Stop Timer B
        TBCTL |= TBCLR;                         // Reset TBR
        TBCTL |= 0x0010;                        // Start Timer B
      }
      else {
        if (crc < 1000)
          crc++;                                // Packet was received O.K, but a CRC Error occurred
        pecount++;                              // include CRC errors in 'PER' calculation
      }
    
      char len = PACKETLEN;                           // Len of pkt to be RXed (only addr plus data)
      pktstatus = RFReceivePacket(rxBuffer, &len);    // Fetch packet from CC1100
      
#ifdef IGNORECRC
      if ((pktstatus & 0x03) == 0) {        // CRC errors will be ignored
#else      
      if (pktstatus == 0x80) {              // 0x80 indicates that packet was recieved with no errors
#endif
     
        P4OUT &= ~LED_ORANGE;               // Turn off the Orange LED (Packet Error)
        P1OUT &= ~0x80;                     // Reset P1_7 (JP200 pin 1)
       
// unpack TX data (8 bit to 10 bit conversion)         

        locate = rxBuffer[1] & 0x01;
        if (locate > 0) {
          if (tone == 0)                    // enable the locate alarm
            tone = 0x03;
          P4OUT |= 0xC0;                    // mark both buffers as available
          rcvpacket = 0;
          waitingforbeacon = 0;             // signal PWM to begin
          continue;                         // skip to the end of the 'while' loop
        }
        else {
          tone = 0;                         // disable the alarm
          P4OUT &= ~0x1F;                   // Turn off the LED Bar
        }
       
        pwmbufrptr = 0;

        if (rxactbufr == 0)       // Buffer A unavailable
          P4OUT &= ~0x40;
        else
          P4OUT &= ~0x80;         // Buffer B unavailable
        
        adcmax = 0;
        for (rx = 2; rx < PACKETLEN; rx += 5) {     
          pwm = 0;
          pwm = rxBuffer[rx] | ((rxBuffer[rx+1] & 0x03) << 8);
          pwmbufr[rxactbufr][pwmbufrptr] = pwm;           // A9...A0

          if (pwm > adcmax)        
            adcmax = pwm;
          
          pwm = 0;
          pwm = (rxBuffer[rx+1] & 0xFC) >> 2;
          pwm |= (rxBuffer[rx+2] & 0x0F) << 6;
          pwmbufr[rxactbufr][pwmbufrptr+1]= pwm;          // B9...B0
          pwm = 0;
          pwm = (rxBuffer[rx+2] & 0xF0) >> 4;
          pwm |= (rxBuffer[rx+3] & 0x3F) << 4;
          pwmbufr[rxactbufr][pwmbufrptr+2]= pwm;          // C9...C0
          pwm = 0;
          pwm = (rxBuffer[rx+3] & 0xC0) >> 6;
          pwm |= rxBuffer[rx+4] << 2;
          pwmbufr[rxactbufr][pwmbufrptr+3]= pwm;          // D9...D0
          pwmbufrptr += 4;
        }
 
        if (adcmax > pktmax)
          pktmax = adcmax;
        
        pktsamples++;
        if (pktsamples == SAMPLEPKTS)  {
          P4OUT &= 0xE0;
          if (pktmax > 600)
            P4OUT |= 0x01;
          if (pktmax > 675)
            P4OUT |= 0x02;
          if (pktmax > 750)
            P4OUT |= 0x04;
          if (pktmax > 825)
            P4OUT |= 0x08;
          if (pktmax > 900)
            P4OUT |= 0x10;
          pktsamples = 0;
          pktmax = 0;
        }

        pktslost = 0;           // Reset the 'consecutive packets lost' counter
 
        if (rxactbufr == 0)      
          P4OUT |= 0x40;          // Buffer A available
        else 
          P4OUT |= 0x80;          // Buffer B available
               
        if (packets == 32) {
          rssiavg = rssiavg >> 6;             // calculate the average rssi value over the last 32 packets, divided by 2
          lqiavg = lqisum >> 5;               // calculate the average LQI value over the last 32 packets
          if ((rssiavg & 0x40) > 0)
            rssiavg |= 0xFF80;                // do a sign extend (if required)
          rssidbm = rssiavg - 74;
          rssiavg = 0;
          lqisum = 0;
          packets = 0;
   
          if (rssidbm > -28)
            TI_CC_SPIWriteReg(TI_CCxxx0_FIFOTHR, 0x37);       // decrease gain by 18 dB
          if (rssidbm < -60)
            TI_CC_SPIWriteReg(TI_CCxxx0_FIFOTHR, 0x07);       // increase gain by 18 dB
        }
        else  {
          rssiavg += rssi;
          lqisum += lqi & 0x7F;
          packets++;
        }
  
        pcktsper++;
        if (pcktsper == 1024) {
          pe1024 = pecount;
          pecount = 0;
          pcktsper = 0;
        }
        
        if (waitingforbeacon == 1) {      
          beaconchan = (rxBuffer[1] >> 1);
          if (beaconchan != hopping_channels[0])    // Was the packet received on hopping_channels[0]?
            wrongchan++;                            // if not, tabulate the occurance
          else    
            waitingforbeacon = 0;                   // if so, exit 'waiting for beacon' mode           
        }   // end of 'waiting for packet' code 
      }     // end of 'Packet Received OK' code 
      else  {                     // Packet Error (Packet was received, but with a non valid length or Address error)
        pecount++;                // include length and addreess errors in 'PER' calculation
        if (packeterrors < 1000)  // LCD display valid for integers < 1000 only 
          packeterrors++;                
      
        if (rxactbufr == 0)       // Buffer A unavailable
          P4OUT &= ~0x40;
        else
          P4OUT &= ~0x80;         // Buffer B unavailable
      }   // end of 'else' (Packet Error) code 
    }     // end of 'packet received' code
        
    rxactbufr ^= 0x01;                // in any event, switch RX buffers
  }   // end of 'while (1)' loop
#endif
}



