/*******************************************************************************************************
 *                                                                                                     *
 *        **********                                                                                   *
 *       ************                                                                                  *
 *      ***        ***                                                                                 *
 *      ***   +++   ***     This file contains all functions related to the receiving (WOR) unit       *
 *      ***   + +   ***                                                                                *
 *      ***   +                                                                                        *
 *      ***   + +   ***                                                                                *
 *      ***   +++   ***     RxWorWithAck.c                                                             *
 *      ***        ***                                                                                 *
 *       ************                                                                                  *
 *        **********                                                                                   *
 *                                                                                                     *
 *******************************************************************************************************
 * Compiler:                Keil C51 V7.50                                                             *
 * Target platform:         Chipcon CCxxx0 (Silabs F320)                                               *
 * Author:                  ESY                                                                        *
 *******************************************************************************************************
 * Revision history:     See end of file                                                               *
 *******************************************************************************************************/
#include <Chipcon\srf04\regssrf04.h>
#include <Chipcon\srf04\halsrf04.h>
#include <Chipcon\srf04\ebsrf04.h>
#include <WorWithAck.h>




//-------------------------------------------------------------------------------------------------------
// Defines
#define RX_BYTES    0x7F
//-------------------------------------------------------------------------------------------------------




//-------------------------------------------------------------------------------------------------------
// Global Variables

// Variables to control the incoming packets and outgoing ACKs
UINT32 xdata packetsReceived = 0;
UINT8 xdata sendAck = FALSE;

// Byte/char arrays for LCD presentation of data
BYTE xdata asciiJoystickPosition[] = "Joystick:  ";
BYTE xdata asciiPackets[] = "Pkts rcvd:      ";

UINT8 xdata updateLcd = FALSE;
//-------------------------------------------------------------------------------------------------------




//-------------------------------------------------------------------------------------------------------
// Function declarations
void initReceiver();
//-------------------------------------------------------------------------------------------------------




//-------------------------------------------------------------------------------------------------------
//  void runReceiver(void)
//
//  DESCRIPTION:
//      This function is used to put the radio in SLEEP mode using WOR. If the MCU detects that a packet
//      is received, this function will send an ACK and then update the LCD display in accordance with 
//      the packet data received.
//-------------------------------------------------------------------------------------------------------
void runReceiver(void) {
    UINT8 i;

    // Initialize receiver
    initReceiver();

    SET_YLED(LED_ON);                       // Turn on yellow LED to indicate unit is running

    // Put the radio to SLEEP by starting Wake-on-Radio.
    halSpiStrobe(CCxxx0_SWORRST);           // Resets the real time clock
    halSpiStrobe(CCxxx0_SWOR);              // Starts Wake-on-Radio

    // The MCU could here enter some power-down state to reduce power consumption while waiting for a 
    // WOR interrupt from the CC2500 radio. (this is not implemented here in this example 
    // - instead there is a while loop updating the LCD.)

    // Loops forever updating LCD with the received data. Button S1 for abortion.
    while(!ebButtonPushed()) {
        if (updateLcd) { // This flag is set in EXTERNAL1_ISR if the LCD needs to be updated 
            updateLcd = FALSE;
            intToAscii(packetsReceived);

            // Copying chars for better LCD presentation
            for (i = 0; asciiString[i] >= '0' && asciiString[i] <= '9'; i++)
                asciiPackets[11 + i] = asciiString[i];
            asciiPackets[11 + i] = NULL;
            ebLcdUpdate(asciiPackets, asciiJoystickPosition);
        }
    }

    //Button S1 has been pressed for abortion
    INT_ENABLE(INUM_EXTERNAL1, INT_OFF);    // Disable external1 interrupts
    SET_YLED(LED_OFF);                      // Turn off yellow LED to indicate unit has stopped.
}// runReceiver




//-------------------------------------------------------------------------------------------------------
//  void initReceiver(void)
//
//  DESCRIPTION:
//      This function is configuring some specific radio register settings and initiating 
//      interrupt for the receiver/WOR unit.
//-------------------------------------------------------------------------------------------------------
void initReceiver(void) {

    // Configuring all the WOR related settings
    // Enable automatic initial calibration of RCosc.
    // Set T_event1 ~ 1.4 ms, enough for XOSC stabilize and FS calibration before RX.
    // Enable RC oscillator before starting with WOR (or else it will not wake up).
    halSpiWriteReg(CCxxx0_WORCTRL, 0x78);           // Not using AUTO_SYNC function.

    // Set Event0 timeout = 300 ms (RX polling interval)
    // WOR_RES = 0
    // T_event0 = 750 / f_xosc * EVENT0 * 2^(5*WOR_RES) = 300 ms   // Assuming f_xosc = 26 MHz
    // =>  EVENT0 = 10400 = 0x28A0
    halSpiWriteReg(CCxxx0_WOREVT1, 0x28);                           // High byte Event0 timeout
    halSpiWriteReg(CCxxx0_WOREVT0, 0xA0);                           // Low byte Event0 timeout.

    // Setting Rx_timeout > 1.0 ms.
    // MCSM2.RX_TIME = 101b
    // => Rx_timeout = T_event0 / (2^(8+WOR_RES)) = 300 ms / 256 = 1.17 ms, i.e. 0.391% RX duty cycle
    halSpiWriteReg(CCxxx0_MCSM2, 0x05);

    // Enable automatic FS calibration when going from IDLE to RX/TX/FSTXON (in between EVENT0 and EVENT1)
    halSpiWriteReg(CCxxx0_MCSM0, 0x18);

    // RXOFF_MODE=01b (RX->FSTXON: 9.6 us), TXOFF_MODE=00b (TX->IDLE, no FS calib: 0.1 us).
    halSpiWriteReg(CCxxx0_MCSM1, 0x04);

    // Enable external interrupt when packet is received
    // IOCFG2 register = 0x06 => GDO2 pin is asserted when sync word detected/sent, de-asserted at 
    // end of packet.
    // MCU is interrupted by radio on low edge of GDO2, i.e. whenever a packet is received.
    ENABLE_GLOBAL_INT(INT_OFF);
    SETUP_GDO2_INT(EDGE, LOW);                  // Enable external interrupt on low edge
    INT_SETFLAG(INUM_EXTERNAL1, INT_CLR);       // Clear the interrupt flag
    ENABLE_GLOBAL_INT(INT_ON);
}// initReceiver




//-------------------------------------------------------------------------------------------------------
//  void EXTERNAL1_ISR(void)
//
//  DESCRIPTION:
//      This interrupt service routine occurs whenever the radio detects a packet using Wake-on-Radio
//-------------------------------------------------------------------------------------------------------
void EXTERNAL1_ISR(void) interrupt INUM_EXTERNAL1 {
    UINT8 packetLength;

    // Packet detected!
    // Contents of TX FIFO and RX FIFO are cleared when entering SLEEP state (WOR),
    // so the RX FIFO does only contain the new packet.

    // Disable new interrupts
    INT_ENABLE(INUM_EXTERNAL1, INT_OFF);    
    
    // Radio should now be in FSTXON state (RXOFF_MODE).

    // Check if packet got CRC_AUTOFLUSHed or got filtered out because of wrong packet length.
    // (There is no address check implemented)
    packetLength = halSpiReadStatus(CCxxx0_RXBYTES) & RX_BYTES;

    if (packetLength != 0) { // Packet received ok.. Must reply with ACK.

        // Read out packet (should only be one byte with joystickposition)
        //halSpiReadBurstReg(CCxxx0_RXFIFO, rxBuffer, packetLength);
        rxBuffer[0] = halSpiReadReg(CCxxx0_RXFIFO);

        // Write ACK byte into TX FIFO and send ACK as quickly as possible
        // ACK byte is the received byte inverted
        halSpiWriteReg(CCxxx0_TXFIFO, (rxBuffer[0]^0xFF));  
        halSpiStrobe(CCxxx0_STX);

        while (!GDO2_PIN);
        while (GDO2_PIN);   // Wait for GDO2 to be de-asserted => end of transmitted packet

        // Put radio back to sleep/WOR (must be in IDLE when this is done)
        halSpiStrobe(CCxxx0_SWOR);

        // Parsing received data byte into correct char for proper LCD presentation
        joystickPosition = rxBuffer[0];

        switch(joystickPosition) {
            
            default: // Other received byte values are parsed as 'C' for ease
            
            case JOYSTICK_CENTER:
                asciiJoystickPosition[10] = 'C';
                break;
            
            case JOYSTICK_LEFT:
                asciiJoystickPosition[10] = 'L';
                break;
            
            case JOYSTICK_RIGHT:
                asciiJoystickPosition[10] = 'R';
                break;
            
            case JOYSTICK_UP:
                asciiJoystickPosition[10] = 'U';
                break;
            
            case JOYSTICK_DOWN:
                asciiJoystickPosition[10] = 'D';
                break;
            
            case JOYSTICK_PUSHED:
                asciiJoystickPosition[10] = 'P';
                break;
            }

        packetsReceived++;
        updateLcd = TRUE;
        P_LED1 = ~P_LED1;   // Toggle green LED for packet received.
        P_LED4 = ~P_LED4;   // Toggle blue LED for ACK sent.
    } else { // No packet received. No need for ACK.

        // Go back to sleep/WOR (have to go via IDLE, i.e.: FSTXON -> IDLE -> SLEEP)
        halSpiStrobe(CCxxx0_SIDLE);
        halSpiStrobe(CCxxx0_SWOR);

        P_LED2 = ~P_LED2;   // Toggle red LED for error.
    }

    INT_SETFLAG(INUM_EXTERNAL1, INT_CLR);   // Clear interrupt flag
    INT_ENABLE(INUM_EXTERNAL1, INT_ON);     // Re-enable new interrupts

    // The MCU could now enter some power-down state to reduce power consumption while waiting 
    // for the next WOR interrupt from the CC2500 radio (this is not implemented here).

}// EXTERNAL1_ISR




/******************************************************************************************************
 * Revision history:                                                                                  *
 *
 * $Log: RxWorWithAck.c,v $
 * Revision 1.1  2005/10/06 12:13:31  sna
 * Initial version in CVS.
 *
 *
 *
 ******************************************************************************************************/
