Implements "much easier to use" as KarlP said in his blog, and some functions to get only the relatively "important data bytes

This commit is contained in:
Pkarc 2011-12-17 01:31:12 -05:00
parent effe217111
commit fac2f3f530
1 changed files with 121 additions and 17 deletions

View File

@ -1,13 +1,31 @@
/**
* mrf24j.cpp, Karl Palsson, 2011, karlp@tweak.net.au
* modifed bsd license / apache license
* modified bsd license / apache license
*/
#include "WProgram.h"
//#include "WProgram.h" //already in mrf24j.h
#include "mrf24j.h"
// aMaxPHYPacketSize = 127, from the 802.15.4-2006 standard.
static uint8_t rx_buf[127];
// essential for obtaining the data frame only
static int bytes_MHR = 9; // header length = 2 Frame control + 1 sequence number + 2 panid + 2 shortAddr Destination + 2 shortAddr Source
static int bytes_FCS = 2; // FCS length = 2
static int bytes_nodata = bytes_MHR + bytes_FCS; // no_data bytes in PHY payload, header length + FCS
volatile uint8_t flag_got_rx;
volatile uint8_t flag_got_tx;
static rx_info_t rx_info;
static tx_info_t tx_info;
/**
* Constructor MRF24J Object.
* @param pin_reset, @param pin_chip_select, @param pin_interrupt
*/
Mrf24j::Mrf24j(int pin_reset, int pin_chip_select, int pin_interrupt) {
_pin_reset = pin_reset;
_pin_cs = pin_chip_select;
@ -17,10 +35,9 @@ Mrf24j::Mrf24j(int pin_reset, int pin_chip_select, int pin_interrupt) {
pinMode(_pin_cs, OUTPUT);
pinMode(_pin_int, INPUT);
SPI.setBitOrder(MSBFIRST) ;
SPI.setDataMode(SPI_MODE0);
SPI.begin();
// arguably should not be here...
reset();
init();
}
void Mrf24j::reset(void) {
@ -34,7 +51,7 @@ byte Mrf24j::read_short(byte address) {
digitalWrite(_pin_cs, LOW);
// 0 top for short addressing, 0 bottom for read
SPI.transfer(address<<1 & 0b01111110);
byte ret = SPI.transfer(0x0);
byte ret = SPI.transfer(0x00);
digitalWrite(_pin_cs, HIGH);
return ret;
}
@ -53,7 +70,7 @@ byte Mrf24j::read_long(word address) {
void Mrf24j::write_short(byte address, byte data) {
digitalWrite(_pin_cs, LOW);
// 0 for top address, 1 bottom for write
// 0 for top short address, 1 bottom for write
SPI.transfer((address<<1 & 0b01111110) | 0x01);
SPI.transfer(data);
digitalWrite(_pin_cs, HIGH);
@ -93,15 +110,16 @@ word Mrf24j::address16_read(void) {
* Simple send 16, with acks, not much of anything.. assumes src16 and local pan only.
* @param data
*/
void Mrf24j::send16(word dest16, byte len, char * data) {
void Mrf24j::send16(word dest16, char * data) {
byte len = strlen(data); // get the length of the char* array
int i = 0;
write_long(i++, 9); // header length
write_long(i++, 9+2+len); //+2 is because module seems to ignore 2 bytes after the header?!
write_long(i++, 9); // header length
write_long(i++, 9+len); // data payload length 0x001
//write_long(i++, 9+2+len); //+2 is because module seems to ignore 2 bytes after the header?!. becose 2 FCS bytes appended by TXMAC
// 0 | pan compression | ack | no security | no data pending | data frame[3 bits]
// 0 | pan compression | ack | no security | no data pending | data frame[3 bits]
write_long(i++, 0b01100001); // first byte of Frame Control
// 16 bit source, 802.15.4 (2003), 16 bit dest,
// 16 bit source, 802.15.4 (2003), 16 bit dest,
write_long(i++, 0b10001000); // second byte of frame control
write_long(i++, 1); // sequence number 1
@ -116,7 +134,7 @@ void Mrf24j::send16(word dest16, byte len, char * data) {
write_long(i++, src16 & 0xff); // src16 low
write_long(i++, src16 >> 8); // src16 high
i+=2; // All testing seems to indicate that the next two bytes are ignored.
//i+=2; // All testing seems to indicate that the next two bytes are ignored. again 2 bytes on FCS appended by TXMAC
for (int q = 0; q < len; q++) {
write_long(i++, data[q]);
}
@ -136,13 +154,13 @@ void Mrf24j::set_channel(byte channel) {
}
void Mrf24j::init(void) {
/*
// Seems a bit ridiculous when I use reset pin anyway
/*
// Seems a bit ridiculous when I use reset pin anyway
write_short(MRF_SOFTRST, 0x7); // from manual
while (read_short(MRF_SOFTRST) & 0x7 != 0) {
; // wait for soft reset to finish
}
*/
*/
write_short(MRF_PACON2, 0x98); // Initialize FIFOEN = 1 and TXONTS = 0x6.
write_short(MRF_TXSTBL, 0x95); // Initialize RFSTBL = 0x9.
@ -163,11 +181,81 @@ void Mrf24j::init(void) {
set_channel(12);
// max power is by default.. just leave it...
//Set transmitter power - See “REGISTER 2-62: RF CONTROL 3 REGISTER (ADDRESS: 0x203)”.
write_long(MRF_RFCON3, 0x00); // transmitter max power
write_long(MRF_TESTMODE, 0x07); // Enables PA/LNA on MRF24J40MB module, otherwise, comment this line.
write_short(MRF_RFCTL, 0x04); // Reset RF state machine.
write_short(MRF_RFCTL, 0x00); // part 2
delay(1); // delay at least 192usec
}
/**
* Call this from within an interrupt handler connected to the MRFs output
* interrupt pin. It handles reading in any data from the module, and letting it
* continue working.
* Only the most recent data is ever kept.
*/
void Mrf24j::interrupt_handler(void) {
uint8_t last_interrupt = read_short(MRF_INTSTAT);
if (last_interrupt & MRF_I_RXIF) {
flag_got_rx++;
// read out the packet data...
noInterrupts();
rx_disable();
uint8_t frame_length = read_long(0x300); // read start of rxfifo for, has 2 bytes more added by FCS. frame_length = m + n + 2
/*
* Uncomment this block, if you want all PHY Payload bytes in the rx_buf buffer
*
// buffer all bytes in PHY Payload
int rb_ptr = 0;
for (int i = 0; i < frame_length; i++) { // from 0x301 to (0x301 + frame_length -1)
rx_buf[rb_ptr++] = read_long(0x301 + i);
}
*/
// buffer data bytes
int rd_ptr = 0;
for (int i = 0; i < rx_datalength(); i++) { // from (0x301 + bytes_MHR) to (0x301 + frame_length - bytes_nodata - 1)
rx_info.rx_data[rd_ptr++] = read_long(0x301 + bytes_MHR + i);
}
rx_info.frame_length = frame_length;
rx_info.lqi = read_long(0x301 + frame_length); // same as datasheet 0x301 + (m + n + 2) <-- frame_length
rx_info.rssi = read_long(0x301 + frame_length + 1); // same as datasheet 0x301 + (m + n + 3) <-- frame_length + 1
rx_enable();
interrupts();
}
if (last_interrupt & MRF_I_TXNIF) {
flag_got_tx++;
uint8_t tmp = read_short(MRF_TXSTAT);
// 1 means it failed, we want 1 to mean it worked.
tx_info.tx_ok = !(tmp & ~(1 << TXNSTAT));
tx_info.retries = tmp >> 6;
tx_info.channel_busy = (tmp & (1 << CCAFAIL));
}
}
/**
* Call this function periodically, it will invoke your nominated handlers
*/
void Mrf24j::check_flags(void (*rx_handler)(void), void (*tx_handler)(void)){
// TODO - we could check whether the flags are > 1 here, indicating data was lost?
if (flag_got_rx) {
flag_got_rx = 0;
rx_handler();
}
if (flag_got_tx) {
flag_got_tx = 0;
tx_handler();
}
}
/**
* Set RX mode to promiscuous, or normal
*/
void Mrf24j::set_promiscuous(boolean enabled) {
if (enabled) {
write_short(MRF_RXMCR, 0x01);
@ -176,6 +264,22 @@ void Mrf24j::set_promiscuous(boolean enabled) {
}
}
rx_info_t * Mrf24j::get_rxinfo(void) {
return &rx_info;
}
tx_info_t * Mrf24j::get_txinfo(void) {
return &tx_info;
}
uint8_t * Mrf24j::get_rxbuf(void) {
return rx_buf;
}
int Mrf24j::rx_datalength(void) {
return rx_info.frame_length - bytes_nodata;
}
void Mrf24j::rx_flush(void) {
write_short(MRF_RXFLUSH, 0x01);
}