// --------------------------------------------------------------------------------------------
// Basic RF functions -- revised version 0.11
// designed for the Smart-Its Core
// RF-module: BIM2-433 (radiometrix), XTR434 (radio-tech)
// MCU: PIC16F876, PIC18F252
// --------------------------------------------------------------------------------------------
// last modified: 09.03.2003
// --------------------------------------------------------------------------------------------
// COPYRIGHT (c) 2002, 2003 by Albrecht Schmidt - http://www.comp.lancs.ac.uk/~albrecht/
// Lancaster University, http://www.comp.lancs.ac.uk/
//
// 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 of the License, 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.
// --------------------------------------------------------------------------------------------
// developed/improved for various prototypes
// in the Smart-Its Project (http://www.smart-its.org) and
// in the Equator IRC (http://www.equator.ac.uk)
// --------------------------------------------------------------------------------------------
// compiled with
// CCS PCM C Compiler, Version 3.080
// CCS PCH C Compiler
// --------------------------------------------------------------------------------------------
// packet format
// <Preamble><FF><FF><10011001><LENByte><LENByte><...DATA...><CRC_LOW><CRC_HI>
// --------------------------------------------------------------------------------------------
// *********************************************************************************************
// you must define the following in your code!
// change these Pins if they are different in your design
// #define RF_TX_PIN PIN_C3
// #define RF_RX_PIN PIN_C0
// #define RF_CD_PIN PIN_B0
// #define RF_TX_ENABLE_PIN PIN_C2
// #define RF_RX_ENABLE_PIN PIN_C1
// #define FORCE_NEW_PROTOCOL 1 // or 0 to be compatible with the old protocol...
// #define RF_SPEED 19200 // or 38400
// *********************************************************************************************
// --------------------------------------------------------------------------------------------
// *********************************************************************************************
// high level functions:
// void reset_rf_buffer() - clear buffer, use before printf
// void to_rf_buffer(char c) - as first argument in printf
//
// void RF_printf() - print the buffer over RF
// int RF_printf_OnNOCD(long timeOut_ms) - print the buffer over RF if no carrier is detected
//
// int rfReceiveOnCD(char *buf, int maxLen, long timeOut) - receive a packet via RF
//
// void RF_version() - print the version over RF
// *********************************************************************************************
// --------------------------------------------------------------------------------------------
// low level functions
// void RF_put_long(unsigned long ldata) - write a long to RF
// void RF_putc(char data) - write a char to RF
// char RF_getc() - get a char from RF
// int RF_kbhit() - check for a char on RF
//
// unsigned long crc16(char * msg, int len) - calculate a crc16 offline
//
// void rfPowerDown() - switch BIM2-module in power down mode
// void rfTxOn() - switch BIM2-module in transmission mode
// void rfRxOn() - switch BIM2-module in receive mode
// void rfSelfTest() - switch BIM2-module in self test mode
//
// int rfTransmit(char * msg, int len) - transmit a number of characters via RF
// int rfReceive(char *buf, int maxLen) - receive a packet via RF
// int rfReceiveOnCD(char *buf, int maxLen, long timeOut) - receive a packet via RF
//
// void RF_version() - print the version over RF
// --------------------------------------------------------------------------------------------
// important global variable:
// rf_buffer - a char array for communication
// int rf_buffer_ptr - the used size of the array rf_buffer
// maximal number of chars to sent/receive in one packet
#define MAXBUF 80
#use rs232(baud=RF_SPEED,xmit=RF_TX_PIN,rcv=RF_RX_PIN)
// buffer used for printing to RF and for receiving packages
byte rf_buffer[MAXBUF];
// pointer to the position in the buffer
int rf_buffer_ptr;
// version number of this program
const float rf_version_no=0.11;
// the table for the CRC calculation
const unsigned long crc_tbl[16]=
{
0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401,
0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400
};
// reset the buffer pointer
void reset_rf_buffer()
{
rf_buffer_ptr=0;
}
// fill the buffer with chars
// used as first parameter in printf
void to_rf_buffer(char c)
{
if (rf_buffer_ptr<MAXBUF)
{
rf_buffer[rf_buffer_ptr++]=c;
}
}
// write a long value to RF
void RF_put_long(unsigned long ldata)
{
#use rs232(baud=RF_SPEED,xmit=RF_TX_PIN,rcv=RF_RX_PIN)
#byte ldataL = ldata
#byte ldataH = ldata+1
putc(ldataL); // low byte first
putc(ldataH);
}
// write char to RF
void RF_putc(char data)
{
#use rs232(baud=RF_SPEED,xmit=RF_TX_PIN,rcv=RF_RX_PIN)
putc(data);
}
// get a char from RF
// non blocking, returns the char received or 0x00 when timed out
// 0x00 does not garantee that it is a timeout could also be received
// however this will be detected in the CRC...
char RF_getc()
{
#use rs232(baud=RF_SPEED,xmit=RF_TX_PIN,rcv=RF_RX_PIN)
boolean flag1;
char ch;
int i;
flag1=0;
while (flag1==0 && i<3000) // wait for the start id '10011001'
{
// check if a character is available
if (kbhit())
{
// if yes then get
ch=getc();
flag1=1;
} else {
// else delay a bit
restart_wdt();
delay_us(5);
}
i++;
}
if (i==3000)
{
// time out condition...
return 0;
}
return ch;
}
// get a char from RF (blocking)
char RF_getc_blocking()
{
#use rs232(baud=RF_SPEED,xmit=RF_TX_PIN,rcv=RF_RX_PIN)
return getc();
}
// get a char from RF
//boolean RF_kbhit()
int RF_kbhit()
{
#use rs232(baud=RF_SPEED,xmit=RF_TX_PIN,rcv=RF_RX_PIN)
return kbhit();
}
// calculate a crc16 offline (for the functions below
// the code is woven in the transmit and receive function)
unsigned long crc16(char * msg, int len)
{
int i, ch;
unsigned long crc;
// initialize
crc = 0xFFFF;
// go over the message
for (i=0;i<len;i++)
{
ch = msg[i];
/* Nibble-at-a-time processing. Note that because this is
using the reflected algorithm, the lo-nibble is processed first. */
crc = crc_tbl[(ch ^ crc) & 15] ^ (crc >> 4);
crc = crc_tbl[((ch >> 4) ^ crc) & 15] ^ (crc >> 4);
}
return crc;
}
// switch BIM2-module in power down mode
void rfPowerDown()
{
// disable RX, disable TX
output_high(RF_TX_ENABLE_PIN);
output_high(RF_RX_ENABLE_PIN);
}
// switch BIM2-module in transmission mode
void rfTxOn()
{
// disable RX, enable TX
output_low(RF_TX_ENABLE_PIN);
output_high(RF_RX_ENABLE_PIN);
}
// switch BIM2-module in receive mode
void rfRxOn()
{
// enable RX, disable TX
output_high(RF_TX_ENABLE_PIN);
output_low(RF_RX_ENABLE_PIN);
}
// switch BIM2-module in self test mode
void rfSelfTest()
{
// enable RX, enable TX
output_low(RF_TX_ENABLE_PIN);
output_low(RF_RX_ENABLE_PIN);
}
// transmit a number of characters via RF
// msg is a char array and len is the number of chars to transmitted
// always return 1 ...
int rfTransmit(char * msg, int len)
{
#use rs232(baud=RF_SPEED,xmit=RF_TX_PIN,rcv=RF_RX_PIN)
int i;
char ch;
// for inline crc calculation
unsigned long crc;
crc = 0xFFFF;
i=0;
// transmitter on
rfTxOn();
restart_wdt();
delay_ms(3); // according to the datasheet of BIM (old BIM1 version)
//preample 18Byte ~ 180 bit ~ fastest case @57600bit/s ~ 3ms
for (i=0;i<18;i++){
RF_putc(85); // sent '01010101'
}
// two bytes with FF
RF_putc(255);
RF_putc(255);
// indicate the start id '10011001' - selected by me
// no reason for the pattern...
RF_putc(154);
// sent len - number of data bytes to follow
ch=len;
RF_putc(ch);
RF_putc(ch);
// sent the message - be aware will perform poorly if data is unsymetric!!!
for (i=0;i<len;i++)
{
restart_wdt();
// copy the character
ch = msg[i];
// sent the char
RF_putc(ch);
// calc crc16
crc = crc_tbl[(ch ^ crc) & 15] ^ (crc >> 4);
crc = crc_tbl[((ch >> 4) ^ crc) & 15] ^ (crc >> 4);
}
// sent two bytes CRC - low byte first, the high byte
RF_put_long(crc);
rfPowerDown();
return 1;
}
// receive a packet via RF
// buf is a char array and len is the max number of chars to receive
// return 0 - OK received
// return 1 - Time out in receive loop
// return 3 - Packet len byte corrupted
// return 4 - Packet DATA corrupted
int rfReceive(char *buf, int maxLen)
{
#use rs232(baud=RF_SPEED,xmit=RF_TX_PIN,rcv=RF_RX_PIN)
int j, packetLen, packetLen1;
// storage for bytes returned
byte ch, crc0, crc1;
// crc is used for inline CRC calculation,
// crc_rec is used to store the crc received in crc0 and crc1
unsigned long i, crc, crc_rec;
// initialize CRC
crc = 0xFFFF;
for (j=0;j<maxLen;j++) {buf[j]='X';}
// switch the receiver on
rfRxOn();
delay_ms(3); // according to the datasheet of BIM (old BIM1 version)
ch=0;
i=0;
while (ch!=153 && ch!=154 && i<15000) // wait for the start id '10011001'
{
// check if a character is available
if (RF_kbhit())
{
// if yes then get
ch=RF_getc();
} else {
// else delay a bit
restart_wdt();
delay_us(5);
}
i++;
}
if (i==15000)
{
// time out condition...
return 1;
}
// got a start byte - get the data length next
packetLen = RF_getc();
if ((ch==154) ||(FORCE_NEW_PROTOCOL==1) ) { // newer version - safer packet size...
packetLen1 = RF_getc();
if (packetLen != packetLen1) { return 3;} // error in packet length...
}
// if the package is to long reduce the length
// will result in a corrupt package...
if ((packetLen+2) >= MAXBUF)
{
// packet to long
packetLen=MAXBUF - 2;
}
// read the data bytes now
i=0;
while ( i<packetLen){
restart_wdt();
// read a byte
ch=RF_getc();
// calc crc16
crc = crc_tbl[(ch ^ crc) & 15] ^ (crc >> 4);
crc = crc_tbl[((ch >> 4) ^ crc) & 15] ^ (crc >> 4);
// store it in the buffer
buf[i]=ch;
i++;
}
// data bytes done, ... read the CRC
crc0 = RF_getc();
crc1 = RF_getc();
// calc 16bit long from the bytes
crc_rec = crc1*256+crc0;
// put a zero at the end - make it printable for a string
buf[packetLen]=0;
// check the CRC...
if (crc==crc_rec) {
// packet ok
return 0;
} else {
// packet currupt
return 4;
}
}
// print the buffer over RF
void RF_printf()
{
rfTransmit(rf_buffer,rf_buffer_ptr);
}
// print the buffer over RF
// timeOut_ms is the time in mili seconds that is looked for
// a time where there is no carrier, return a 0 if send was
// ok otherwise 1
int RF_printf_OnNOCD(long timeOut_ms)
{
long i;
rfRxOn();
i=0;
while(i<timeOut_ms){
restart_wdt();
if(input(RF_CD_PIN)==1){
rfTransmit(rf_buffer,rf_buffer_ptr);
return 0; // ok
} else {
delay_ms(1);
}
i++;
}
return 1; // timed out ....
}
// print the version over RF
void RF_version()
{
reset_rf_buffer();
printf(to_rf_buffer, "RF V%f, 09/03/03", rf_version_no);
RF_printf();
}
// receive a packet via RF when a CD is dected
// buf is a char array and len is the max number of chars to receive
// timeOut is the time in mili seconds that is looked for a carrier
// return 0 - OK received
// return 1 - Time out in receive loop
// return 2 - Time out NO_CD
// return 3 - Packet len byte corrupted
// return 4 - Packet DATA corrupted
int rfReceiveOnCD(char *buf, int maxLen, long timeOut)
{
long i;
int ret;
rfRxOn();
i=0;
ret = 5;
while(i<timeOut){
restart_wdt();
if(input(RF_CD_PIN)==0){
ret = rfReceive(buf,maxLen);
return (ret);
} else {
delay_ms(1);
}
i++;
}
// timed out
return 2;
}