diff --git a/src/driver.cpp b/src/driver.cpp
new file mode 100644
index 0000000..4fbd537
--- /dev/null
+++ b/src/driver.cpp
@@ -0,0 +1,58 @@
+#include "driver.h"
+#include <avr/interrupt.h>
+#include <util/delay.h>
+
+
+namespace driver
+{   
+    namespace {
+        Mrf24j *mrf;
+    }
+    void init(Mrf24j *mrf) {
+        driver::mrf = mrf;
+        SPI_PORT |= (1<<SPI_CS); //set chip select pin high
+        SPI_DDR |= (1<<SPI_SCK)|(1<<SPI_MOSI)|(1<<SPI_CS); // spi sck mosi and chip select outputs
+        RESET_PORT |= (1<<RESET);
+        RESET_DDR |= (1<<RESET);
+        SPCR |= (1<<SPE)|(1<<MSTR)|(1<<SPR0); //enable SPI , Master, fck/16
+        #ifdef WAKE_PORT
+        WAKE_PORT &= ~(1<<WAKE_PIN);
+        WAKE_DDR |= (1<<WAKE_PIN);
+        #endif
+        #if defined __AVR_ATmega328P__
+        EICRA |= (1<<ISC01);
+        EIMSK |= (1<<INT0);
+        SPSR |= (1<< SPI2X); // FOSC/2
+        #elif defined __AVR_ATmega32__
+        GICR |= (1<<INT2);
+
+        #endif
+        sei();
+    }
+
+    uint8_t transfer(uint8_t data) {
+        SPDR = data;
+        while(!(SPSR & (1<<SPIF))); //wait for transmition to complete
+        return SPDR;
+    }
+    void reset() {
+        RESET_PORT &= ~(1<<RESET);
+        _delay_ms(10);
+        RESET_PORT |= (1<<RESET);
+        _delay_ms(20);
+    }
+
+    void wake() {
+        #ifdef WAKE_PORT
+        WAKE_PORT |= (1<<WAKE_PIN);
+        _delay_ms(1);
+        WAKE_PORT &= ~(1<<WAKE_PIN);
+        #endif
+    }
+
+    INTERRUPT {
+        mrf->interrupt_handler(); // mrf24 object interrupt routine
+        mrf->check_flags();
+    }
+}
+    
diff --git a/src/driver.h b/src/driver.h
new file mode 100644
index 0000000..32e7101
--- /dev/null
+++ b/src/driver.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#include <avr/io.h>
+#include "mrf24j.h"
+
+
+#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 INTERRUPT ISR(INT2_vect)
+#elif defined RASPBERRYPI
+
+#endif
+
+namespace driver
+{
+    void init(Mrf24j *mrf);
+    uint8_t transfer(uint8_t data);
+  
+    inline void cs_low() {SPI_PORT &= ~(1<<SPI_CS);}
+
+    inline void cs_high() {SPI_PORT |= (1<<SPI_CS);}
+    void wake();
+    void reset();
+} // namespace spi
diff --git a/src/mrf24j.cpp b/src/mrf24j.cpp
new file mode 100644
index 0000000..b720cd6
--- /dev/null
+++ b/src/mrf24j.cpp
@@ -0,0 +1,348 @@
+/**
+ * mrf24j.cpp, Karl Palsson, 2011, karlp@tweak.net.au
+ * modified bsd license / apache license
+ */
+
+#include "mrf24j.h"
+#include "driver.h"
+#include <string.h>
+#include <util/delay.h>
+#include <avr/interrupt.h>
+
+// 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);
+}
+
+/**
+ * Simple send 16, with acks, not much of anything.. assumes src16 and local pan only.
+ * @param 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++, 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<<MRF_TXNACKREQ | 1<<MRF_TXNTRIG));
+}
+
+void Mrf24j::set_interrupts(void) {
+    // interrupts for rx and tx normal complete
+    write_short(MRF_INTCON, 0b11110110);
+}
+
+/** use the 802.15.4 channel numbers..
+ */
+void Mrf24j::set_channel(byte channel) {
+    write_long(MRF_RFCON0, (((channel - 11) << 4) | 0x03));
+}
+
+void Mrf24j::init(void) {
+    
+    // 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.
+
+    write_long(MRF_RFCON0, 0x03); // – Initialize RFOPT = 0x03.
+    write_long(MRF_RFCON1, 0x01); // – Initialize VCOOPT = 0x02.
+    write_long(MRF_RFCON2, 0x80); // – Enable PLL (PLLEN = 1).
+    write_long(MRF_RFCON6, 0x90); // – Initialize TXFIL = 1 and 20MRECVR = 1.
+    write_long(MRF_RFCON7, 0x80); // – Initialize SLPCLKSEL = 0x2 (100 kHz Internal oscillator).
+    write_long(MRF_RFCON8, 0x10); // – Initialize RFVCO = 1.
+    write_long(MRF_SLPCON1, 0x21); // – Initialize CLKOUTEN = 1 and SLPCLKDIV = 0x01.
+
+    //  Configuration for nonbeacon-enabled devices (see Section 3.8 “Beacon-Enabled and
+    //  Nonbeacon-Enabled Networks”):
+    write_short(MRF_BBREG2, 0x80); // Set CCA mode to ED
+    write_short(MRF_CCAEDTH, 0x60); // – Set CCA ED threshold.
+    write_short(MRF_BBREG6, 0x40); // – Set appended RSSI value to RXFIFO.
+    set_interrupts();
+    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_short(MRF_RFCTL, 0x04); //  – Reset RF state machine.
+    write_short(MRF_RFCTL, 0x00); // part 2
+    _delay_ms(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...
+        cli();
+        rx_disable();
+        // read start of rxfifo for, has 2 bytes more added by FCS. frame_length = m + n + 2
+        uint8_t frame_length = read_long(0x300);
+
+        // buffer all bytes in PHY Payload
+        if(bufPHY){
+            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;
+        // from (0x301 + bytes_MHR) to (0x301 + frame_length - bytes_nodata - 1)
+        for (int i = 0; i < rx_datalength(); i++) {
+            rx_info.rx_data[rd_ptr++] = read_long(0x301 + bytes_MHR + i);
+        }
+
+        rx_info.frame_length = frame_length;
+        // same as datasheet 0x301 + (m + n + 2) <-- frame_length
+        rx_info.lqi = read_long(0x301 + frame_length);
+        // same as datasheet 0x301 + (m + n + 3) <-- frame_length + 1
+        rx_info.rssi = read_long(0x301 + frame_length + 1);
+
+        rx_enable();
+        sei();
+    }
+    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(){
+    // 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);
+    _delay_ms(2); // 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 100644
index 0000000..1475b95
--- /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
+ */
+
+#include <avr/io.h>
+
+typedef uint8_t byte;
+typedef uint16_t 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 send16(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 100644
index 0000000..8637985
--- /dev/null
+++ b/test/rx/main.cpp
@@ -0,0 +1,68 @@
+/**
+ * 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 "../../lib/usart/src/usart.h"
+#include <avr/interrupt.h>
+#include <util/delay.h>
+
+Mrf24j mrf;
+
+void handle_rx();
+void handle_tx();
+
+int main() {
+  usart::init(1000000);
+  
+  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();
+
+  sei();
+  while(1) {
+    //printf("txxxing...\n\r");
+    //mrf.send16(0x4201, "abcd");
+    _delay_ms(5000);
+  }
+}
+
+
+
+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("%x", 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\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 100644
index 0000000..c3cc9f4
--- /dev/null
+++ b/test/tx/main.cpp
@@ -0,0 +1,78 @@
+/**
+ * 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 "../../lib/usart/src/usart.h"
+#include "../../src/driver.h"
+#include <avr/interrupt.h>
+#include <util/delay.h>
+
+
+
+Mrf24j mrf;
+
+void handle_rx();
+void handle_tx();
+
+int main() {
+  usart::init(1000000);
+  
+  mrf.reset();
+  mrf.init();
+  
+  mrf.set_pan(0xcafe);
+  // This is _our_ address
+  mrf.address16_write(0x4201); 
+  mrf.handlers(&handle_rx, &handle_tx);
+  //mrf.enable_wake();
+  mrf.set_bufferPHY(true);
+  mrf.turbo();
+  mrf.set_power(0b1100000);
+  //mrf.sleep();
+  sei();
+  while(1) {
+    printf("txxxing...\n\r");
+    //mrf.wake();
+    mrf.send16(0x4202, "Tx Hello");
+    
+    _delay_ms(2000);
+  }
+}
+
+
+
+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\n\r");
+    } else {
+        printf("TX failed after %i retries\n\n\r",  mrf.get_txinfo()->retries);
+    }
+    printf("Sleeping\n\r");
+    //mrf.sleep();
+}