HOPE RF12 FSK Transceiver Library

/*==============================================================================
   rf12.h
 
   HOPE RF12 FSK Transceiver Library 
   Written by Ervin Jung (2010)
 
   Based on: HOPE RF, RF12B programming guide
--------------------------------------------------------------------------------
 
   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2, or (at your option) any
   later version.
 
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
 
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
   In other words, you are welcome to use, share and improve this program.
   You are forbidden to forbid anyone else to use, share and improve
   what you give them.   Help stamp out software-hoarding!
 
   As a special exception, if you link this library with other files,
   some of which are compiled with SDCC, to produce an executable,
   this library does not by itself cause the resulting executable
   to be covered by the GNU General Public License.
   This exception does not however invalidate any other reasons why
   the executable file might be covered by the GNU General Public License.
 
--------------------------------------------------------------------------------
 
  defaults:
 
  PIC                        RF12
  ----_------                 ----------
       RB7  + --------------> + SDI
       RB6  + <-------------- + SDO
       RB5  + --------------> + SCK
       RB4  + --------------> + nSEL
       RB3  + --------------> + Reset (To do (Optional))
  INT2/RB2  + <-------------- + nIRQ
  -----------                 ----------
 
 
--------------------------------------------------------------------------------
  #define RF12_BUFFER_SIZE 16
  #define RF12_TX_ENABLED
  #include <rf12.h>
 
  RF12_FRAME Frame; 
 
  // to write
  rf12_init_tx();
  Frame.Sender = 0x10;
  Frame.Dest   = 0x20;
  strcpy(Frame.Data, "Hello World!");
  rf12_tx_send(&Frame);
 
  // read
  #define RF12_BUFFER_SIZE 16
  #define RF12_RX_ENABLED
  #define MY_ID 0x20;
  rf12_init_rx();
 
  if(rf12_rx_read(&Frame) == RF12_CHECKSUM_OK) {
    if(Frame.Dest == MY_ID) {
      printf(Frame.Data);
    }      
  }
 
  //*** read by interrupt ***
  #define RF12_BUFFER_SIZE 16
  #define RF12_RX_ENABLED
  #define RF12_RX_INTERRUPT
  rf12_init_rx();
  while (1) {
    if(rf12_rx_data_status) {
      rf12_rx_led_on();
      printf("RawData: ");
      for(j=0; j < sizeof(RF12_PACKET); j++) 
        printf("%02X", RF12_PACKET.Raw[j]);
 
      if(rf12_rx_data_status == RF12_RX_DATA_CHK_OK)
         printf("\r\nCHK OK!");
         else printf("\r\nCHK FAILED!");
      printf("\r\n\r\n");
      rf12_rx_data_invalidate();
      rf12_rx_led_off();
    }
  }
 
--------------------------------------------------------------------------------
config for 18F2550 Internal 8Mhz, MCLR_OFF
 
void main(void) {
  OSCCON = 0x72;
  init();
  ..
}
 
#define FOSC 8000000
 
code char at __CONFIG1L config1l = 0xff & _PLLDIV_NO_DIVIDE__4MHZ_INPUT__1L & _CPUDIV__OSC1_OSC2_SRC___1__96MHZ_PLL_SRC___2__1L & _USBPLL_CLOCK_SRC_FROM_OSC1_OSC2_1L;
code char at __CONFIG1H config1h = 0xff & _OSC_INTOSC__USB_HS_1H & _FCMEN_ON_1H & _IESO_ON_1H;
code char at __CONFIG2L config2l = 0xff & _PUT_ON_2L & _BODEN_ON_2L & _BODENV_2_0V_2L & _VREGEN_ON_2L;
code char at __CONFIG2H config2h = 0xff & _WDT_DISABLED_CONTROLLED_2H & _WDTPS_1_32768_2H;
code char at __CONFIG3H config3h = 0xff & _CCP2MUX_RC1_3H & _PBADEN_PORTB_4_0__CONFIGURED_AS_DIGITAL_I_O_ON_RESET_3H & _LPT1OSC_ON_3H & _MCLRE_MCLR_OFF_RE3_ON_3H;
code char at __CONFIG4L config4l = 0xff & _STVR_OFF_4L & _LVP_OFF_4L & _ENICPORT_OFF_4L & _ENHCPU_OFF_4L & _BACKBUG_OFF_4L;
code char at __CONFIG5L config5l = 0xff & _CP_0_OFF_5L & _CP_1_OFF_5L & _CP_2_OFF_5L & _CP_3_OFF_5L;
code char at __CONFIG5H config5h = 0xff & _CPB_OFF_5H;
code char at __CONFIG6L config6l = 0xff & _WRT_0_OFF_6L & _WRT_1_OFF_6L & _WRT_2_OFF_6L & _WRT_3_OFF_6L;
code char at __CONFIG6H config6h = 0xff & _WRTB_OFF_6H & _WRTC_OFF_6H & _WRTD_OFF_6H;
code char at __CONFIG7L config7l = 0xff & _EBTR_0_OFF_7L & _EBTR_1_OFF_7L & _EBTR_2_OFF_7L & _EBTR_3_OFF_7L;
code char at __CONFIG7H config7h = 0xff & _EBTRB_OFF_7H;
 
#endif
 
 
==============================================================================*/
#ifndef __RF12_H__
#define __RF12_H__
 
//SDI
#define SDI_TRIS()  TRISBbits.TRISB7=0
#define SDI_PIN(x)  LATBbits.LATB7=x      
 
//SDO
#define SDO_TRIS()  TRISBbits.TRISB6=1
#define SDO_PIN()   PORTBbits.RB6
 
//SCK
#define SCK_TRIS()  TRISBbits.TRISB5=0 
#define SCK_PIN(x)  LATBbits.LATB5=x
 
//nSEL
#define nSEL_TRIS() TRISBbits.TRISB4=0
#define nSEL_PIN(x) LATBbits.LATB4=x
 
#define RESET_TRIS() TRISBbits.TRISB2=0
#define RESET_PIN(x) LATBbits.LATB3=x
 
//nIRQ
#ifdef RF12_RX_INTERRUPT
  #define nIRQ_TRIS() TRISBbits.TRISB2=1
  #define nIRQ_PIN()  PORTBbits.RB2
#else
  #define nIRQ_TRIS() TRISBbits.TRISB2=1
  #define nIRQ_PIN()  PORTBbits.RB2
#endif
 
 
//TX LED
#define rf12_tx_led_init() TRISAbits.TRISA0 = 0
#define rf12_tx_led_on()   LATAbits.LATA0 = 1
#define rf12_tx_led_off()  LATAbits.LATA0 = 0
 
//RX LED
#define rf12_rx_led_init() TRISAbits.TRISA0 = 0
#define rf12_rx_led_on()   LATAbits.LATA0 = 1
#define rf12_rx_led_off()  LATAbits.LATA0 = 0
 
//FAIL LED
#define rf12_fail_led_init() TRISAbits.TRISA1 = 0
#define rf12_fail_led_on()   LATAbits.LATA1 = 1
#define rf12_fail_led_off()  LATAbits.LATA1 = 0
 
// BUFFER SIZE
#ifndef RF12_BUFFER_SIZE
  #define RF12_BUFFER_SIZE 16
#endif
 
typedef union {
  struct {
    unsigned char Sender;   // Sender ID
    unsigned char Dest;     // Destination ID
    unsigned char Data[RF12_BUFFER_SIZE];
    unsigned int  Checksum;
  };
  struct {
    unsigned char Raw[RF12_BUFFER_SIZE + sizeof(char) * 2 + sizeof(int)];
  };
} RF12_FRAME;
 
#define RF12_RX_DATA_INVALID    0
#define RF12_RX_DATA_CHK_OK     1
#define RF12_RX_DATA_CHK_FAILED 2
 
RF12_FRAME RF12_PACKET;
unsigned char rf12_rx_data_index  = 0;
unsigned char rf12_rx_data_status = RF12_RX_DATA_INVALID;
unsigned int  rf12_rx_fail_count  = 0;
 
#define RF12_BROADCAST_ADDR  1
#define RF12_TIMEOUT         20000 
#define RF12_EXPIRED         0
 
#ifdef RF12_RX_INTERRUPT
  #include <signal.h>  
  #define rf12_rx_interrupt_enable()  INTCON3bits.INT2IE = 1
  #define rf12_rx_interrupt_disable() INTCON3bits.INT2IE = 0
#endif
 
static void rf12_write0(void){
   SCK_PIN(0);
   _asm 
     NOP
   _endasm;
   SDI_PIN(0);
   _asm
     NOP
     NOP
     NOP
     NOP
     NOP
     NOP
     NOP
     NOP
     NOP
     NOP
     NOP
     NOP
     NOP
     NOP
   _endasm;
   SCK_PIN(1);
   _asm
     NOP
   _endasm;   
}
 
static void rf12_write1(void){
   SCK_PIN(0);
   _asm
     NOP
   _endasm;   
   SDI_PIN(1);
   _asm
     NOP
     NOP
     NOP
     NOP
     NOP
     NOP
     NOP
     NOP
     NOP
     NOP
     NOP
     NOP
     NOP
     NOP
   _endasm;
   SCK_PIN(1);
   _asm
     NOP
   _endasm;   
}
 
void rf12_write_cmd(int cmd) {
  char n = 16;
  SCK_PIN(0);  
  nSEL_PIN(0); 
 
  while(n--) {
    if(cmd & 0x8000)
      rf12_write1();
    else rf12_write0();
    cmd = cmd << 1;
  }
 
  SCK_PIN(0);  
  nSEL_PIN(1); 
}
 
#ifdef RF12_RX_ENABLED
unsigned char rf12_read_fifo(void) { 
  unsigned char i;
  unsigned char result = 0; 
  SCK_PIN(0); 
  SDI_PIN(0); 
  nSEL_PIN(0);
 
  for(i = 0;i < 16; i++) { 
    SCK_PIN(1); 
    _asm
      NOP
      NOP
    _endasm;
    SCK_PIN(0); 
    _asm
      NOP
      NOP
    _endasm; 
  }
 
  for(i = 0;i < 8; i++) { 
    result = result << 1; 
    if(SDO_PIN())  
      result |= 1; 
 
    SCK_PIN(1);  
    _asm
      NOP
      NOP
    _endasm; 
    SCK_PIN(0); 
    _asm
      NOP
      NOP
    _endasm;
  } 
  nSEL_PIN(1); 
  return result;  
} 
#endif //#ifdef RF12_RX_ENABLED 
 
#ifdef RF12_RX_ENABLED
void rf12_reset_fifo() {
  rf12_write_cmd(0xCA80); 
  rf12_write_cmd(0xCA83);
}          
#endif //#ifdef RF12_RX_ENABLED
 
#ifdef RF12_RX_ENABLED
void rf12_rx_data_invalidate() {
  rf12_reset_fifo();
  while(!nIRQ_PIN()) {
    rf12_read_fifo();
  }
  rf12_rx_data_index  = 0;
  rf12_rx_data_status = RF12_RX_DATA_INVALID;
}
#endif //#ifdef RF12_RX_ENABLED
 
 
#ifdef RF12_TX_ENABLED
void rf12_write_byte(unsigned int adata) {
  unsigned char RGIT = 0;
  unsigned int  temp = 0xB800;
  temp |= adata;
  loop: 
    SCK_PIN(0); 
    nSEL_PIN(0);
    SDI_PIN(0); 
    SCK_PIN(1); 
    if(SDO_PIN())
      RGIT = 1;
      else RGIT = 0;
    SCK_PIN(0);
    SDI_PIN(1);
    nSEL_PIN(1);
    if(RGIT == 0) {
      goto loop;
    } else {
        RGIT = 0;
        rf12_write_cmd(temp);
    }
}
#endif //#ifdef RF12_TX_ENABLED
 
#ifdef RF12_TX_ENABLED
void rf12_tx_send(RF12_FRAME * Frame) {
  unsigned char i;
  unsigned int  chk = 0;
 
  #ifdef rf12_tx_led_on
  rf12_tx_led_on();
  #endif
 
  rf12_write_cmd(0x8228);  
  delay_us(4); 
  rf12_write_cmd(0x8238); 
  _asm
    NOP
    NOP
  _endasm;        
  rf12_write_byte(0xAA); 
  rf12_write_byte(0xAA); 
  rf12_write_byte(0xAA);  
  rf12_write_byte(0x2D); 
  rf12_write_byte(0xD4); 
 
  rf12_write_byte(Frame->Sender);
  chk += Frame->Sender; 
  rf12_write_byte(Frame->Dest);
  chk += Frame->Dest; 
  for(i = 0; i < sizeof(Frame->Data); i++) {
    rf12_write_byte(Frame->Data[i]);
    chk += Frame->Data[i];
  }
  rf12_write_byte(chk);
  rf12_write_byte(chk >> 8);
 
  rf12_write_byte(0xAA);
  rf12_write_byte(0xAA); 
  rf12_write_cmd(0x8208); 
 
  #ifdef rf12_tx_led_off
  rf12_tx_led_off();
  #endif
}
#endif //#ifdef RF12_TX_ENABLED
 
void rf12_init_io_pins(void) {
  #ifdef rf12_rx_led_init
  rf12_rx_led_init();
  #endif
  #ifdef rf12_tx_led_init
  rf12_tx_led_init();
  #endif
  #ifdef rf12_fail_led_init
  rf12_tx_led_init();
  #endif
 
  SDI_TRIS();
  SDO_TRIS();
  SCK_TRIS();
  nSEL_TRIS();
  RESET_TRIS();
  nIRQ_TRIS();
}
 
#ifdef RF12_RX_INTERRUPT
SIGHANDLER(int2_handler){
  unsigned char i; 
  unsigned int  chk = 0;
 
  if(!rf12_rx_data_status) {
    rf12_rx_led_on();
    RF12_PACKET.Raw[rf12_rx_data_index++] = rf12_read_fifo();
    rf12_rx_data_status = RF12_RX_DATA_INVALID;
 
    if(rf12_rx_data_index > (sizeof(RF12_FRAME))) {
      for(i=0; i < (sizeof(RF12_FRAME) - sizeof(RF12_PACKET.Checksum)); i++)
        chk += RF12_PACKET.Raw[i];
 
      if(RF12_PACKET.Checksum == chk){
          rf12_rx_data_status = RF12_RX_DATA_CHK_OK;
          rf12_fail_led_off();
      } else {
        rf12_rx_data_status = RF12_RX_DATA_CHK_FAILED;
        rf12_fail_led_on();
        rf12_rx_fail_count++;
        //Todo: Restet RF12
        RESET_PIN(1);
      }
    }
    rf12_rx_led_off();
  }
  INTCON3bits.INT2IF = 0;
}
 
DEF_INTHIGH(high_handler) 
  DEF_HANDLER(SIG_INT2, int2_handler);
END_DEF
 
DEF_INTLOW(low_handler) 
  DEF_HANDLER(SIG_INT2, int2_handler);
END_DEF
#endif  
 
#ifdef RF12_RX_ENABLED  
void rf12_init_rx() {
 
  rf12_init_io_pins();
 
  //Interrupt
  #ifdef RF12_RX_INTERRUPT
  INTCON3bits.INT2IF = 0;
  INTCON2bits.INTEDG2 = 0;
  INTCON3bits.INT2IE = 1;
  INTCONbits.GIE = 1;
  #endif
 
  nSEL_PIN(1);
  SDI_PIN(1);
  SCK_PIN(0);
 
  rf12_write_cmd(0x80D8);//enable register,433MHz,12.5pF
  rf12_write_cmd(0x82D8);//enable receive,!PA 
  rf12_write_cmd(0xA640); 
  rf12_write_cmd(0xC647); 
  rf12_write_cmd(0x94A0);//VDI,FAST,134kHz,0dBm,-103dBm 
  rf12_write_cmd(0xC2AC); 
  rf12_write_cmd(0XCC77);  
  rf12_write_cmd(0xC49B); 
  rf12_write_cmd(0x9850);//!mp,9810=30kHz,MAX OUT 
  rf12_write_cmd(0xE000);//NOT USE 
  rf12_write_cmd(0xC800);//NOT USE 
  rf12_write_cmd(0xC000);//1.0MHz,2.
  rf12_rx_data_invalidate(); 
}
#endif //#ifdef RF12_RX_ENABLED
 
 
#ifdef RF12_TX_ENABLED
void rf12_tx_init(void){
 
  rf12_init_io_pins();
 
  nSEL_PIN(1);
  SDI_PIN(1);
  SCK_PIN(0);
 
  rf12_write_cmd(0x80d8);
  rf12_write_cmd(0x8208);
  rf12_write_cmd(0xA640);
  rf12_write_cmd(0xc647);
  rf12_write_cmd(0xcc77);
  rf12_write_cmd(0x94a0);
  rf12_write_cmd(0xc2ac);
  rf12_write_cmd(0xca80);
  rf12_write_cmd(0xca83);
  rf12_write_cmd(0xc49b);
  rf12_write_cmd(0x9850);
  rf12_write_cmd(0xe000);
  rf12_write_cmd(0xc80e);
  rf12_write_cmd(0xc000);
}
#endif //#ifdef RF12_TX_ENABLED
 
 
#ifndef RF12_RX_INTERRUPT
unsigned char rf12_rx_read(RF12_FRAME * Frame) {
  unsigned char index = 0;
  unsigned int  chk = 0;
  unsigned char i;
  int timeout = RF12_TIMEOUT;
 
  while(timeout) {
    if(!nIRQ_PIN()){
      #ifdef rf12_rx_led_on
      rf12_rx_led_on();
      #endif
      Frame->Raw[index++] = rf12_read_fifo();
      if(index > (sizeof(RF12_FRAME))) {
        for(i=0; i < (sizeof(RF12_FRAME) - sizeof(Frame->Checksum)); i++)
          chk += Frame->Raw[i];
 
        rf12_reset_fifo();
        #ifdef rf12_rx_led_off
        rf12_rx_led_off();
        #endif
        if(Frame->Checksum == chk)
          return RF12_RX_DATA_CHK_OK;
          return RF12_RX_DATA_CHK_FAILED;
      }
     timeout = RF12_TIMEOUT;
    }
    timeout--;
  }
  rf12_reset_fifo();
  #ifdef rf12_rx_led_off
  rf12_rx_led_off();
  #endif
  LATAbits.LATA0 = 0;
  return RF12_EXPIRED;
}
#endif //#ifndef RF12_RX_INTERRUPT
 
#endif // __rf12_H__