/*******************************************************************************************************
 *                                                                                                     *
 *        **********                                                                                   *
 *       ************                                                                                  *
 *      ***        ***                                                                                 *
 *      ***   +++   ***                                                                                *
 *      ***   + +   ***     This example shows how to use the Wake-on-Radio function of the CC2500     *
 *      ***   +             in a simple "packet burst with ACK" protocol.                              *
 *      ***   + +   ***                                                                                *
 *      ***   +++   ***     WorWithAck.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>
#include <RegSettings_Wor.h>




//-------------------------------------------------------------------------------------------------------
// DESCRIPTION:
//      This example is an improved implementation of the simple WOR example described in App. Note 38.
//      A transmitting remote control is sending packets with control commands to the remotely 
//      controlled receiving object. WOR is used to reduce power consumption at the receiver side.
//      The remote control EB starts bursting identical packets until it gets an ACK back from receiver.
//      This means that there, in contrast to the simple WOR example, is no fixed number of packets 
//      in a burst. 
//      One evaluation board (EB) is set up as the remote control (TX unit), and the other as 
//      the remotely controlled object (RX/WOR unit). Data regarding movements of the joystick on 
//      the remote control are transmitted to the receiver and displayed on the LCD of this EB. 
//      Please see App. Note 38 for more details.
//      
//      RX UNIT:
//          * Move joystick right to choose RX
//          * Push the S1 button to confirm your choice. 
//          After the unit has been configured, the yellow LED will be on.
//
//          GLED: Toggles when a packet has been received successfully.
//          RLED: Toggles when an invalid packet has been received. 
//          BLED: Toggles when an ACK is sent.
//
//      TX UNIT:
//          * Move joystick left to choose TX
//          * Push the S1 button to confirm your choice. 
//          After the unit has been configured, the yellow LED will turn on.
//
//          BLED: Toggles when a packet has been sent.
//          GLED: Toggles every time a valid packet (ACK) has been received.
//          RLED: Toggles every time an invalid packet has been received.
//
//      If the TX unit is selected, you are now able to push the joystick button or move it up, 
//      down, left or right. This will start the packet burst and the number of packets sent in the 
//      burst will be displayed on the LCD. The number of packets in a burst is variable, depending on
//      when an ACK is received. Normally, less than 305 packets need to be sent.One should not move 
//      the joystick to a new position before the previous burst transmission has completed. 
//
//
//      If the RX unit is selected, it will automatically enter the WOR mode, waiting for packets. 
//
//      The LCD will continuously display how many valid packets have been received together with 
//      the position of the joystick on the remote control.
//      
//      The program can be terminated by pressing the S1 button after the setup has been done. 
//      This will turn off the yellow LED.
//
//      Current config specs
//
//          Common Settings:
//              Packet format = 4B preamble + 4B sync word + 1B payload + 2B CRC = 11 Bytes
//
//          TX Unit Settings:
//              Packet interval:        1.0 ms
//              Packet send time:       ~ 11 B * 8 bit/B / 250 kbps = 352 us
//              Tx duty cycle:          ~ 352 us / 1.0 ms = 35.2 %
//              RX timeout (get ACK):   325 us                      (word sync search timeout)
//              RX duty cycle:          325 us / 1000 us = 32.5 %
//
//          RX/WOR Unit Settings:
//              Event0 timeout:         300 ms                      (radio RX polling period)
//              Event1 timeout:         ~ 1.4 ms (f_xosc = 26 MHz)  (time between wake-up from SLEEP and 
//                                                                   start RX)
//              Rx timeout:             ~ 1.172 ms
//              Rx duty cycle:          ~ 1.172 ms / 300 ms = 0.391 %
//              ACK send time:          ~ 11B * 8 bit/B / 250 kbps = 352 us
//              TX duty cycle (max):    352 us / 300 ms = 0.117 %
//-------------------------------------------------------------------------------------------------------




//-------------------------------------------------------------------------------------------------------
// Defines

// Defines used as mode values for the setup menu
#define MODE_NOT_SET    0
#define MODE_TX         1
#define MODE_RX         2
//-------------------------------------------------------------------------------------------------------




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

RF_SETTINGS code rfSettings;

extern BYTE code paTable;

UINT8 xdata mode = MODE_NOT_SET;        // Variable used to hold the mode for the setup menu

// Defining some external variables
UINT8 xdata joystickPosition = JOYSTICK_CENTER;
UINT8 xdata prevJoystickPosition = JOYSTICK_CENTER;
BYTE xdata rxBuffer[1];                 // Max received packet length = 1B
BYTE xdata asciiString[11];             // Byte array used by the intToAscii(UINT32 value) function
//-------------------------------------------------------------------------------------------------------




//-------------------------------------------------------------------------------------------------------
//  void main(void)
//
//  DESCRIPTION:
//      This function takes care of all the MCU initialization and radio configuration. 
//-------------------------------------------------------------------------------------------------------
void main (void) {
   #ifdef STAND_ALONE

        // Select the Internal Oscillator as Multiplier input source and disable the watchdog timer
        // SYSCLK = 4X Clock Multiplier / 2
        CLOCK_INIT();
    #endif

    // Set up the crossbar and I/O ports to communicate with the SmartRF04EB peripherals
    IO_PORT_INIT();

    // Initialize the LCD display. The SMBus uses timer 0 to generate SCL
    ebLcdInit();

    // Initialize the ADC converter
    ebAdcInit(ADC_JOY);

    SPI_INIT(SCLK_6_MHZ);

    // Reset CC2500 and write RF settings to config registers
    POWER_UP_RESET_CCxxx0();
    
    halRfWriteRfSettings(&rfSettings);
    
    halSpiWriteReg(CCxxx0_PATABLE, paTable);

    // Write custom sync word (avoiding default sync word)
    halSpiWriteReg(CCxxx0_SYNC1, 0x9B);
    halSpiWriteReg(CCxxx0_SYNC0, 0xAD);

    halSpiWriteReg(CCxxx0_IOCFG1, 0x25);



    // Calibrating frequency synthesizer (FS) at startup
    halSpiStrobe(CCxxx0_SCAL);

    // Starts menu for setting up EB unit to either "TX" or "RX/WOR" unit.
    showMenu();

    // Remote control
    if (mode == TX) {                                                                           
        ebLcdUpdate("Tx unit...", "(Move joystick)");
        runTransmitter();

    // Remote-controlled object
    } else {                                                                                            
        ebLcdUpdate("Rx/WOR unit...", NULL);
        runReceiver();
    }    
}





//-------------------------------------------------------------------------------------------------------
//  void showMenu(void) 
//
//  DESCRIPTION:
//      Function to show menu. Select mode by moving joystick left/right. 
//      Press S1 button to confirm the choice.
//-------------------------------------------------------------------------------------------------------
void showMenu(void) {
    mode = MODE_NOT_SET;
    ebLcdUpdate("WorWithAck.c", "<-  Set Mode  ->");
    
    // Select Tx or Rx mode by moving the joystick left or right
    do {
        halWait(250);
        
        // Get current position of joystick
        joystickPosition = ebGetJoystickPosition();

        if (prevJoystickPosition != joystickPosition) {
            prevJoystickPosition = joystickPosition;
            parseMenu(joystickPosition);
        }
    } while (!ebButtonPushed() || (mode == MODE_NOT_SET));
}// showMenu




//-------------------------------------------------------------------------------------------------------
//  void parseMenu(UINT8 joystickPosition) 
//
//  DESCRIPTION: 
//      This function selects mode and updates the LCD display based on the joystick position
//
//  ARGUMENTS:
//      UINT8 joystickPosition
//          The position of the joystick
//-------------------------------------------------------------------------------------------------------
void parseMenu(UINT8 joystickPosition) {

    switch (joystickPosition) {

        case JOYSTICK_LEFT:
            if (mode == RX || mode == MODE_NOT_SET) {
                mode = MODE_TX;
                ebLcdUpdate("Mode:", "Tx/Burst");
            }
            break;

        case JOYSTICK_RIGHT:
            if (mode == TX || mode == MODE_NOT_SET) {
                mode = MODE_RX;
                ebLcdUpdate("Mode:", "Rx/Wake-on-Radio");
            }
            break;

        default:    // Other joystick movements: do nothing
            break;
    }
}// parseMenu




//-------------------------------------------------------------------------------------------------------
//  void intToAscii(UINT32 value)
//
// DESCRIPTION:
//      Takes a 32 bits integer as input and converts it to ascii. Puts the result in the global
//      variable asciiString[]
//
//  ARGUMENTS:
//      UINT32 value
//          The value to be converted
//-------------------------------------------------------------------------------------------------------
void intToAscii(UINT32 value) {
    UINT8 i = 10;
    UINT8 j = 0;
    UINT8 digit_start = 0;
    UINT16 digit = 0;
    UINT32 denom = 1000000000;

    if (value == 0) {
        asciiString[0] = '0';
        asciiString[1] = NULL;
    } else {
        for(i = 10; i > 0; i--) {
            digit = value / denom;
            if((digit_start == 1) || (digit != 0)) {
                digit_start = 1;
                value %= denom;
                asciiString[j++] = (digit + '0');
            }
            denom /= 10;
        }
        asciiString[j++] = NULL;
    }
}// intToAscii




/******************************************************************************************************
 * Revision history:                                                                                  *
 *
 * $Log: WorWithAck.c,v $
 * Revision 1.2  2005/10/25 12:23:40  sna
 * Register settings moved to separate *.h file
 *
 * Revision 1.1  2005/10/06 12:14:27  sna
 * Initial version in CVS.
 *
 *
 *
 ******************************************************************************************************/






