Prototype RF driver for STM Sub-1 GHz RF expansion board based on the SPSGRF-868 module for STM32 Nucleo.

Prototype RF Driver for STM Sub-1 GHz RF Expansion Boards based on the SPSGRF-868 and SPSGRF-915 Modules for STM32 Nucleo

Currently supported boards:

Note, in order to use expansion board X-NUCLEO-IDS01A4 in mbed you need to perform the following HW modifications on the board:

  • Unmount resistor R4
  • Mount resistor R7

Furthermore, on some Nucleo development boards (e.g. the NUCLEO_F429ZI), in order to be able to use Ethernet together with these Sub-1 GHz RF expansion boards, you need to compile this driver with macro SPIRIT1_SPI_MOSI=PB_5 defined, while the development board typically requires some HW modification as e.g. described here!

This driver can be used together with the 6LoWPAN stack (a.k.a. Nanostack).

Files at this revision

API Documentation at this revision

Comitter:
Wolfgang Betz
Date:
Fri Oct 28 14:14:03 2016 +0200
Parent:
11:b769d6caad82
Child:
13:739d89e71f31
Commit message:
Add thread for sending ACK's

Changed in this revision

SimpleSpirit1.cpp Show annotated file Show diff for this revision Revisions of this file
SimpleSpirit1.h Show annotated file Show diff for this revision Revisions of this file
mbed_driver_api.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/SimpleSpirit1.cpp	Wed Oct 26 15:08:44 2016 +0200
+++ b/SimpleSpirit1.cpp	Fri Oct 28 14:14:03 2016 +0200
@@ -83,7 +83,6 @@
     packet_is_prepared = 0;
     just_got_an_ack = 0;
 #endif // CONTIKI
-    receiving_packet = 0;
     last_rssi = 0 ; //MGR
     last_lqi = 0 ;  //MGR
 
@@ -133,11 +132,11 @@
     irq_clear_status();
     irq_set_status(TX_DATA_SENT, S_ENABLE);
     irq_set_status(RX_DATA_READY,S_ENABLE);
-    irq_set_status(VALID_SYNC,S_ENABLE);
     irq_set_status(RX_DATA_DISC, S_ENABLE);
     irq_set_status(TX_FIFO_ERROR, S_ENABLE);
     irq_set_status(RX_FIFO_ERROR, S_ENABLE);
     irq_set_status(RX_FIFO_ALMOST_FULL, S_ENABLE);
+    irq_set_status(VALID_SYNC, S_ENABLE);
 
     /* Configure Spirit1 */
     radio_persisten_rx(S_ENABLE);
@@ -155,6 +154,7 @@
     CLEAR_RXBUF();
     _spirit_tx_started = false;
     _spirit_rx_err = false;
+    _is_receiving = false;
 
     /* Configure the radio to route the IRQ signal to its GPIO 3 */
     SGpioInit x_gpio_init = {
@@ -325,10 +325,11 @@
 
   disable_spirit_irq();
 
+  _is_receiving = false;
+
   if(SPIRIT1_STATUS() == SPIRIT1_STATE_STANDBY) {
 	  cmd_strobe(SPIRIT1_STROBE_READY);
   } else if(SPIRIT1_STATUS() == SPIRIT1_STATE_RX) {
-	  receiving_packet = 0;
 	  cmd_strobe(SPIRIT1_STROBE_SABORT);
   }
   irq_clear_status();
@@ -345,7 +346,6 @@
     disable_spirit_irq();
 
     /* first stop rx/tx */
-	receiving_packet = 0;
     cmd_strobe(SPIRIT1_STROBE_SABORT);
 
     /* Clear any pending irqs */
@@ -368,6 +368,8 @@
     spirit_on = OFF;
     _nr_of_irq_disables = 1;
     _spirit_tx_started = false;
+    _is_receiving = false;
+
     CLEAR_TXBUF();
     CLEAR_RXBUF();
   }
@@ -399,8 +401,8 @@
       //return 1;
     }
     CLEAR_RXBUF();
-	receiving_packet = 0;
     _spirit_rx_err = false;
+    _is_receiving = false;
 
     /* Enables the mcu to get IRQ from the SPIRIT1 */
     spirit_on = ON;
@@ -442,7 +444,6 @@
   /* Checks if the RX buffer is empty */
   if(IS_RXBUF_EMPTY()) {
     CLEAR_RXBUF();
-	receiving_packet = 0;
     cmd_strobe(SPIRIT1_STROBE_SABORT);
     wait_us(SABORT_WAIT_US);
     cmd_strobe(SPIRIT1_STROBE_READY);
@@ -451,6 +452,7 @@
     cmd_strobe(SPIRIT1_STROBE_RX);
     BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_RX, 1);
     _spirit_rx_err = false;
+    _is_receiving = false;
     PRINTF("READ OUT RX BUF EMPTY\n");
     enable_spirit_irq();
     return 0;
@@ -472,6 +474,7 @@
 #endif
 
     bufsize = spirit_rx_len;
+    _is_receiving = false;
     CLEAR_RXBUF();
 
     enable_spirit_irq();
@@ -528,6 +531,7 @@
     BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_RX, 5);
     CLEAR_RXBUF();
     _spirit_rx_err = false;
+    _is_receiving = false;
     enable_spirit_irq();
   }
 
@@ -557,8 +561,8 @@
 
   /* Reception errors */
   if((x_irq_status.IRQ_RX_FIFO_ERROR) || (x_irq_status.IRQ_RX_DATA_DISC) || (x_irq_status.IRQ_RX_TIMEOUT)) {
-    receiving_packet = 0;
     _spirit_rx_err = true;
+    _is_receiving = false;
     CLEAR_RXBUF();
     cmd_strobe(SPIRIT1_STROBE_FRX);
     if(_spirit_tx_started) {
@@ -574,7 +578,7 @@
   /* Transmission error */
   if(x_irq_status.IRQ_TX_FIFO_ERROR) {
 	error("IRQ_TX_FIFO_ERROR should never happen!\n");
-    receiving_packet = 0;
+
     cmd_strobe(SPIRIT1_STROBE_FTX);
     if(_spirit_tx_started) {
     	_spirit_tx_started = false;
@@ -588,28 +592,21 @@
 
   /* The IRQ_VALID_SYNC is used to notify a new packet is coming */
   if(x_irq_status.IRQ_VALID_SYNC) {
-    receiving_packet = 1;
-    _spirit_rx_err = false;
-    CLEAR_RXBUF();
-    if(_spirit_tx_started) { // betzw - TOCHECK: is this really correct to be done here?
-    	_spirit_tx_started = false;
-    	CLEAR_TXBUF();
-		/* call user callback */
-		if(_current_irq_callback) {
-			_current_irq_callback(TX_ERR);
-		}
-    }
+	  _is_receiving = true;
+	  _spirit_rx_err = false;
+	  CLEAR_RXBUF();
+	  MBED_ASSERT(!_spirit_tx_started);
   }
 
   /* RX FIFO almost full */
   if(x_irq_status.IRQ_RX_FIFO_ALMOST_FULL) {
+	  _is_receiving = true;
 	  if(_spirit_rx_err) {
 		  cmd_strobe(SPIRIT1_STROBE_FRX);
 	  } else {
 		  uint8_t fifo_available = linear_fifo_read_num_elements_rx_fifo();
 		  unsigned int remaining = MAX_PACKET_LEN - _spirit_rx_pos;
 		  if(fifo_available > remaining) {
-			    receiving_packet = 0;
 			    _spirit_rx_err = true;
 			    CLEAR_RXBUF();
 			    cmd_strobe(SPIRIT1_STROBE_FRX);
@@ -640,8 +637,9 @@
 
   /* The IRQ_RX_DATA_READY notifies a new packet arrived */
   if(x_irq_status.IRQ_RX_DATA_READY) {
+	_is_receiving = false; // Finished receiving
+
 	if(_spirit_rx_err) {
-		receiving_packet = 0;
 		_spirit_rx_err = false;
 	    CLEAR_RXBUF();
 		cmd_strobe(SPIRIT1_STROBE_FRX);
@@ -668,8 +666,6 @@
 		last_rssi = qi_get_rssi(); //MGR
 		last_lqi  = qi_get_lqi();  //MGR
 
-		receiving_packet = 0;
-
 #if NULLRDC_CONF_802154_AUTOACK
 		if (spirit_rxbuf[0] == ACK_LEN) {
 			/* For debugging purposes we assume this is an ack for us */
--- a/SimpleSpirit1.h	Wed Oct 26 15:08:44 2016 +0200
+++ b/SimpleSpirit1.h	Fri Oct 28 14:14:03 2016 +0200
@@ -66,16 +66,16 @@
      * The +1 because of the first byte,
      * which will contain the length of the packet.
      */
-    uint16_t spirit_tx_len;
-    bool _spirit_tx_started;
-    uint16_t spirit_rx_len;
-    uint16_t _spirit_rx_pos;
-    bool _spirit_rx_err;
+    volatile uint16_t spirit_tx_len;
+    volatile bool _spirit_tx_started;
+    volatile uint16_t spirit_rx_len;
+    volatile uint16_t _spirit_rx_pos;
+    volatile bool _spirit_rx_err;
     uint8_t spirit_rx_buf[MAX_PACKET_LEN];
+    volatile bool _is_receiving;
 
     /** Status Variables from Cube Implementation **/
-    volatile uint8_t receiving_packet;
-    volatile unsigned int spirit_on;
+    unsigned int spirit_on;
     uint8_t last_rssi; //MGR
     uint8_t last_lqi;  //MGR
 
@@ -391,14 +391,14 @@
       */
     int channel_clear(void);
 
-    /** Check if the radio driver is currently receiving a packet */
-    int get_receiving_packet(void) {
-    	return receiving_packet;
-    }
-
     /** Check if the radio driver has just received a packet **/
     int get_pending_packet(void);
 
+    /** Is radio currently receiving **/
+    bool is_receiving(void) {
+    	return _is_receiving;
+    }
+
     /** Get latest value of RSSI **/
     float get_last_rssi_dbm(void) {
     	if(last_rssi == 0) {
--- a/mbed_driver_api.cpp	Wed Oct 26 15:08:44 2016 +0200
+++ b/mbed_driver_api.cpp	Fri Oct 28 14:14:03 2016 +0200
@@ -1,5 +1,9 @@
 #include "SimpleSpirit1.h"
 #include "nanostack/platform/arm_hal_phy.h"
+#include "platform/arm_hal_interrupt.h"
+
+#include "mbed_trace.h"
+#define TRACE_GROUP  "SPIRIT"
 
 /*Atmel RF Part Type*/
 // betzw - TODO
@@ -32,30 +36,91 @@
     {CHANNEL_PAGE_0, NULL}
 };
 
+static uint8_t need_ack = 0;
 static uint8_t tx_sequence = 0xff;
 static uint8_t mac_tx_handle = 0;
 
 static SimpleSpirit1 *rf_device = NULL;
 static uint8_t rf_rx_buf[MAX_PACKET_LEN];
 
+static uint8_t stored_mac_address[8];
+static uint8_t stored_short_adr[2];
+static uint8_t stored_pan_id[2];
+
+#define RF_SIG_ACK_NEEDED (1<<0)
+static Thread rf_ack_sender(osPriorityRealtime);
+static uint8_t rf_rx_sequence;
+static uint8_t rf_src_pan_id[2];
+static bool rf_ack_sent = false;
+
+/* MAC frame helper macros */
+#define MAC_FCF_FRAME_TYPE_MASK         0x0007
+#define MAC_FCF_FRAME_TYPE_SHIFT        0
+#define MAC_FCF_SECURITY_BIT_MASK       0x0008
+#define MAC_FCF_SECURITY_BIT_SHIFT      3
+#define MAC_FCF_PENDING_BIT_MASK        0x0010
+#define MAC_FCF_PENDING_BIT_SHIFT       4
+#define MAC_FCF_ACK_REQ_BIT_MASK        0x0020
+#define MAC_FCF_ACK_REQ_BIT_SHIFT       5
+#define MAC_FCF_INTRA_PANID_MASK        0x0040
+#define MAC_FCF_INTRA_PANID_SHIFT       6
+#define MAC_FCF_DST_ADDR_MASK           0x0c00
+#define MAC_FCF_DST_ADDR_SHIFT          10
+#define MAC_FCF_VERSION_MASK            0x3000
+#define MAC_FCF_VERSION_SHIFT           12
+#define MAC_FCF_SRC_ADDR_MASK           0xc000
+#define MAC_FCF_SRC_ADDR_SHIFT          14
+
+/* MAC supported frame types */
+#define FC_BEACON_FRAME         0x00
+#define FC_DATA_FRAME           0x01
+#define FC_ACK_FRAME            0x02
+#define FC_CMD_FRAME            0x03
+
+static void rf_if_lock(void)
+{
+    platform_enter_critical();
+}
+
+static void rf_if_unlock(void)
+{
+    platform_exit_critical();
+}
+
 static int8_t rf_start_cca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol)
 {
+	MBED_ASSERT(data_length >= 3);
+
     /*Check if transmitter is busy*/
-    if((rf_device->get_receiving_packet()) || (rf_device->channel_clear() == 0)) {
-        /*Return busy*/
+    if((rf_device->get_pending_packet()) || (rf_device->channel_clear() == 0)) {
+    	/*Return busy*/
         return -1;
     } else {
-        /*Store the sequence number for ACK handling*/
-        tx_sequence = *(data_ptr + 2);
+    	/* Get Lock */
+    	rf_if_lock();
 
-        /*Store TX handle*/
-        mac_tx_handle = tx_handle;
+    	/*Check if transmitted data needs to be acked*/
+    	if((data_ptr[0] & MAC_FCF_ACK_REQ_BIT_MASK) >> MAC_FCF_ACK_REQ_BIT_SHIFT)
+    		need_ack = 1;
+    	else
+    		need_ack = 0;
+
+    	/*Store the sequence number for ACK handling*/
+    	tx_sequence = *(data_ptr + 2);
+
+    	/*Store TX handle*/
+    	mac_tx_handle = tx_handle;
 
         /*Send the packet*/
         rf_device->send(data_ptr, data_length);
+
+    	/* Release Lock */
+    	rf_if_unlock();
+
+    	tr_debug("%s (%d), tx_handle=%x, tx_seq=%x", __func__, __LINE__, tx_handle, tx_sequence);
     }
 
-    /*Return success*/
+	/*Return success*/
     return 0;
 }
 
@@ -66,10 +131,12 @@
     {
         /*Reset PHY driver and set to idle*/
         case PHY_INTERFACE_RESET:
+        	tr_debug("%s (%d)", __func__, __LINE__);
         	rf_device->reset_board();
             break;
         /*Disable PHY Interface driver*/
         case PHY_INTERFACE_DOWN:
+        	tr_debug("%s (%d)", __func__, __LINE__);
             ret_val = rf_device->off();
             if(ret_val != 0) ret_val = -1;
             break;
@@ -77,19 +144,26 @@
         case PHY_INTERFACE_UP:
         	ret_val = rf_device->on();
         	if(ret_val != 0) {
+            	tr_debug("%s (%d)", __func__, __LINE__);
         		ret_val = -1;
         		break;
         	}
+        	tr_debug("%s (%d) - channel: %d", __func__, __LINE__, (int)rf_channel);
             rf_device->set_channel(rf_channel);
             break;
         /*Enable wireless interface ED scan mode*/
         case PHY_INTERFACE_RX_ENERGY_STATE:
+        	tr_debug("%s (%d)", __func__, __LINE__);
             break;
         /*Enable Sniffer state*/
         case PHY_INTERFACE_SNIFFER_STATE:
             // TODO - if we really need this - WAS: rf_setup_sniffer(rf_channel);
+        	tr_debug("%s (%d)", __func__, __LINE__);
         	ret_val = -1;
             break;
+        default:
+        	tr_debug("%s (%d)", __func__, __LINE__);
+        	break;
     }
     return ret_val;
 }
@@ -100,45 +174,82 @@
     {
         /*Control MAC pending bit for Indirect data transmission*/
         case PHY_EXTENSION_CTRL_PENDING_BIT:
+        	tr_debug("%s (%d)", __func__, __LINE__);
             break;
 
         /*Return frame pending status*/
         case PHY_EXTENSION_READ_LAST_ACK_PENDING_STATUS:
-            // TODO: *data_ptr = rf_if_last_acked_pending();
-            *data_ptr = 0;
+        	tr_debug("%s (%d), need_ack=%x", __func__, __LINE__, (unsigned int)need_ack);
+            *data_ptr = need_ack;
             break;
 
         /*Set channel, used for setting channel for energy scan*/
         case PHY_EXTENSION_SET_CHANNEL:
+        	tr_debug("%s (%d)", __func__, __LINE__);
             break;
 
         /*Read energy on the channel*/
         case PHY_EXTENSION_READ_CHANNEL_ENERGY:
             // TODO: *data_ptr = rf_get_channel_energy();
+        	tr_debug("%s (%d)", __func__, __LINE__);
            	*data_ptr = rf_device->get_last_rssi_dbm();
             break;
 
         /*Read status of the link*/
         case PHY_EXTENSION_READ_LINK_STATUS:
             // TODO: *data_ptr = rf_get_link_status();
-        	*data_ptr = rf_device->get_last_lqi();
+        	tr_debug("%s (%d)", __func__, __LINE__);
+        	*data_ptr = rf_device->get_last_lqi()*17;
             break;
 
         default:
+        	tr_debug("%s (%d)", __func__, __LINE__);
         	break;
     }
     return 0;
 }
 
+#if 0 // Not used in this example
+static inline void rf_set_mac_48bit(uint8_t *ptr) {
+	tr_debug("%s (%d), adr0=%x, adr1=%x, adr2=%x, adr3=%x, adr4=%x, adr5=%x",
+			__func__, __LINE__,
+			ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]);
+}
+#endif // 0
+
+static inline void rf_set_mac_address(uint8_t *ptr) {
+	tr_debug("%s (%d), adr0=%x, adr1=%x, adr2=%x, adr3=%x, adr4=%x, adr5=%x, adr6=%x, adr7=%x",
+			__func__, __LINE__,
+			ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7]);
+	for(int i = 0; i < 8; i++) {
+		stored_mac_address[i] = ptr[i];
+	}
+}
+
+static inline void rf_set_short_adr(uint8_t *ptr) {
+	tr_debug("%s (%d), adr0=%x, adr1=%x",
+			__func__, __LINE__,
+			ptr[0], ptr[1]);
+	stored_short_adr[0] = ptr[0];
+	stored_short_adr[1] = ptr[1];
+}
+
+static inline void rf_set_pan_id(uint8_t *ptr) {
+	tr_debug("%s (%d), adr0=%x, adr1=%x",
+			__func__, __LINE__,
+			ptr[0], ptr[1]);
+	stored_pan_id[0] = ptr[0];
+}
+
 static int8_t rf_address_write(phy_address_type_e address_type, uint8_t *address_ptr)
 {
 
-#if 0 // TODO - if we really need this - WAS
     switch (address_type)
     {
         /*Set 48-bit address*/
         case PHY_MAC_48BIT:
             /* Not used in this example */
+        	// betzw - WAS: rf_set_mac_48bit(address_ptr);
             break;
         /*Set 64-bit address*/
         case PHY_MAC_64BIT:
@@ -153,34 +264,117 @@
             rf_set_pan_id(address_ptr);
             break;
     }
-#endif // 0
 
     return 0;
 }
 
 /* Note: we are in IRQ context */
-static void rf_handle_ack(uint8_t seq_number, uint8_t data_pending)
+static void rf_handle_ack(uint8_t seq_number)
 {
-    phy_link_tx_status_e phy_status;
-
-    // TODO - if we really need this - WAS: rf_if_lock();
-
     /*Received ACK sequence must be equal with transmitted packet sequence*/
     if(tx_sequence == seq_number)
     {
-        /*When data pending bit in ACK frame is set, inform NET library*/
-        if(data_pending)
-            phy_status = PHY_LINK_TX_DONE_PENDING;
-        else
-            phy_status = PHY_LINK_TX_DONE;
+    	/* Reset 'need_ack' */
+    	need_ack = 0;
 
-        /*Call PHY TX Done API*/
+    	/*Call PHY TX Done API*/
         if(device_driver.phy_tx_done_cb){
-            device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, phy_status, 1, 1);
+            device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_DONE, 1, 1);
         }
     }
+}
 
-    // TODO - if we really need this - WAS: rf_if_unlock();
+/* Note: we are in IRQ context */
+static inline bool rf_check_mac_address(uint8_t *dest) {
+	for(int i = 0; i < 8; i++) {
+		if(dest[i] != stored_mac_address[i]) return false;
+	}
+	return true;
+}
+
+/* Note: we are in IRQ context */
+/* Returns true if packet should be accepted */
+static bool rf_check_destination(int len, uint8_t *ack_requested) {
+	uint8_t dst_pan_id[2];
+	uint8_t dest_addr[8];
+	uint8_t dst_addr_mode = 0x0; /*0x00 = no address 0x01 = reserved 0x02 = 16-bit short address 0x03 = 64-bit extended address */
+	uint8_t src_addr_mode = 0x0; /*0x00 = no address 0x01 = reserved 0x02 = 16-bit short address 0x03 = 64-bit extended address */
+	uint8_t min_size = 3;
+	bool ret = false;
+
+	if(len < min_size) return false;
+
+	(*ack_requested) = ((rf_rx_buf[0] & MAC_FCF_ACK_REQ_BIT_MASK) >> MAC_FCF_ACK_REQ_BIT_SHIFT);
+	dst_addr_mode = ((rf_rx_buf[0] & MAC_FCF_DST_ADDR_MASK) >> MAC_FCF_DST_ADDR_SHIFT);
+	src_addr_mode = ((rf_rx_buf[0] & MAC_FCF_SRC_ADDR_MASK) >> MAC_FCF_SRC_ADDR_SHIFT);
+
+	rf_rx_sequence = rf_rx_buf[2];
+
+	switch(dst_addr_mode) {
+	case 0x00:
+		ret = true; // no check & ack possible;
+		(*ack_requested) = 0;
+		break;
+	case 0x02:
+		min_size = 7;
+		if(len < min_size) return false;
+		min_size = 9;
+		dst_pan_id[0] = rf_rx_buf[3];
+		dst_pan_id[1] = rf_rx_buf[4];
+		if((dst_pan_id[0] == 0xFF) && (dst_pan_id[1] == 0xFF)) {
+			ret = true;
+			break;
+		}
+
+		if((dst_pan_id[0] == stored_pan_id[0]) && (dst_pan_id[1] == stored_pan_id[1])) {
+			ret = true;
+			break;
+		}
+
+		dest_addr[0] = rf_rx_buf[5];
+		dest_addr[1] = rf_rx_buf[6];
+		if((dest_addr[0] == stored_short_adr[0]) && (dest_addr[1] == stored_short_adr[1])) {
+			ret = true;
+			break;
+		}
+		break;
+	case 0x03:
+		min_size = 7;
+		if(len < 7) return false;
+		min_size = 15;
+		dst_pan_id[0] = rf_rx_buf[3];
+		dst_pan_id[1] = rf_rx_buf[4];
+		if((dst_pan_id[0] == 0xFF) && (dst_pan_id[1] == 0xFF)) {
+			ret = true;
+			break;
+		}
+
+		ret = rf_check_mac_address(&rf_rx_buf[5]);
+		break;
+	default:
+		/* not supported */
+		return false;
+	}
+
+	if(*ack_requested) {
+		if(src_addr_mode == 0x00) {
+			*ack_requested = 0; // cannot send acknowledgment
+		} else {
+			if(len < min_size) {
+				*ack_requested = 0; // cannot send acknowledgment
+			} else {
+				rf_src_pan_id[0] = rf_rx_buf[min_size-2];
+				rf_src_pan_id[1] = rf_rx_buf[min_size-1];
+			}
+		}
+	}
+
+	return ret;
+}
+
+/* Note: we are in IRQ context */
+static inline void rf_send_ack() {
+	rf_ack_sender.signal_set(RF_SIG_ACK_NEEDED);
 }
 
 /* Note: we are in IRQ context */
@@ -189,31 +383,39 @@
     uint8_t rf_lqi;
     int8_t rf_rssi;
     uint16_t rf_buffer_len;
+    uint8_t ack_requested = 0;
 
     /* Get received data */
     rf_buffer_len = rf_device->read(rf_rx_buf, MAX_PACKET_LEN);
     if(!rf_buffer_len)
         return;
 
-    /* If waiting for ACK, check here if the packet is an ACK to a message previously sent */
-    if((rf_buffer_len == 3) && ((rf_rx_buf[0] & 0x07) == 0x02)) {
-    	uint8_t pending = 0;
+    /* Check if packet should be accepted */
+    if(!rf_check_destination(rf_buffer_len, &ack_requested)) {
+    	return;
+    }
 
-    	/*Check if data is pending*/
-    	if ((rf_rx_buf[0] & 0x10)) {
-    		pending=1;
-        }
+    /* If waiting for ACK, check here if the packet is an ACK to a message previously sent */
+    if((rf_buffer_len == 5) && (((rf_rx_buf[0] & MAC_FCF_FRAME_TYPE_MASK) >> MAC_FCF_FRAME_TYPE_SHIFT) == FC_ACK_FRAME)) {
+    	/*Send sequence number in ACK handler*/
+    	tr_debug("%s (%d), len=%u", __func__, __LINE__, (unsigned int)rf_buffer_len);
+       	rf_handle_ack(rf_rx_buf[2]);
+       	return;
+    }
 
-       	/*Send sequence number in ACK handler*/
-       	rf_handle_ack(rf_rx_buf[2], pending);
-       	return;
+    /* Kick off ACK sending */
+    if(ack_requested) {
+    	rf_send_ack();
     }
 
     /* Get link information */
     rf_rssi = (int8_t)rf_device->get_last_rssi_dbm();
     rf_lqi = (uint8_t)rf_device->get_last_lqi();
+    rf_lqi *= 17; // scale to 8-bit value
 
     /* Note: Checksum of the packet must be checked and removed before entering here */
+    /* TODO - betzw: what to do? */
+    // rf_buffer_len -= 2;
 
     /* Send received data and link information to the network stack */
     if( device_driver.phy_rx_cb ){
@@ -226,6 +428,12 @@
 {
     phy_link_tx_status_e phy_status = PHY_LINK_TX_SUCCESS;
 
+    /* Check if this is an ACK sending which is still pending */
+	if(rf_ack_sent) {
+		rf_ack_sent = false;
+		return; // no need to inform stack
+	}
+
     /*Call PHY TX Done API*/
     if(device_driver.phy_tx_done_cb){
         device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, phy_status, 1, 1);
@@ -252,14 +460,52 @@
 		rf_handle_tx_end();
 		break;
 	case SimpleSpirit1::TX_ERR:
+    	tr_debug("%s (%d)", __func__, __LINE__);
 		rf_handle_tx_err();
 		break;
 	}
 }
 
+static void rf_ack_loop(void) {
+	static uint16_t buffer[4];
+
+	/* Pre-prepare payload */
+	buffer[0] = FC_ACK_FRAME | (0x2 << MAC_FCF_DST_ADDR_SHIFT); // FCF
+
+	do {
+		/* Wait for signal */
+		rf_ack_sender.signal_wait(RF_SIG_ACK_NEEDED);
+
+		/* Prepare payload */
+		uint8_t *ptr = (uint8_t*)&buffer[1];
+		ptr[0] = rf_rx_sequence;   // Sequence number
+		ptr[1] = rf_src_pan_id[0]; // pan_id_0
+		ptr[2] = rf_src_pan_id[1]; // pan_id_1
+
+		/* Get Lock */
+		rf_if_lock();
+
+		/* Wait for device not receiving */
+		while(rf_device->is_receiving()) {
+			wait_us(10);
+		}
+
+		/* Set information that we have sent an ACK */
+		rf_ack_sent = true;
+
+        /*Send the packet*/
+        rf_device->send((uint8_t*)buffer, 5);
+
+		/* Release Lock */
+		rf_if_unlock();
+	} while(true);
+}
+
 static void rf_init(void) {
 	rf_device = &SimpleSpirit1::CreateInstance(D11, D12, D13, D9, D10, D2);
 	rf_device->attach_irq_callback(rf_callback_func);
+
+	rf_ack_sender.start(rf_ack_loop);
 }
 
 extern "C" int8_t rf_device_register(void)
@@ -303,6 +549,7 @@
     /*Register device driver*/
     rf_radio_driver_id = arm_net_phy_register(&device_driver);
 
+	tr_debug("%s (%d)", __func__, __LINE__);
     return rf_radio_driver_id;
 }
 
@@ -315,6 +562,7 @@
  */
 extern "C" void rf_read_mac_address(uint8_t *ptr)
 {
+	tr_debug("%s (%d)", __func__, __LINE__);
     memcpy(ptr, mac_address, 8);
 }
 
@@ -327,6 +575,7 @@
  */
 extern "C" int8_t rf_read_random(void)
 {
+	tr_debug("%s (%d)", __func__, __LINE__);
     return rf_rnd_rssi;
 }
 
@@ -339,5 +588,6 @@
  */
 extern "C" rf_trx_part_e rf_radio_type_read(void)
 {
-  return ATMEL_UNKNOW_DEV;
+	tr_debug("%s (%d)", __func__, __LINE__);
+	return ATMEL_UNKNOW_DEV;
 }