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).
Revision 12:b8056eda4028, committed 2016-10-28
- 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
--- 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;
}
X-NUCLEO-IDS01A4 Sub-1GHz RF Expansion Board