From ed3dac2ffbac83019fb1c35923b1b0ff64a7e9fe Mon Sep 17 00:00:00 2001 From: Jimmy Date: Tue, 22 Feb 2022 02:29:53 +1300 Subject: [PATCH] Add Rasperry Pi version --- .gitignore | 3 + .gitmodules | 3 + main | Bin 0 -> 20176 bytes makefile | 5 + src/driver.cpp | 49 +++++++ src/driver.h | 52 +++++++ src/mrf24j.cpp | 351 +++++++++++++++++++++++++++++++++++++++++++++++ src/mrf24j.h | 250 +++++++++++++++++++++++++++++++++ test/rx/main.cpp | 66 +++++++++ test/tx/main.cpp | 83 +++++++++++ 10 files changed, 862 insertions(+) create mode 100755 .gitignore create mode 100755 .gitmodules create mode 100755 main create mode 100755 makefile create mode 100755 src/driver.cpp create mode 100755 src/driver.h create mode 100755 src/mrf24j.cpp create mode 100755 src/mrf24j.h create mode 100755 test/rx/main.cpp create mode 100755 test/tx/main.cpp diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..f37224e --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.hex +*.elf +*.bin diff --git a/.gitmodules b/.gitmodules new file mode 100755 index 0000000..52c979b --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "test/usart"] + path = test/usart + url = git@git.chch.tech:avr/usart.git diff --git a/main b/main new file mode 100755 index 0000000000000000000000000000000000000000..8355a3338345b3e8cea6977991717bdd0fd03eaa GIT binary patch literal 20176 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 + +namespace driver +{ + namespace { + Mrf24j *mrf; + int spi; + } + + void callback(int gpio, int level, uint32_t tick) { + mrf->interrupt_handler(); + mrf->check_flags(); + } + + void init(Mrf24j *mrf) { + + gpioInitialise(); + driver::mrf = mrf; + spi = spiOpen(0, 1000000, 0); + gpioSetMode(RESET, PI_OUTPUT); + gpioWrite(RESET, 1); + gpioSetMode(SPI_CS, PI_OUTPUT); + cs_high(); + gpioSetAlertFunc(INT, callback); + } + + uint8_t transfer(uint8_t data) { + char txbuff[1], rxbuff[1]; + txbuff[0] = data; + spiXfer(spi, txbuff, rxbuff, 1); + return rxbuff[0]; + } + void reset() { + gpioWrite(RESET , 0); + time_sleep(0.01); + gpioWrite(RESET, 1); + time_sleep(0.02); + } + + void wake() { + } + + // INTERRUPT { + // mrf->interrupt_handler(); // mrf24 object interrupt routine + // mrf->check_flags(); + // } +} + diff --git a/src/driver.h b/src/driver.h new file mode 100755 index 0000000..82ee2a2 --- /dev/null +++ b/src/driver.h @@ -0,0 +1,52 @@ +#pragma once + +#include "mrf24j.h" +#include + + +#if defined __AVR_ATmega328P__ + #define SPI_DDR DDRB + #define SPI_PORT PORTB + #define SPI_SCK PB5 + #define SPI_MISO PB4 + #define SPI_MOSI PB3 + #define SPI_CS PB2 + #define RESET_DDR DDRB + #define RESET_PORT PORTB + #define RESET PB0 + #define WAKE_PORT PORTB + #define WAKE_DDR DDRB + #define WAKE_PIN PB1 + #define INTERRUPT ISR(INT0_vect) +#elif defined __AVR_ATmega32__ || defined __AVR_ATmega16__ + #define SPI_PORT PORTB + #define SPI_DDR DDRB + #define SPI_SCK PB7 + #define SPI_MOSI PB5 + #define SPI_CS PB4 + #define RESET_DDR DDRB + #define RESET_PORT PORTB + #define RESET PB0 + #define WAKE_PORT PORTB + #define WAKE_DDR DDRB + #define WAKE_PIN PB1 + #define INTERRUPT ISR(INT2_vect) +#elif defined RASPBERRYPI + +#endif + +#define RESET 24 //24 +#define SPI_CS 8 //8 +#define INT 2 //25 + +namespace driver +{ + void init(Mrf24j *mrf); + uint8_t transfer(uint8_t data); + + inline void cs_low() {gpioWrite(SPI_CS, 0);} + + inline void cs_high() {gpioWrite(SPI_CS, 1);} + void wake(); + void reset(); +} // namespace spi diff --git a/src/mrf24j.cpp b/src/mrf24j.cpp new file mode 100755 index 0000000..f6709b7 --- /dev/null +++ b/src/mrf24j.cpp @@ -0,0 +1,351 @@ +/** + * mrf24j.cpp, Karl Palsson, 2011, karlp@tweak.net.au + * modified bsd license / apache license + */ + +#include "mrf24j.h" +#include "driver.h" +#include +#include + + +// aMaxPHYPacketSize = 127, from the 802.15.4-2006 standard. +static uint8_t rx_buf[127]; + +// essential for obtaining the data frame only +// bytes_MHR = 2 Frame control + 1 sequence number + 2 panid + 2 shortAddr Destination + 2 shortAddr Source +static int bytes_MHR = 9; +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 + +static int ignoreBytes = 0; // bytes to ignore, some modules behaviour. + +static bool bufPHY = false; // flag to buffer all bytes in PHY Payload, or not + +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. + */ +Mrf24j::Mrf24j() { + driver::init(this); +} + +void Mrf24j::reset(void) { + driver::reset(); +} +void Mrf24j::handlers(void (*rx_handler)(void), void (*tx_handler)(void)) { + this->rx_handler = rx_handler; + this->tx_handler = tx_handler; + +} + +byte Mrf24j::read_short(byte address) { + driver::cs_low(); + // 0 top for short addressing, 0 bottom for read + driver::transfer(address<<1 & 0b01111110); + byte ret = driver::transfer(0x00); + driver::cs_high(); + return ret; +} + +byte Mrf24j::read_long(word address) { + driver::cs_low(); + byte ahigh = address >> 3; + byte alow = address << 5; + driver::transfer(0x80 | ahigh); // high bit for long + driver::transfer(alow); + byte ret = driver::transfer(0); + driver::cs_high(); + return ret; +} + + +void Mrf24j::write_short(byte address, byte data) { + driver::cs_low(); + // 0 for top short address, 1 bottom for write + driver::transfer((address<<1 & 0b01111110) | 0x01); + driver::transfer(data); + driver::cs_high(); +} + +void Mrf24j::write_long(word address, byte data) { + driver::cs_low(); + byte ahigh = address >> 3; + byte alow = address << 5; + driver::transfer(0x80 | ahigh); // high bit for long + driver::transfer(alow | 0x10); // last bit for write + driver::transfer(data); + driver::cs_high(); +} + +word Mrf24j::get_pan(void) { + byte panh = read_short(MRF_PANIDH); + return panh << 8 | read_short(MRF_PANIDL); +} + +void Mrf24j::set_pan(word panid) { + write_short(MRF_PANIDH, panid >> 8); + write_short(MRF_PANIDL, panid & 0xff); +} + +void Mrf24j::address16_write(word address16) { + write_short(MRF_SADRH, address16 >> 8); + write_short(MRF_SADRL, address16 & 0xff); +} + +word Mrf24j::address16_read(void) { + byte a16h = read_short(MRF_SADRH); + return a16h << 8 | read_short(MRF_SADRL); +} + + +void Mrf24j::send_str(word dest16, char * data) { + byte len = strlen(data); // get the length of the char* array + send(dest16, data, len); +} + +/** + * Simple send 16, with acks, not much of anything.. assumes src16 and local pan only. + * @param data + */ +void Mrf24j::send(word dest16, char * data, int len) { + int i = 0; + write_long(i++, bytes_MHR); // header length + // +ignoreBytes is because some module seems to ignore 2 bytes after the header?!. + // default: ignoreBytes = 0; + write_long(i++, bytes_MHR+ignoreBytes+len); + + // 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, + write_long(i++, 0b10001000); // second byte of frame control + write_long(i++, 1); // sequence number 1 + + word panid = get_pan(); + + write_long(i++, panid & 0xff); // dest panid + write_long(i++, panid >> 8); + write_long(i++, dest16 & 0xff); // dest16 low + write_long(i++, dest16 >> 8); // dest16 high + + word src16 = address16_read(); + write_long(i++, src16 & 0xff); // src16 low + write_long(i++, src16 >> 8); // src16 high + + // All testing seems to indicate that the next two bytes are ignored. + //2 bytes on FCS appended by TXMAC + i+=ignoreBytes; + for (int q = 0; q < len; q++) { + write_long(i++, data[q]); + } + // ack on, and go! + write_short(MRF_TXNCON, (1<> 6; + tx_info.channel_busy = (tmp & (1 << CCAFAIL)); + } +} + + +/** + * Call this function periodically, it will invoke your nominated handlers + */ +void Mrf24j::check_flags(){ + // TODO - we could check whether the flags are > 1 here, indicating data was lost? + if (flag_got_rx) { + flag_got_rx = 0; + this->rx_handler(); + } + if (flag_got_tx) { + flag_got_tx = 0; + this->tx_handler(); + } +} + +/** + * Set RX mode to promiscuous, or normal + */ +void Mrf24j::set_promiscuous(boolean enabled) { + if (enabled) { + write_short(MRF_RXMCR, 0x01); + } else { + write_short(MRF_RXMCR, 0x00); + } +} + +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::set_ignoreBytes(int ib) { + // some modules behaviour + ignoreBytes = ib; +} + +/** + * Set bufPHY flag to buffer all bytes in PHY Payload, or not + */ +void Mrf24j::set_bufferPHY(boolean bp) { + bufPHY = bp; +} + +boolean Mrf24j::get_bufferPHY(void) { + return bufPHY; +} + +/** + * Set PA/LNA external control + */ +void Mrf24j::set_palna(boolean enabled) { + if (enabled) { + write_long(MRF_TESTMODE, 0x07); // Enable PA/LNA on MRF24J40MB module. + }else{ + write_long(MRF_TESTMODE, 0x00); // Disable PA/LNA on MRF24J40MB module. + } +} + +void Mrf24j::rx_flush(void) { + write_short(MRF_RXFLUSH, 0x01); +} + +void Mrf24j::rx_disable(void) { + write_short(MRF_BBREG1, 0x04); // RXDECINV - disable receiver +} + +void Mrf24j::rx_enable(void) { + write_short(MRF_BBREG1, 0x00); // RXDECINV - enable receiver +} + +void Mrf24j::enable_wake() { + write_short(MRF_RXFLUSH, 0x60); // Enable WAKE pin and set polarity to active-high + write_short(MRF_WAKECON, 0x80); // Enable Immediate Wake-up mode +} + +void Mrf24j::sleep() { + write_short(MRF_SOFTRST, 0x04); // Perform a Power Management Reset + write_short(MRF_SLPACK, 0x80); // Put MRF24J40 to Sleep immediately +} + +void Mrf24j::wake() { + driver::wake(); + write_short(MRF_RFCTL, 0x04); // RF State Machine reset + write_short(MRF_RFCTL, 0x00); + gpioSleep(0, 0 ,2000); // Delay 2 ms to allow 20 MHz main oscillator time to stabilize before transmitting or receiving. +} + +void Mrf24j::turbo() { + write_short(MRF_BBREG0, 0x01); + write_short(MRF_BBREG3, (1<<5)|(1<<4)); + write_short(MRF_BBREG4, (1<<6)); + write_short(MRF_SOFTRST, (1<<1)); +} + +void Mrf24j::set_power(byte level) { + write_short(MRF_RFCON3, level); +} \ No newline at end of file diff --git a/src/mrf24j.h b/src/mrf24j.h new file mode 100755 index 0000000..2c8f71e --- /dev/null +++ b/src/mrf24j.h @@ -0,0 +1,250 @@ +/* + * File: mrf24j.h + * copyright Karl Palsson, karlp@tweak.net.au, 2011 + * modified BSD License / apache license + */ +typedef unsigned char uint8_t; + +typedef unsigned char byte; +typedef unsigned int word; +typedef bool boolean; + +#ifndef LIB_MRF24J_H +#define LIB_MRF24J_H + +#define MRF_RXMCR 0x00 +#define MRF_PANIDL 0x01 +#define MRF_PANIDH 0x02 +#define MRF_SADRL 0x03 +#define MRF_SADRH 0x04 +#define MRF_EADR0 0x05 +#define MRF_EADR1 0x06 +#define MRF_EADR2 0x07 +#define MRF_EADR3 0x08 +#define MRF_EADR4 0x09 +#define MRF_EADR5 0x0A +#define MRF_EADR6 0x0B +#define MRF_EADR7 0x0C +#define MRF_RXFLUSH 0x0D +//#define MRF_Reserved 0x0E +//#define MRF_Reserved 0x0F +#define MRF_ORDER 0x10 +#define MRF_TXMCR 0x11 +#define MRF_ACKTMOUT 0x12 +#define MRF_ESLOTG1 0x13 +#define MRF_SYMTICKL 0x14 +#define MRF_SYMTICKH 0x15 +#define MRF_PACON0 0x16 +#define MRF_PACON1 0x17 +#define MRF_PACON2 0x18 +//#define MRF_Reserved 0x19 +#define MRF_TXBCON0 0x1A + +// TXNCON: TRANSMIT NORMAL FIFO CONTROL REGISTER (ADDRESS: 0x1B) +#define MRF_TXNCON 0x1B +#define MRF_TXNTRIG 0 +#define MRF_TXNSECEN 1 +#define MRF_TXNACKREQ 2 +#define MRF_INDIRECT 3 +#define MRF_FPSTAT 4 + +#define MRF_TXG1CON 0x1C +#define MRF_TXG2CON 0x1D +#define MRF_ESLOTG23 0x1E +#define MRF_ESLOTG45 0x1F +#define MRF_ESLOTG67 0x20 +#define MRF_TXPEND 0x21 +#define MRF_WAKECON 0x22 +#define MRF_FRMOFFSET 0x23 +// TXSTAT: TX MAC STATUS REGISTER (ADDRESS: 0x24) +#define MRF_TXSTAT 0x24 +#define TXNRETRY1 7 +#define TXNRETRY0 6 +#define CCAFAIL 5 +#define TXG2FNT 4 +#define TXG1FNT 3 +#define TXG2STAT 2 +#define TXG1STAT 1 +#define TXNSTAT 0 + +#define MRF_TXBCON1 0x25 +#define MRF_GATECLK 0x26 +#define MRF_TXTIME 0x27 +#define MRF_HSYMTMRL 0x28 +#define MRF_HSYMTMRH 0x29 +#define MRF_SOFTRST 0x2A +//#define MRF_Reserved 0x2B +#define MRF_SECCON0 0x2C +#define MRF_SECCON1 0x2D +#define MRF_TXSTBL 0x2E +//#define MRF_Reserved 0x2F +#define MRF_RXSR 0x30 +#define MRF_INTSTAT 0x31 +#define MRF_INTCON 0x32 +#define MRF_GPIO 0x33 +#define MRF_TRISGPIO 0x34 +#define MRF_SLPACK 0x35 +#define MRF_RFCTL 0x36 +#define MRF_SECCR2 0x37 +#define MRF_BBREG0 0x38 +#define MRF_BBREG1 0x39 +#define MRF_BBREG2 0x3A +#define MRF_BBREG3 0x3B +#define MRF_BBREG4 0x3C +//#define MRF_Reserved 0x3D +#define MRF_BBREG6 0x3E +#define MRF_CCAEDTH 0x3F + +#define MRF_RFCON0 0x200 +#define MRF_RFCON1 0x201 +#define MRF_RFCON2 0x202 +#define MRF_RFCON3 0x203 +#define MRF_RFCON5 0x205 +#define MRF_RFCON6 0x206 +#define MRF_RFCON7 0x207 +#define MRF_RFCON8 0x208 +#define MRF_SLPCAL0 0x209 +#define MRF_SLPCAL1 0x20A +#define MRF_SLPCAL2 0x20B +#define MRF_RSSI 0x210 +#define MRF_SLPCON0 0x211 +#define MRF_SLPCON1 0x220 +#define MRF_WAKETIMEL 0x222 +#define MRF_WAKETIMEH 0x223 +#define MRF_REMCNTL 0x224 +#define MRF_REMCNTH 0x225 +#define MRF_MAINCNT0 0x226 +#define MRF_MAINCNT1 0x227 +#define MRF_MAINCNT2 0x228 +#define MRF_MAINCNT3 0x229 +#define MRF_TESTMODE 0x22F +#define MRF_ASSOEADR1 0x231 +#define MRF_ASSOEADR2 0x232 +#define MRF_ASSOEADR3 0x233 +#define MRF_ASSOEADR4 0x234 +#define MRF_ASSOEADR5 0x235 +#define MRF_ASSOEADR6 0x236 +#define MRF_ASSOEADR7 0x237 +#define MRF_ASSOSADR0 0x238 +#define MRF_ASSOSADR1 0x239 +#define MRF_UPNONCE0 0x240 +#define MRF_UPNONCE1 0x241 +#define MRF_UPNONCE2 0x242 +#define MRF_UPNONCE3 0x243 +#define MRF_UPNONCE4 0x244 +#define MRF_UPNONCE5 0x245 +#define MRF_UPNONCE6 0x246 +#define MRF_UPNONCE7 0x247 +#define MRF_UPNONCE8 0x248 +#define MRF_UPNONCE9 0x249 +#define MRF_UPNONCE10 0x24A +#define MRF_UPNONCE11 0x24B +#define MRF_UPNONCE12 0x24C + +#define MRF_I_RXIF 0b00001000 +#define MRF_I_TXNIF 0b00000001 + +#define MRF_S_WAKEPOL (1<<6) +#define MRF_S_PAKEPAD (1<<5) +#define MRF_S_IMMWAKE (1<<8) +#define MRF_S_SLPACK (1<<7) +#define MRF_S_RFRST (1<<2) + + + + +typedef struct _rx_info_t{ + uint8_t frame_length; + uint8_t rx_data[116]; //max data length = (127 aMaxPHYPacketSize - 2 Frame control - 1 sequence number - 2 panid - 2 shortAddr Destination - 2 shortAddr Source - 2 FCS) + uint8_t lqi; + uint8_t rssi; +} rx_info_t; + +/** + * Based on the TXSTAT register, but "better" + */ +typedef struct _tx_info_t{ + uint8_t tx_ok:1; + uint8_t retries:2; + uint8_t channel_busy:1; +} tx_info_t; + +class Mrf24j +{ + public: + Mrf24j(); + void reset(void); + void init(void); + void handlers(void (*rx_handler)(void), void (*tx_handler)(void)); + + byte read_short(byte address); + byte read_long(word address); + + void write_short(byte address, byte data); + void write_long(word address, byte data); + + word get_pan(void); + void set_pan(word panid); + + void address16_write(word address16); + word address16_read(void); + + void set_interrupts(void); + + void set_promiscuous(boolean enabled); + + /** + * Set the channel, using 802.15.4 channel numbers (11..26) + */ + void set_channel(byte channel); + + void rx_enable(void); + void rx_disable(void); + + /** If you want to throw away rx data */ + void rx_flush(void); + + rx_info_t * get_rxinfo(void); + + tx_info_t * get_txinfo(void); + + uint8_t * get_rxbuf(void); + + int rx_datalength(void); + + void set_ignoreBytes(int ib); + + /** + * Set bufPHY flag to buffer all bytes in PHY Payload, or not + */ + void set_bufferPHY(boolean bp); + + boolean get_bufferPHY(void); + + /** + * Set PA/LNA external control + */ + void set_palna(boolean enabled); + + void send(word dest16, char * data, int len); + void send_str(word dest16, char * data); + + void interrupt_handler(void); + + void check_flags(); + + void enable_wake(); + void sleep(); + void wake(); + void turbo(); + void set_power(byte level); + + private: + int _pin_reset; + int _pin_cs; + int _pin_int; + void (*rx_handler)(void); + void (*tx_handler)(void); +}; + +#endif /* LIB_MRF24J_H */ diff --git a/test/rx/main.cpp b/test/rx/main.cpp new file mode 100755 index 0000000..461407d --- /dev/null +++ b/test/rx/main.cpp @@ -0,0 +1,66 @@ +/** + * Example code for using a microchip mrf24j40 module to send and receive + * packets using plain 802.15.4 + * Requirements: 3 pins for spi, 3 pins for reset, chip select and interrupt + * notifications + * This example file is considered to be in the public domain + * Originally written by Karl Palsson, karlp@tweak.net.au, March 2011 + */ +#define F_CPU 8000000UL +#include "../../src/mrf24j.h" +#include "../usart/src/usart.h" +#include + +Mrf24j mrf; + +void handle_rx(); +void handle_tx(); + +int main() { + mrf.reset(); + mrf.init(); + + mrf.set_pan(0xcafe); + mrf.set_bufferPHY(true); + // This is _our_ address + mrf.address16_write(0x4202); + mrf.handlers(&handle_rx, &handle_tx); + //mrf.turbo(); + + printf("Started"); + while(1) { + printf("Hello\n\r"); + _delay_ms(2000); + + } +} + + + +void handle_rx() { + printf("------------------------------------------------------\n\r"); + printf("received a packet %i bytes long\n\r", mrf.get_rxinfo()->frame_length); + + if(mrf.get_bufferPHY()){ + printf("Packet data (PHY Payload): "); + for (int i = 0; i < mrf.get_rxinfo()->frame_length; i++) { + printf("%x", mrf.get_rxbuf()[i]); + } + } + + printf("\r\nASCII data (relevant data): "); + for (int i = 0; i < mrf.rx_datalength(); i++) { + putchar(mrf.get_rxinfo()->rx_data[i]); + } + + printf("LQI/RSSI="); + printf("%i/%i\n\r", mrf.get_rxinfo()->lqi, mrf.get_rxinfo()->rssi); +} + +void handle_tx() { + if (mrf.get_txinfo()->tx_ok) { + printf("TX went ok, got ack\n\r"); + } else { + printf("TX failed after %i retries\n\n\r", mrf.get_txinfo()->retries); + } +} diff --git a/test/tx/main.cpp b/test/tx/main.cpp new file mode 100755 index 0000000..0bf1f35 --- /dev/null +++ b/test/tx/main.cpp @@ -0,0 +1,83 @@ +/** + * Example code for using a microchip mrf24j40 module to send and receive + * packets using plain 802.15.4 + * Requirements: 3 pins for spi, 3 pins for reset, chip select and interrupt + * notifications + * This example file is considered to be in the public domain + * Originally written by Karl Palsson, karlp@tweak.net.au, March 2011 + */ + +#define F_CPU 8000000UL +#include "../../src/mrf24j.h" +#include "../../src/driver.h" +#include +#include + + +Mrf24j mrf; +int i = 0; + +void handle_rx(); +void handle_tx(); + +int main() { + + mrf.reset(); + mrf.init(); + time_sleep(1); + + mrf.set_pan(0xcafe); + // This is _our_ address + mrf.address16_write(0x4201); + mrf.handlers(&handle_rx, &handle_tx); + printf("Pan id: %x\n\r", mrf.get_pan()); + //mrf.enable_wake(); + //mrf.set_bufferPHY(true); + //mrf.turbo(); + //mrf.set_power(0b1100000); + //mrf.sleep(); + + printf("Started\n\r"); + + char tmp[20]; + while(1) { + printf("txxxing... %i\n\r", i++); + //mrf.wake(); + + sprintf(tmp,"Received %i\n\r", i); + mrf.send_str(0x4202, tmp); + + time_sleep(2); + } +} + + + +void handle_rx() { + printf("received a packet %i bytes long\n\r", mrf.get_rxinfo()->frame_length); + + if(mrf.get_bufferPHY()){ + printf("Packet data (PHY Payload):\n\r"); + for (int i = 0; i < mrf.get_rxinfo()->frame_length; i++) { + printf("%i", mrf.get_rxbuf()[i]); + } + } + + // printf("\r\nASCII data (relevant data):\n\r"); + // for (int i = 0; i < mrf.rx_datalength(); i++) { + // usart::put(mrf.get_rxinfo()->rx_data[i]); + // } + + printf("\r\nLQI/RSSI="); + printf("%i/%i\n\r", mrf.get_rxinfo()->lqi, mrf.get_rxinfo()->rssi); +} + +void handle_tx() { + if (mrf.get_txinfo()->tx_ok) { + printf("TX went ok, got ack %i\n\r", i); + } else { + printf("TX failed after %i retries\n\n\r", mrf.get_txinfo()->retries); + } + printf("Sleeping\n\r"); + //mrf.sleep(); +}