diff --git a/radio/nrf24L01/nrf-ftdi-ring.c b/radio/nrf24L01/nrf-ftdi-ring.c
new file mode 100644
index 0000000000000000000000000000000000000000..f484375091d54571fd164ea1cac7e858dd1ed293
--- /dev/null
+++ b/radio/nrf24L01/nrf-ftdi-ring.c
@@ -0,0 +1,398 @@
+//
+// xmega spi for LIS3MDL, 3 axis magnetometer with Xmega 8E5
+// sec, 2016
+#ifndef F_CPU
+#define F_CPU 32000000UL
+#endif
+
+#include "serial.h"
+#include <avr/io.h>
+#include <util/delay.h>
+#include <avr/pgmspace.h>
+#include <avr/interrupt.h>
+
+#define SS_BM PIN4_bm
+#define CE_BM PIN0_bm
+#define IRQ_BM PIN2_bm
+
+//NRF24L01 registers
+//https://www.nordicsemi.com/eng/content/download/2726/34069/file/nrf24L01P_Product_Specification_1_0.pdf
+//Every new command must be started by a high to low transition on CSN.
+const uint8_t CONFIG = 0x00;
+const uint8_t EN_AA = 0x01;
+const uint8_t EN_RXADDR = 0x02;
+const uint8_t SETUP_AW = 0x03;
+const uint8_t SETUP_RETR = 0x04;
+const uint8_t RF_CH = 0x05;
+const uint8_t RF_SETUP = 0x06;
+const uint8_t STATUS = 0x07;
+const uint8_t OBSERVE_TX = 0x08;
+const uint8_t RPD = 0x09;
+const uint8_t RX_ADDR_P0 = 0x0A;
+const uint8_t RX_ADDR_P1 = 0x0B;
+const uint8_t RX_ADDR_P2 = 0x0C;
+const uint8_t RX_ADDR_P3 = 0x0D;
+const uint8_t RX_ADDR_P4 = 0x0E;
+const uint8_t RX_ADDR_P5 = 0x0F;
+const uint8_t TX_ADDR = 0x10;
+const uint8_t RX_PW_P0 = 0x11;
+const uint8_t RX_PW_P1 = 0x12;
+const uint8_t RX_PW_P2 = 0x13;
+const uint8_t RX_PW_P3 = 0x14;
+const uint8_t RX_PW_P4 = 0x15;
+const uint8_t RX_PW_P5 = 0x16;
+const uint8_t FIFO_STATUS = 0x17;
+const uint8_t DYNPD = 0x1C;
+const uint8_t FEATURE = 0x1D;
+
+const uint8_t PWR_UP = 1 << 1;
+const uint8_t PRIM_RX = 1 << 0;
+const uint8_t R_REGISTER = 0;
+const uint8_t W_REGISTER = 1<<5;
+const uint8_t R_RX_PAYLOAD = (1<<6) | (1<<5) | 1;
+const uint8_t W_TX_PAYLOAD = (1<<7) | (1<<5);
+const uint8_t FLUSH_TX = (1<<7) | (1<<6) | (1<<5) | 1;
+const uint8_t FLUSH_RX = (1<<7) | (1<<6) | (1<<5) | (1<<1);
+const uint8_t MAX_RT = 1<<4;
+const uint8_t TX_DS = 1<<5; //tx data sent interrupt
+const uint8_t RX_DR = 1<<6; //rx data ready interrupt
+
+
+uint8_t read_register(uint8_t reg){
+   PORTC.OUTCLR = SS_BM; //SS low      
+   _delay_ms(1);  //give time after ss low 
+   SPIC.DATA = R_REGISTER | reg; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   SPIC.DATA = 0; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   uint8_t temp = SPIC.DATA;
+   PORTC.OUTSET = SS_BM; //SS high
+   _delay_ms(1);  //give time after ss high
+   return temp;
+}
+
+
+
+USART_data_t USART_data;
+
+uint8_t token = 0; //token to pass
+uint8_t tempval = 0;
+
+void check_registers(){
+   //enter standby so we can write to configuration register.
+   PORTC.OUTCLR = CE_BM; 
+   _delay_us(10);
+
+   //read registers for debug
+   PORTC.OUTCLR = SS_BM; //SS low  
+   _delay_us(10);            
+   SPIC.DATA = R_REGISTER | EN_AA; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   uint8_t status = SPIC.DATA;
+   SPIC.DATA = 0; while(!(SPIC.STATUS & SPI_IF_bm)) {};  //read
+   uint8_t en_aa = SPIC.DATA;
+   PORTC.OUTSET = SS_BM; //SS high
+   _delay_us(10);            
+
+   PORTC.OUTCLR = SS_BM; //SS low  
+   _delay_us(10);            
+   SPIC.DATA = R_REGISTER | CONFIG; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   SPIC.DATA = 0; while(!(SPIC.STATUS & SPI_IF_bm)) {};  //read
+   uint8_t config = SPIC.DATA;
+   PORTC.OUTSET = SS_BM; //SS high
+   _delay_us(10); 
+
+   PORTC.OUTCLR = SS_BM; //SS low  
+   _delay_us(10);            
+   SPIC.DATA = R_REGISTER | SETUP_RETR; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   SPIC.DATA = 0; while(!(SPIC.STATUS & SPI_IF_bm)) {};  //read
+   uint8_t setup_retr = SPIC.DATA;
+   PORTC.OUTSET = SS_BM; //SS high
+   _delay_us(10); 
+
+   usart_send_byte(&USART_data,status);
+   usart_send_byte(&USART_data,config);
+   usart_send_byte(&USART_data,en_aa);
+   usart_send_byte(&USART_data,setup_retr);
+   usart_send_byte(&USART_data,token);
+   usart_send_byte(&USART_data,10);
+
+   //interrupts
+   /*if (!(PORTC.IN & IRQ_BM)){
+      usart_send_byte(&USART_data,1);
+   } 
+   //clear interrupt on MAX_RT
+   PORTC.OUTCLR = SS_BM; //SS low  
+   _delay_ms(1);            
+   SPIC.DATA = W_REGISTER | STATUS; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   SPIC.DATA |= MAX_RT; while(!(SPIC.STATUS & SPI_IF_bm)) {};  //write 1 to MAX_RT bit
+   PORTC.OUTSET = SS_BM; //SS high
+   _delay_ms(1);
+   //interrupts
+   if (!(PORTC.IN & IRQ_BM)){
+      usart_send_byte(&USART_data,2);
+   }*/
+}
+
+// nRF24L01+ must be in a standby or power down mode before writing to the configuration registers. 
+
+//overview
+// - turn off autoretransmit
+// - MAX_RT interrupts on IRQ
+// - set interrupt service routine on rising edge of IRQ (RX_DR)
+// - set interrupt service routing on USART RX
+// - enter RX mode PRIM_RX = 1 (SPI transaction), CE = 1
+// - When IRQ interupt, 
+//    - enter standby (CE=0)
+//    - read payload (SPI transaction)
+//    - process data and put result in TX fifo 
+//    - enter TX (PRIM_RX=0, CE=1 for more than 10 us) (130us)
+//    - clear IRQ by writing 1 to STATUS register RX_DR bit. (SPI transaction)
+//    - set CE=0 so we return to Standby when finished transmitting
+//    - set PRIM_RX=1 (SPI transaction).  can we only do this from standby? (130us)
+// - When USART interrupt,
+//    - enter standby (CE=0)
+//    - put token in TX fifo 
+//    - enter TX (PRIM_RX=0, CE=1 for more than 10 us)
+//    - set CE=0 so we return to Standby when finished transmitting
+//    - set PRIM_RX=1 (SPI transaction) to enter RX can we only do this from standby? (130us)
+
+//experiments
+// RF_SETUP, RF_DR_LOW, RF_DR_HIGH.  Default RF data rate is 250kbps ( 4 us per byte ).  
+// It can also be 1 Mbps (1 us per byte) and 2 Mbps (.5 us per byte)
+// increase SPI rate.  right now its running at clkper/128 = sysclk/128 = 250 kHz (4 us per byte)
+
+
+void rx_from_standby(){
+   //enter standby so we can write to configuration register.
+   PORTC.OUTCLR = CE_BM; 
+   _delay_us(10);
+
+   //enter RX mode: set PRIM_RX = 1
+   tempval = read_register(CONFIG);
+   PORTC.OUTCLR = SS_BM; //SS low      
+   SPIC.DATA = W_REGISTER | CONFIG; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   SPIC.DATA = tempval | PRIM_RX; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   PORTC.OUTSET = SS_BM; //SS high
+   _delay_ms(1);  //give time to start up   
+
+   //set CE for at least 10 us 
+   PORTC.OUTSET = CE_BM;
+   _delay_us(10);
+
+   //wait for pll to settle
+   _delay_us(130);
+}
+
+void setup(){
+   // set up clock
+   OSC.CTRL = OSC_RC32MEN_bm; // enable 32MHz clock
+   while (!(OSC.STATUS & OSC_RC32MRDY_bm)); // wait for clock to be ready
+   CCP = CCP_IOREG_gc; // enable protected register change
+   CLK.CTRL = CLK_SCLKSEL_RC32M_gc; // switch to 32MHz clock
+
+   //set up usart
+   PORTD.DIRSET = PIN3_bm; //TXD0
+   PORTD.DIRCLR = PIN2_bm; //RXD0
+   USART_InterruptDriver_Initialize(&USART_data, &USARTD0, USART_DREINTLVL_LO_gc);
+   USART_Format_Set(USART_data.usart, USART_CHSIZE_8BIT_gc,
+                     USART_PMODE_DISABLED_gc, 0);
+   USART_RxdInterruptLevel_Set(USART_data.usart, USART_RXCINTLVL_LO_gc);
+   //take f_sysclk/(BSEL+1) ~= f_baud*16 with zero scale.  See manual or spreadsheet for scale defs
+   USART_Baudrate_Set(&USARTD0, 123 , -4); //230400 baud with .08% error
+   USART_Rx_Enable(USART_data.usart);
+   USART_Tx_Enable(USART_data.usart);
+   //enable interrupts
+   PMIC.CTRL |= PMIC_LOLVLEX_bm;
+
+   
+   PORTC.DIRSET = SS_BM; //set up SS pin on PC4
+   PORTC.PIN4CTRL = PORT_OPC_WIREDANDPULL_gc; //wired AND and pull-up on SS
+   PORTC.PIN2CTRL = PORT_OPC_PULLUP_gc; //pull-up on IRQ
+   PORTC.DIRSET = CE_BM; //set up CE pin on PC0
+   //set up spic.ctrl
+   SPIC.CTRL   = SPI_PRESCALER_DIV128_gc |        /* SPI prescaler. */
+                         (0 ? SPI_CLK2X_bm : 0) |    /* SPI Clock double. */
+                         SPI_ENABLE_bm |                 /* Enable SPI module. */
+                         SPI_MASTER_bm |                 /* SPI master. */
+                         SPI_MODE_0_gc; //bits driven at falling edge, sampled at rising edge  
+   SPIC.INTCTRL = SPI_INTLVL_OFF_gc;
+   PORTC.DIRSET = PIN5_bm | PIN7_bm; //mosi and sck as outputs
+   PORTC.OUTSET = SS_BM; //SS high   
+
+   _delay_ms(5); //warm up
+
+
+   //turn off auto-retransmit
+   PORTC.OUTCLR = SS_BM; //SS low      
+   SPIC.DATA = W_REGISTER | SETUP_RETR; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   SPIC.DATA = 0 ; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   PORTC.OUTSET = SS_BM; //SS high   
+   _delay_ms(1);
+
+   //turn off disable auto-acknowledge
+   PORTC.OUTCLR = SS_BM; //SS low      
+   SPIC.DATA = W_REGISTER | EN_AA; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   SPIC.DATA = 0 ; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   PORTC.OUTSET = SS_BM; //SS high   
+   _delay_ms(1);
+
+   //set the PWR_UP bit in the CONFIG register to 1 to enter standby mode
+   PORTC.OUTCLR = SS_BM; //SS low      
+   SPIC.DATA = W_REGISTER | CONFIG; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   SPIC.DATA = PWR_UP; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   PORTC.OUTSET = SS_BM; //SS high
+   _delay_ms(1);  //give time to start up 
+
+   //set up data pipe 0 
+   PORTC.OUTCLR = SS_BM; //SS low      
+   SPIC.DATA = W_REGISTER | EN_RXADDR; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   SPIC.DATA = 1; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   PORTC.OUTSET = SS_BM; //SS high
+   _delay_ms(1);  //give time to start up 
+
+   //set data pipe 0 payload length to 1
+   PORTC.OUTCLR = SS_BM; //SS low      
+   SPIC.DATA = W_REGISTER | RX_PW_P0; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   SPIC.DATA = 1; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   PORTC.OUTSET = SS_BM; //SS high
+   _delay_ms(1);  //give time to start up 
+
+   //flush tx
+   PORTC.OUTCLR = SS_BM; //SS low      
+   SPIC.DATA = FLUSH_TX; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   PORTC.OUTSET = SS_BM; //SS high
+   _delay_ms(1);  //give time to start up 
+   //flush rx
+   PORTC.OUTCLR = SS_BM; //SS low      
+   SPIC.DATA = FLUSH_TX; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   PORTC.OUTSET = SS_BM; //SS high
+   _delay_ms(1);  //give time to start up 
+
+   // and mask MAX_RT interrupts on IRQ
+   tempval = read_register(CONFIG);
+   PORTC.OUTCLR = SS_BM; //SS low      
+   SPIC.DATA = W_REGISTER | CONFIG; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   SPIC.DATA = tempval | MAX_RT; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   PORTC.OUTSET = SS_BM; //SS high
+   _delay_ms(1);  //give time to start up 
+   
+   //clear all interrupts
+   tempval = read_register(STATUS);
+   PORTC.OUTCLR = SS_BM; //SS low      
+   SPIC.DATA = W_REGISTER | STATUS; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   SPIC.DATA = tempval | MAX_RT | RX_DR | TX_DS; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   PORTC.OUTSET = SS_BM; //SS high
+   _delay_ms(1);  //give time to start up 
+
+   //
+
+   sei();
+
+   rx_from_standby();
+
+}
+
+
+// NOTE: we can't do SPIC.DATA &= or |= thing because SPIC.DATA will hold STATUS!!!
+
+
+void send_token(){
+   //transition from RX to standby1 (CE=0)
+   PORTC.OUTCLR = CE_BM;   
+   _delay_us(10);
+
+   //put token in tx fifo
+   PORTC.OUTCLR = SS_BM; //SS low
+   _delay_ms(1);           
+   SPIC.DATA = W_TX_PAYLOAD; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   SPIC.DATA = token; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   PORTC.OUTSET = SS_BM; //SS high
+   _delay_ms(1); 
+
+   check_registers();      
+
+   tempval = read_register(CONFIG);
+   PORTC.OUTCLR = SS_BM; //SS low  
+   _delay_ms(1);            
+   SPIC.DATA = W_REGISTER | CONFIG; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   SPIC.DATA = tempval & (~PRIM_RX); while(!(SPIC.STATUS & SPI_IF_bm)) {};  //make sure PRIM_RX is low
+   PORTC.OUTSET = SS_BM; //SS high
+   _delay_ms(1);
+
+   check_registers();      
+
+   //pulse CE for at least 10 us 
+   PORTC.OUTSET = CE_BM; _delay_us(15); PORTC.OUTCLR = CE_BM;
+
+   //wait for pll to settle
+   _delay_us(130);
+
+   //wait until transmit complete
+   usart_send_byte(&USART_data,68); usart_send_byte(&USART_data,10); //for debug on usart   
+   while( PORTC.IN & IRQ_BM ){}
+   usart_send_byte(&USART_data,69); usart_send_byte(&USART_data,10); //for debug on usart         
+   
+   //clear IRQ -- need to be in standby.
+   tempval = read_register(STATUS);
+   PORTC.OUTCLR = SS_BM; //SS low  
+   _delay_ms(1);            
+   SPIC.DATA = W_REGISTER | STATUS; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   SPIC.DATA = tempval | TX_DS; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   PORTC.OUTSET = SS_BM; //SS high
+   _delay_ms(1);
+
+   rx_from_standby(); //return to RX mode
+}
+
+void read_token(){
+   check_registers();
+   //get token from rx fifo
+   PORTC.OUTCLR = SS_BM; //SS low
+   _delay_ms(1);           
+   SPIC.DATA = R_RX_PAYLOAD; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   SPIC.DATA = 0; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   token = SPIC.DATA;
+   PORTC.OUTSET = SS_BM; //SS high
+   _delay_ms(1); 
+
+   //transition from RX to standby1 (CE=0)
+   PORTC.OUTCLR = CE_BM;   
+   _delay_us(10);
+
+   //clear IRQ
+   tempval = read_register(STATUS);
+   PORTC.OUTCLR = SS_BM; //SS low  
+   _delay_ms(1);            
+   SPIC.DATA = W_REGISTER | STATUS; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   SPIC.DATA = tempval | RX_DR; while(!(SPIC.STATUS & SPI_IF_bm)) {};
+   PORTC.OUTSET = SS_BM; //SS high
+   _delay_ms(1);
+   usart_send_byte(&USART_data,255); usart_send_byte(&USART_data,10); //for debug on usart         
+   check_registers();
+}
+
+int main(void) {
+   setup();
+   while(1){
+      //should be in rx mode here.
+      if ( !(PORTC.IN & IRQ_BM)){
+         usart_send_byte(&USART_data,70); usart_send_byte(&USART_data,10);
+         read_token(); //in standby
+         token = 1-token; //transform token
+         send_token(); //in rx
+         usart_send_byte(&USART_data,66); usart_send_byte(&USART_data,10); //for debug on usart         
+      }
+      
+      //when we get signal from usart, send a token on nrf
+      if (USART_RXBufferData_Available(&USART_data)) {
+         usart_send_byte(&USART_data,64); usart_send_byte(&USART_data,10); //for debug on usart
+         USART_RXBuffer_GetByte(&USART_data); //clear usart buffer so we only fire once.
+         check_registers();
+         send_token(); //in rx
+         usart_send_byte(&USART_data,65); usart_send_byte(&USART_data,10); //for debug on usart
+      }
+      _delay_ms(1000);
+   }
+}
+
+
+ISR(USARTD0_RXC_vect){USART_RXComplete(&USART_data);}
+ISR(USARTD0_DRE_vect){USART_DataRegEmpty(&USART_data);}
diff --git a/radio/nrf24L01/nrf-ftdi-ring.make b/radio/nrf24L01/nrf-ftdi-ring.make
new file mode 100644
index 0000000000000000000000000000000000000000..453d446ab4681c82bb7a043e7190ba1f620aef7e
--- /dev/null
+++ b/radio/nrf24L01/nrf-ftdi-ring.make
@@ -0,0 +1,19 @@
+PROJECT=nrf-ftdi-ring
+SOURCES=$(PROJECT).c
+MMCU=atxmega8e5
+F_CPU = 32000000
+TARGET = x8e5
+PROGRAMMER= atmelice_pdi
+
+CFLAGS=-mmcu=$(MMCU) -Wall -Os -DF_CPU=$(F_CPU)
+
+$(PROJECT).hex: $(PROJECT).out
+	avr-objcopy -O ihex $(PROJECT).out $(PROJECT).c.hex;\
+	avr-size --mcu=$(MMCU) --format=avr $(PROJECT).out
+ 
+$(PROJECT).out: $(SOURCES)
+	avr-gcc $(CFLAGS) -I./ -o $(PROJECT).out $(SOURCES)
+ 
+program: $(PROJECT).hex
+	avrdude -p $(TARGET) -c $(PROGRAMMER) -U flash:w:$(PROJECT).c.hex
+
diff --git a/radio/nrf24L01/serial-monitor.py b/radio/nrf24L01/serial-monitor.py
new file mode 100644
index 0000000000000000000000000000000000000000..54bfb554915a54b599bf57f836cd6a9ab04e678e
--- /dev/null
+++ b/radio/nrf24L01/serial-monitor.py
@@ -0,0 +1,23 @@
+import serial,sys
+
+serial_ports = ["/dev/tty.usbserial-FTFMIM12", "/dev/tty.usbserial-FT9L39VL"]
+
+ser = serial.Serial(serial_ports[int(sys.argv[1])], 230400)
+print "connecting"
+labels = ['status','config','en_aa','setup_retr','token']
+while True:
+	try:
+		print "writing to usart"
+		ser.write([0])
+		bytes = map(ord,ser.readline().strip('\n'))
+		#print "read: ",bytes
+		print bytes
+		print "Registers:"
+		for l,b in zip(labels,bytes):
+			print '\t',l,format(b, '08b')
+		#if len(labels) != len(bytes):
+		#	print bytes[len(labels):]
+	except(KeyboardInterrupt):
+		break
+print "Quitting"
+ser.close()
\ No newline at end of file
diff --git a/radio/nrf24L01/serial.h b/radio/nrf24L01/serial.h
new file mode 100644
index 0000000000000000000000000000000000000000..4d7312a5ca4cbc6b7815e702b2d655cff1ebd21a
--- /dev/null
+++ b/radio/nrf24L01/serial.h
@@ -0,0 +1,227 @@
+#include <avr/io.h>
+#include <util/delay.h>
+#include <avr/pgmspace.h>
+
+#define output(directions,pin) (directions |= pin) // set port direction for output
+#define set(port,pin) (port |= pin) // set port pin
+#define clear(port,pin) (port &= (~pin)) // clear port pin
+#define pin_test(pins,pin) (pins & pin) // test for port pin
+#define bit_test(byte,bit) (byte & (1 << bit)) // test for bit set
+
+/* USART buffer defines. */
+/* \brief  Receive buffer size: 2,4,8,16,32,64,128 or 256 bytes. */
+#define USART_RX_BUFFER_SIZE 128
+/* \brief Transmit buffer size: 2,4,8,16,32,64,128 or 256 bytes */
+#define USART_TX_BUFFER_SIZE 128
+/* \brief Receive buffer mask. */
+#define USART_RX_BUFFER_MASK ( USART_RX_BUFFER_SIZE - 1 )
+/* \brief Transmit buffer mask. */
+#define USART_TX_BUFFER_MASK ( USART_TX_BUFFER_SIZE - 1 )
+
+#if ( USART_RX_BUFFER_SIZE & USART_RX_BUFFER_MASK )
+#error RX buffer size is not a power of 2
+#endif
+#if ( USART_TX_BUFFER_SIZE & USART_TX_BUFFER_MASK )
+#error TX buffer size is not a power of 2
+#endif
+
+/* \brief USART transmit and receive ring buffer. */
+typedef struct USART_Buffer
+{
+   /* \brief Receive buffer. */
+   volatile uint8_t RX[USART_RX_BUFFER_SIZE];
+   /* \brief Transmit buffer. */
+   volatile uint8_t TX[USART_TX_BUFFER_SIZE];
+   /* \brief Receive buffer head. */
+   volatile uint8_t RX_Head;
+   /* \brief Receive buffer tail. */
+   volatile uint8_t RX_Tail;
+   /* \brief Transmit buffer head. */
+   volatile uint8_t TX_Head;
+   /* \brief Transmit buffer tail. */
+   volatile uint8_t TX_Tail;
+} USART_Buffer_t;
+
+
+/*! \brief Struct used when interrupt driven driver is used.
+*
+*  Struct containing pointer to a usart, a buffer and a location to store Data
+*  register interrupt level temporary.
+*/
+typedef struct Usart_and_buffer
+{
+   /* \brief Pointer to USART module to use. */
+   USART_t * usart;
+   /* \brief Data register empty interrupt level. */
+   USART_DREINTLVL_t dreIntLevel;
+   /* \brief Data buffer. */
+   USART_Buffer_t buffer;
+} USART_data_t;
+
+#define USART_RxdInterruptLevel_Set(_usart, _rxdIntLevel)                      \
+   ((_usart)->CTRLA = ((_usart)->CTRLA & ~USART_RXCINTLVL_gm) | _rxdIntLevel)
+#define USART_Format_Set(_usart, _charSize, _parityMode, _twoStopBits)         \
+   (_usart)->CTRLC = (uint8_t) _charSize | _parityMode |                      \
+                     (_twoStopBits ? USART_SBMODE_bm : 0)
+#define USART_Baudrate_Set(_usart, _bselValue, _bScaleFactor)                  \
+   (_usart)->BAUDCTRLA =(uint8_t)_bselValue;                                           \
+   (_usart)->BAUDCTRLB =(_bScaleFactor << USART_BSCALE0_bp)|(_bselValue >> 8)
+#define USART_Rx_Enable(_usart) ((_usart)->CTRLB |= USART_RXEN_bm)
+#define USART_Rx_Disable(_usart) ((_usart)->CTRLB &= ~USART_RXEN_bm)
+#define USART_Tx_Enable(_usart)  ((_usart)->CTRLB |= USART_TXEN_bm)
+#define USART_Tx_Disable(_usart) ((_usart)->CTRLB &= ~USART_TXEN_bm)
+
+
+
+_Bool USART_TXBuffer_FreeSpace(USART_data_t * usart_data)
+{
+   /* Make copies to make sure that volatile access is specified. */
+   uint8_t tempHead = (usart_data->buffer.TX_Head + 1) & USART_TX_BUFFER_MASK;
+   uint8_t tempTail = usart_data->buffer.TX_Tail;
+
+   /* There are data left in the buffer unless Head and Tail are equal. */
+   return (tempHead != tempTail);
+}
+_Bool USART_TXBuffer_PutByte(USART_data_t * usart_data, uint8_t data)
+{
+   uint8_t tempCTRLA;
+   uint8_t tempTX_Head;
+   _Bool TXBuffer_FreeSpace;
+   USART_Buffer_t * TXbufPtr;
+
+   TXbufPtr = &usart_data->buffer;
+   TXBuffer_FreeSpace = USART_TXBuffer_FreeSpace(usart_data);
+
+
+   if(TXBuffer_FreeSpace)
+   {
+      tempTX_Head = TXbufPtr->TX_Head;
+      TXbufPtr->TX[tempTX_Head]= data;
+      /* Advance buffer head. */
+      TXbufPtr->TX_Head = (tempTX_Head + 1) & USART_TX_BUFFER_MASK;
+
+      /* Enable DRE interrupt. */
+      tempCTRLA = usart_data->usart->CTRLA;
+      tempCTRLA = (tempCTRLA & ~USART_DREINTLVL_gm) | usart_data->dreIntLevel;
+      usart_data->usart->CTRLA = tempCTRLA;
+   }
+   return TXBuffer_FreeSpace;
+}
+_Bool USART_RXBufferData_Available(USART_data_t * usart_data)
+{
+   /* Make copies to make sure that volatile access is specified. */
+   uint8_t tempHead = usart_data->buffer.RX_Head;
+   uint8_t tempTail = usart_data->buffer.RX_Tail;
+
+   /* There are data left in the buffer unless Head and Tail are equal. */
+   return (tempHead != tempTail);
+}
+uint8_t USART_RXBuffer_GetByte(USART_data_t * usart_data)
+{
+   USART_Buffer_t * bufPtr;
+   uint8_t ans;
+   bufPtr = &usart_data->buffer;
+   ans = (bufPtr->RX[bufPtr->RX_Tail]);
+
+   /* Advance buffer tail. */
+   bufPtr->RX_Tail = (bufPtr->RX_Tail + 1) & USART_RX_BUFFER_MASK;
+   return ans;
+}
+_Bool USART_RXComplete(USART_data_t * usart_data)
+{
+   USART_Buffer_t * bufPtr;
+   _Bool ans;
+
+   bufPtr = &usart_data->buffer;
+   /* Advance buffer head. */
+   uint8_t tempRX_Head = (bufPtr->RX_Head + 1) & USART_RX_BUFFER_MASK;
+
+   /* Check for overflow. */
+   uint8_t tempRX_Tail = bufPtr->RX_Tail;
+   uint8_t data = usart_data->usart->DATA;
+
+   if (tempRX_Head == tempRX_Tail) {
+      ans = 0;
+   }else{
+      ans = 1;
+      usart_data->buffer.RX[usart_data->buffer.RX_Head] = data;
+      usart_data->buffer.RX_Head = tempRX_Head;
+   }
+   return ans;
+}
+void USART_DataRegEmpty(USART_data_t * usart_data)
+{
+   USART_Buffer_t * bufPtr;
+   bufPtr = &usart_data->buffer;
+
+   /* Check if all data is transmitted. */
+   uint8_t tempTX_Tail = usart_data->buffer.TX_Tail;
+   if (bufPtr->TX_Head == tempTX_Tail){
+       /* Disable DRE interrupts. */
+      uint8_t tempCTRLA = usart_data->usart->CTRLA;
+      tempCTRLA = (tempCTRLA & ~USART_DREINTLVL_gm) | USART_DREINTLVL_OFF_gc;
+      usart_data->usart->CTRLA = tempCTRLA;
+
+   }else{
+      /* Start transmitting. */
+      uint8_t data = bufPtr->TX[usart_data->buffer.TX_Tail];
+      usart_data->usart->DATA = data;
+
+      /* Advance buffer tail. */
+      bufPtr->TX_Tail = (bufPtr->TX_Tail + 1) & USART_TX_BUFFER_MASK;
+   }
+}
+void USART_InterruptDriver_Initialize(USART_data_t * usart_data,
+                                      USART_t * usart,
+                                      USART_DREINTLVL_t dreIntLevel)
+{
+   usart_data->usart = usart;
+   usart_data->dreIntLevel = dreIntLevel;
+
+   usart_data->buffer.RX_Tail = 0;
+   usart_data->buffer.RX_Head = 0;
+   usart_data->buffer.TX_Tail = 0;
+   usart_data->buffer.TX_Head = 0;
+}
+void USART_InterruptDriver_DreInterruptLevel_Set(USART_data_t * usart_data,
+                                                 USART_DREINTLVL_t dreIntLevel)
+{
+   usart_data->dreIntLevel = dreIntLevel;
+}
+
+void usart_send_byte(USART_data_t * usart_data, char msg){
+   while(!USART_TXBuffer_FreeSpace(usart_data)){}
+   USART_TXBuffer_PutByte(usart_data,msg);
+}
+void usart_send_uint32(USART_data_t * usart_data, uint32_t n){
+   unsigned char * nn = (unsigned char *)&n;
+   usart_send_byte(usart_data, nn[0] );
+   usart_send_byte(usart_data, nn[1] );
+   usart_send_byte(usart_data, nn[2] );
+   usart_send_byte(usart_data, nn[3] );
+}
+void usart_send_int32(USART_data_t * usart_data, int32_t n){
+   unsigned char * nn = ( unsigned char *)&n;
+   usart_send_byte(usart_data, nn[0] );
+   usart_send_byte(usart_data, nn[1] );
+   usart_send_byte(usart_data, nn[2] );
+   usart_send_byte(usart_data, nn[3] );   
+}
+uint32_t parse_uint32(char* b){return *(uint32_t *) b;}
+int32_t parse_int32(char* b){return *(int32_t *) b;}
+uint16_t parse_uint16(char* b){return *(uint16_t *) b;}
+
+
+/*
+void usart_write_buffer(char* buffer){
+   //write \n terminated buffer over usart
+   int j=0;
+   do{
+      usart_send_byte( buffer[j] );
+      j++;
+   } while( j < PACKET_SIZE);
+   //} while( buffer[j-1] != 10);
+}
+*/
+
+