/*********************************************
*
* draft version v 0.1, experimental
*
* code based on the code of "benedikt k."
* this was an avr project from the site: http://www.mikrocontroller.net/topic/65984#541030
*
*
* code should be matched with RF01
*
* up to now no transmission between the RF12 modules and Jeelabs.com RF12 lib
*
* this code has worked: transmitting using atmega168 and atmega328 in combination with RF01s and RF02s
*
* arduino 18
*
* five march, contrechoc.com, june 2010 , october 2010
*
*
*********************************************/

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
#include <stdlib.h>

#include "rf01.h"

#define F_CPU 16000000UL
#include <util/delay.h>

#define RF_PORT PORTB
#define RF_DDR  DDRB
#define RF_PIN  PINB

#define SDI             5       // RF01  SDI,  arduino  13 cannot be changed
#define SCK             4       // RF01  SCK,  arduino  12 cannot be changed
#define CS              3       // RF01  nSEL, arduino  11 cannot be changed
#define SDO             2       // RF01  SDO,  arduino  10 cannot be changed
//----------------- // RF01  niRQ, arduino  02 cannot be changed
//------------------// RF01  nFFS: 1-10k Pullup too Vcc

#define LED_PORT        PORTD
#define LED_DDR         DDRD
#define LED_PIN         PIND

#define LED0    5
#define LED1    6 //not used

// nFFS: 1-10k Pullup an Vcc !!!

#ifndef cbi
#define cbi(sfr, bit)     (_SFR_BYTE(sfr) &= ~_BV(bit)) 
#endif
#ifndef sbi
#define sbi(sfr, bit)     (_SFR_BYTE(sfr) |= _BV(bit))  
#endif

#ifndef cLED0
#define cLED0()     (LED_PORT &= ~(1<<LED0)) 
#endif
#ifndef sLED0
#define sLED0()     (LED_PORT |= (1<<LED0) )  
#endif

#ifndef cLED1
#define cLED1()     (LED_PORT &= ~(1<<LED1)) 
#endif
#ifndef sLED1
#define sLED1()     (LED_PORT |= (1<<LED1) )  
#endif

// maximum receive buffer
#define RF_MAX   32
unsigned char  rf01_buf[RF_MAX];  // recv buf

#include <util/delay.h>

void rf01_receive(){
        rf01_rxdata(rf01_data, 32);
}

void rf01_prepAll(){
        rf01_init();                                    // ein paar Register setzen (z.B. CLK auf 10MHz)
        rf01_setfreq(RF01FREQ(434));    // Sende/Empfangsfrequenz auf 433,92MHz einstellen
        rf01_setbandwidth(4);                   // 4 200kHz Bandbreite
        rf01_setreceiver(2,4);                  //2,4 -6dB Verstärkung, DRSSI threshold: -79dBm 
        rf01_setbaud(57600);                    // 19200 Baud

}

static unsigned char sdrssi, sgain;

void rf01_trans(unsigned short wert)
{       unsigned char i;

        cbi(RF_PORT, CS);
        for (i=0; i<16; i++)
        {       if (wert&32768)
                        sbi(RF_PORT, SDI);
                else
                        cbi(RF_PORT, SDI);
                sbi(RF_PORT, SCK);
                wert<<=1;
                _delay_us(0.2);
                cbi(RF_PORT, SCK);
        }
        sbi(RF_PORT, CS);
}

void rf01_init(void)
{       unsigned char i;

        RF_PORT=(1<<CS);
        RF_DDR=(1<<SDI)|(1<<SCK)|(1<<CS);

        for (i=0; i<11; i++)
                _delay_ms(10);                  // wait until POR done

        rf01_trans(0xC2E0);                     // AVR CLK: 10MHz
        rf01_trans(0xC42B);                     // Data Filter: internal
        rf01_trans(0xCE88);                     // FIFO mode
        rf01_trans(0xC6F7);                     // AFC settings: autotuning: -10kHz...+7,5kHz
        rf01_trans(0xE000);                     // disable wakeuptimer
        rf01_trans(0xCC00);                     // disable low duty cycle

        LED_DDR= 0xFF;//(1<<LED0)|(1<<LED1);
        blinkLED();

}

void rf01_setbandwidth(unsigned char bandwidth)
{
        rf01_trans(0x8970|((bandwidth&7)<<1));
}

void rf01_setreceiver(unsigned char gain, unsigned char drssi)
{
        sdrssi=drssi;
        sgain=gain;
}

void rf01_setfreq(unsigned short freq)
{       if (freq<96)                            // 430,2400MHz
                freq=96;
        else if (freq>3903)                     // 439,7575MHz
                freq=3903;
        rf01_trans(0xA000|freq);
}

void rf01_setbaud(unsigned short baud)
{
        if (baud<336)
                return;
        if (baud<5400)                          // Baudrate= 344827,58621/(R+1)/(1+CS*7)
                rf01_trans(0xC880|((43104/baud)-1));
        else
                rf01_trans(0xC800|((344828UL/baud)-1));

        rf01_trans(0xC806);
}

void rf01_rxdata(unsigned char *data, unsigned char number)
{       unsigned char i,j,c;

        rf01_trans(0xC0C1|((sgain&3)<<4)|((sdrssi&7)<<1));      // RX on
        rf01_trans(0xCE89);                     // set FIFO mode
        rf01_trans(0xCE8B);                     // enable FIFO
        cbi(RF_PORT, SDI);
        for (i=0; i<number; i++)
        {       cbi(RF_PORT, CS);
                while (!(RF_PIN&(1<<SDO))); // wait until data in FIFO
                for (j=0; j<16; j++)    // read and discard status register
                {       sbi(RF_PORT, SCK);
                        asm("nop");
                        cbi(RF_PORT, SCK);
                }
                c=0;
                for (j=0; j<8; j++)
                {       c<<=1;
                        if (RF_PIN&(1<<SDO))
                                c|=1;
                        sbi(RF_PORT, SCK);
                        _delay_us(0.2);
                        cbi(RF_PORT, SCK);
                }
                *data++=c;
                sbi(RF_PORT, CS);
        }
        //blinkLED();
        rf01_trans(0xC0C0|((sgain&3)<<4)|((sdrssi&7)<<1));      // RX off
}

void blinkLED(void){
        for (unsigned char i=0; i<15; i++)
                _delay_ms(5);
        sLED1();

        for (unsigned char i=0; i<15; i++)
                _delay_ms(5);
        cLED1();

}

void makePulse(int numberOfPulses){
        if ( numberOfPulses > 0)
        {
        for (unsigned char i=0; i<numberOfPulses; i++)
                {
                        _delay_ms(20);
                        sLED0();
                        _delay_ms(20);
                        cLED0();                        
                }
                _delay_ms(50);
                }

}