Added support for the WNC M14A2A Cellular LTE Data Module.

Dependencies:   WNC14A2AInterface

Easy Connect

Easily add all supported connectivity methods to your mbed OS project

This project is derived from https://developer.mbed.org/teams/sandbox/code/simple-mbed-client-example/file/dd6231df71bb/easy-connect.lib. It give user the ability to switch between connectivity methods and includes support for the WNC14A2A Data Module. The `NetworkInterface` API makes this easy, but you still need a mechanism for the user to select the connection method, The selection is made by modifying the `mbed_app.json` file and using `easy_connect()` from your application.

Specifying connectivity method

To add support for the WNC14A2A, add the following to your ``mbed_app.json`` file:

mbed_app.json

{
    "config": {
        "network-interface":{
            "help": "options are ETHERNET,WIFI_ESP8266,WIFI_ODIN,MESH_LOWPAN_ND,MESH_THREAD,WNC14A2A",
            "value": "WNC14A2A"
        }
    },
}

After you choose `WNC14A2A` you'll also need to indicate if you want debug output or not by Enabling (true) or Disabling (false) WNC_DEBUG.

If WNC_DEBUG is enabled, there are 3 different levels of debug output (selected via bit settings). These debug levels are set using the following values:

ValueDescription
1Basic WNC driver debug output
2Comprehensive WNC driver debug output
4Network Layer debug output

You can have any combination of these three bit values for a total value of 0 – 7.

WNC Debug Settings

    "config": {
        "WNC_DEBUG": {
            "value": false
        },
        "WNC_DEBUG_SETTING": {
            "value": 4
        },
    }

Using Easy Connect from your application

Easy Connect has just one function which will either return a `NetworkInterface`-pointer or `NULL`:

Sample Code

#include "easy-connect.h"

int main(int, char**) {
    NetworkInterface* network = easy_connect(true); /* has 1 argument, enable_logging (pass in true to log to serial port) */
    if (!network) {
        printf("Connecting to the network failed... See serial output.\r\n");
        return 1;
    }
 
    // Rest of your program
}

Tested on

  • K64F with Ethernet.
  • AT&T Cellular IoT Starter Kit with WNC M14A2A Cellular Data Module

The WNCInterface class currently supports the following version(s):

  • MPSS: M14A2A_v11.50.164451 APSS: M14A2A_v11.53.164451

License

This library is released under the Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License and may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Committer:
group-Avnet
Date:
Wed Apr 19 01:08:11 2017 +0000
Revision:
0:478cfd88041f
Initial commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
group-Avnet 0:478cfd88041f 1 #include "NanostackRfPhySpirit1.h"
group-Avnet 0:478cfd88041f 2 #include "SimpleSpirit1.h"
group-Avnet 0:478cfd88041f 3 #include "nanostack/platform/arm_hal_phy.h"
group-Avnet 0:478cfd88041f 4 #include "platform/arm_hal_interrupt.h"
group-Avnet 0:478cfd88041f 5
group-Avnet 0:478cfd88041f 6 #include "mbed_trace.h"
group-Avnet 0:478cfd88041f 7 #define TRACE_GROUP "SPIRIT"
group-Avnet 0:478cfd88041f 8
group-Avnet 0:478cfd88041f 9 /* Define beyond macro if you want to perform heavy debug tracing also in IRQ context */
group-Avnet 0:478cfd88041f 10 // #define HEAVY_TRACING
group-Avnet 0:478cfd88041f 11
group-Avnet 0:478cfd88041f 12 static phy_device_driver_s device_driver;
group-Avnet 0:478cfd88041f 13 static int8_t rf_radio_driver_id = -1;
group-Avnet 0:478cfd88041f 14
group-Avnet 0:478cfd88041f 15 const phy_rf_channel_configuration_s phy_subghz = {868000000, 1000000, 250000, 11, M_GFSK};
group-Avnet 0:478cfd88041f 16
group-Avnet 0:478cfd88041f 17 static phy_device_channel_page_s phy_channel_pages[] = {
group-Avnet 0:478cfd88041f 18 {CHANNEL_PAGE_2, &phy_subghz},
group-Avnet 0:478cfd88041f 19 {CHANNEL_PAGE_0, NULL}
group-Avnet 0:478cfd88041f 20 };
group-Avnet 0:478cfd88041f 21
group-Avnet 0:478cfd88041f 22 static uint8_t tx_sequence = 0xff;
group-Avnet 0:478cfd88041f 23 static uint8_t mac_tx_handle = 0;
group-Avnet 0:478cfd88041f 24
group-Avnet 0:478cfd88041f 25 static SimpleSpirit1 *rf_device = NULL;
group-Avnet 0:478cfd88041f 26 static uint8_t rf_rx_buf[MAX_PACKET_LEN];
group-Avnet 0:478cfd88041f 27
group-Avnet 0:478cfd88041f 28 static uint16_t stored_short_adr;
group-Avnet 0:478cfd88041f 29 static uint16_t stored_pan_id;
group-Avnet 0:478cfd88041f 30 static uint8_t stored_mac_address[8] = MBED_CONF_SPIRIT1_MAC_ADDRESS;
group-Avnet 0:478cfd88041f 31
group-Avnet 0:478cfd88041f 32 #define RF_SIG_ACK_NEEDED (1<<0)
group-Avnet 0:478cfd88041f 33 #define RF_SIG_CB_TX_DONE (1<<1)
group-Avnet 0:478cfd88041f 34 #define RF_SIG_CB_RX_RCVD (1<<2)
group-Avnet 0:478cfd88041f 35 static Thread rf_ack_sender(osPriorityRealtime);
group-Avnet 0:478cfd88041f 36 static volatile uint8_t rf_rx_sequence;
group-Avnet 0:478cfd88041f 37 static volatile bool rf_ack_sent = false;
group-Avnet 0:478cfd88041f 38
group-Avnet 0:478cfd88041f 39 /* MAC frame helper macros */
group-Avnet 0:478cfd88041f 40 #define MAC_FCF_FRAME_TYPE_MASK 0x0007
group-Avnet 0:478cfd88041f 41 #define MAC_FCF_FRAME_TYPE_SHIFT 0
group-Avnet 0:478cfd88041f 42 #define MAC_FCF_SECURITY_BIT_MASK 0x0008
group-Avnet 0:478cfd88041f 43 #define MAC_FCF_SECURITY_BIT_SHIFT 3
group-Avnet 0:478cfd88041f 44 #define MAC_FCF_PENDING_BIT_MASK 0x0010
group-Avnet 0:478cfd88041f 45 #define MAC_FCF_PENDING_BIT_SHIFT 4
group-Avnet 0:478cfd88041f 46 #define MAC_FCF_ACK_REQ_BIT_MASK 0x0020
group-Avnet 0:478cfd88041f 47 #define MAC_FCF_ACK_REQ_BIT_SHIFT 5
group-Avnet 0:478cfd88041f 48 #define MAC_FCF_INTRA_PANID_MASK 0x0040
group-Avnet 0:478cfd88041f 49 #define MAC_FCF_INTRA_PANID_SHIFT 6
group-Avnet 0:478cfd88041f 50 #define MAC_FCF_DST_ADDR_MASK 0x0c00
group-Avnet 0:478cfd88041f 51 #define MAC_FCF_DST_ADDR_SHIFT 10
group-Avnet 0:478cfd88041f 52 #define MAC_FCF_VERSION_MASK 0x3000
group-Avnet 0:478cfd88041f 53 #define MAC_FCF_VERSION_SHIFT 12
group-Avnet 0:478cfd88041f 54 #define MAC_FCF_SRC_ADDR_MASK 0xc000
group-Avnet 0:478cfd88041f 55 #define MAC_FCF_SRC_ADDR_SHIFT 14
group-Avnet 0:478cfd88041f 56
group-Avnet 0:478cfd88041f 57 /* MAC supported frame types */
group-Avnet 0:478cfd88041f 58 #define FC_BEACON_FRAME 0x00
group-Avnet 0:478cfd88041f 59 #define FC_DATA_FRAME 0x01
group-Avnet 0:478cfd88041f 60 #define FC_ACK_FRAME 0x02
group-Avnet 0:478cfd88041f 61 #define FC_CMD_FRAME 0x03
group-Avnet 0:478cfd88041f 62
group-Avnet 0:478cfd88041f 63 static void rf_if_lock(void)
group-Avnet 0:478cfd88041f 64 {
group-Avnet 0:478cfd88041f 65 platform_enter_critical();
group-Avnet 0:478cfd88041f 66 }
group-Avnet 0:478cfd88041f 67
group-Avnet 0:478cfd88041f 68 static void rf_if_unlock(void)
group-Avnet 0:478cfd88041f 69 {
group-Avnet 0:478cfd88041f 70 platform_exit_critical();
group-Avnet 0:478cfd88041f 71 }
group-Avnet 0:478cfd88041f 72
group-Avnet 0:478cfd88041f 73 static inline uint16_t rf_read_16_bit(uint8_t *data_ptr) { // little-endian
group-Avnet 0:478cfd88041f 74 uint16_t ret;
group-Avnet 0:478cfd88041f 75
group-Avnet 0:478cfd88041f 76 ret = ((uint16_t)data_ptr[0]) + (((uint16_t)data_ptr[1]) << 8);
group-Avnet 0:478cfd88041f 77 return ret;
group-Avnet 0:478cfd88041f 78 }
group-Avnet 0:478cfd88041f 79
group-Avnet 0:478cfd88041f 80 static int8_t rf_trigger_send(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol)
group-Avnet 0:478cfd88041f 81 {
group-Avnet 0:478cfd88041f 82 #ifndef NDEBUG
group-Avnet 0:478cfd88041f 83 debug_if(!(data_length >= 3), "\n\rassert failed in: %s (%d)\n\r", __func__, __LINE__);
group-Avnet 0:478cfd88041f 84 #endif
group-Avnet 0:478cfd88041f 85
group-Avnet 0:478cfd88041f 86 /* Give 'rf_ack_sender' a better chance to run */
group-Avnet 0:478cfd88041f 87 Thread::yield();
group-Avnet 0:478cfd88041f 88
group-Avnet 0:478cfd88041f 89 /* Get Lock */
group-Avnet 0:478cfd88041f 90 rf_if_lock();
group-Avnet 0:478cfd88041f 91
group-Avnet 0:478cfd88041f 92 /*Check if transmitter is busy*/
group-Avnet 0:478cfd88041f 93 if(rf_device->is_receiving()) { /* betzw - WAS: (rf_device->channel_clear() != 0)), do NOT use this but rather study and enable automatic CCA */
group-Avnet 0:478cfd88041f 94 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 95
group-Avnet 0:478cfd88041f 96 /* Release Lock */
group-Avnet 0:478cfd88041f 97 rf_if_unlock();
group-Avnet 0:478cfd88041f 98
group-Avnet 0:478cfd88041f 99 /*Return busy*/
group-Avnet 0:478cfd88041f 100 return -1;
group-Avnet 0:478cfd88041f 101 } else {
group-Avnet 0:478cfd88041f 102 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 103 uint16_t fcf = rf_read_16_bit(data_ptr);
group-Avnet 0:478cfd88041f 104 uint16_t need_ack;
group-Avnet 0:478cfd88041f 105
group-Avnet 0:478cfd88041f 106 /*Check if transmitted data needs to be acked*/
group-Avnet 0:478cfd88041f 107 if((fcf & MAC_FCF_ACK_REQ_BIT_MASK) >> MAC_FCF_ACK_REQ_BIT_SHIFT)
group-Avnet 0:478cfd88041f 108 need_ack = 1;
group-Avnet 0:478cfd88041f 109 else
group-Avnet 0:478cfd88041f 110 need_ack = 0;
group-Avnet 0:478cfd88041f 111 #endif
group-Avnet 0:478cfd88041f 112
group-Avnet 0:478cfd88041f 113 /*Store the sequence number for ACK handling*/
group-Avnet 0:478cfd88041f 114 tx_sequence = *(data_ptr + 2);
group-Avnet 0:478cfd88041f 115
group-Avnet 0:478cfd88041f 116 /*Store TX handle*/
group-Avnet 0:478cfd88041f 117 mac_tx_handle = tx_handle;
group-Avnet 0:478cfd88041f 118
group-Avnet 0:478cfd88041f 119 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 120 tr_info("%s (%d), len=%d, tx_handle=%x, tx_seq=%x, need_ack=%d (%x:%x, %x:%x, %x:%x, %x:%x)", __func__, __LINE__,
group-Avnet 0:478cfd88041f 121 data_length, tx_handle, tx_sequence, need_ack,
group-Avnet 0:478cfd88041f 122 data_ptr[3], data_ptr[4], data_ptr[5], data_ptr[6],
group-Avnet 0:478cfd88041f 123 data_ptr[7], data_ptr[8], data_ptr[9], data_ptr[10]);
group-Avnet 0:478cfd88041f 124 #endif
group-Avnet 0:478cfd88041f 125
group-Avnet 0:478cfd88041f 126 /*Send the packet*/
group-Avnet 0:478cfd88041f 127 rf_device->send(data_ptr, data_length);
group-Avnet 0:478cfd88041f 128
group-Avnet 0:478cfd88041f 129 /* Release Lock */
group-Avnet 0:478cfd88041f 130 rf_if_unlock();
group-Avnet 0:478cfd88041f 131 }
group-Avnet 0:478cfd88041f 132
group-Avnet 0:478cfd88041f 133 /*Return success*/
group-Avnet 0:478cfd88041f 134 return 0;
group-Avnet 0:478cfd88041f 135 }
group-Avnet 0:478cfd88041f 136
group-Avnet 0:478cfd88041f 137 static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel)
group-Avnet 0:478cfd88041f 138 {
group-Avnet 0:478cfd88041f 139 int8_t ret_val = 0;
group-Avnet 0:478cfd88041f 140 switch (new_state)
group-Avnet 0:478cfd88041f 141 {
group-Avnet 0:478cfd88041f 142 /*Reset PHY driver and set to idle*/
group-Avnet 0:478cfd88041f 143 case PHY_INTERFACE_RESET:
group-Avnet 0:478cfd88041f 144 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 145 rf_device->reset_board();
group-Avnet 0:478cfd88041f 146 break;
group-Avnet 0:478cfd88041f 147 /*Disable PHY Interface driver*/
group-Avnet 0:478cfd88041f 148 case PHY_INTERFACE_DOWN:
group-Avnet 0:478cfd88041f 149 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 150 ret_val = rf_device->off();
group-Avnet 0:478cfd88041f 151 if(ret_val != 0) ret_val = -1;
group-Avnet 0:478cfd88041f 152 break;
group-Avnet 0:478cfd88041f 153 /*Enable PHY Interface driver*/
group-Avnet 0:478cfd88041f 154 case PHY_INTERFACE_UP:
group-Avnet 0:478cfd88041f 155 ret_val = rf_device->on();
group-Avnet 0:478cfd88041f 156 if(ret_val != 0) {
group-Avnet 0:478cfd88041f 157 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 158 ret_val = -1;
group-Avnet 0:478cfd88041f 159 break;
group-Avnet 0:478cfd88041f 160 }
group-Avnet 0:478cfd88041f 161 tr_debug("%s (%d) - channel: %d", __func__, __LINE__, (int)rf_channel);
group-Avnet 0:478cfd88041f 162 rf_device->set_channel(rf_channel);
group-Avnet 0:478cfd88041f 163 break;
group-Avnet 0:478cfd88041f 164 /*Enable wireless interface ED scan mode*/
group-Avnet 0:478cfd88041f 165 case PHY_INTERFACE_RX_ENERGY_STATE:
group-Avnet 0:478cfd88041f 166 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 167 break;
group-Avnet 0:478cfd88041f 168 /*Enable Sniffer state*/
group-Avnet 0:478cfd88041f 169 case PHY_INTERFACE_SNIFFER_STATE:
group-Avnet 0:478cfd88041f 170 // TODO - if we really need this - WAS: rf_setup_sniffer(rf_channel);
group-Avnet 0:478cfd88041f 171 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 172 ret_val = -1;
group-Avnet 0:478cfd88041f 173 break;
group-Avnet 0:478cfd88041f 174 default:
group-Avnet 0:478cfd88041f 175 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 176 break;
group-Avnet 0:478cfd88041f 177 }
group-Avnet 0:478cfd88041f 178 return ret_val;
group-Avnet 0:478cfd88041f 179 }
group-Avnet 0:478cfd88041f 180
group-Avnet 0:478cfd88041f 181 static int8_t rf_extension(phy_extension_type_e extension_type, uint8_t *data_ptr)
group-Avnet 0:478cfd88041f 182 {
group-Avnet 0:478cfd88041f 183 switch (extension_type)
group-Avnet 0:478cfd88041f 184 {
group-Avnet 0:478cfd88041f 185 /*Control MAC pending bit for Indirect data transmission*/
group-Avnet 0:478cfd88041f 186 case PHY_EXTENSION_CTRL_PENDING_BIT:
group-Avnet 0:478cfd88041f 187 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 188 break;
group-Avnet 0:478cfd88041f 189
group-Avnet 0:478cfd88041f 190 /*Return frame pending status*/
group-Avnet 0:478cfd88041f 191 case PHY_EXTENSION_READ_LAST_ACK_PENDING_STATUS:
group-Avnet 0:478cfd88041f 192 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 193 *data_ptr = 0;
group-Avnet 0:478cfd88041f 194 break;
group-Avnet 0:478cfd88041f 195
group-Avnet 0:478cfd88041f 196 /*Set channel, used for setting channel for energy scan*/
group-Avnet 0:478cfd88041f 197 case PHY_EXTENSION_SET_CHANNEL:
group-Avnet 0:478cfd88041f 198 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 199 break;
group-Avnet 0:478cfd88041f 200
group-Avnet 0:478cfd88041f 201 /*Read energy on the channel*/
group-Avnet 0:478cfd88041f 202 case PHY_EXTENSION_READ_CHANNEL_ENERGY:
group-Avnet 0:478cfd88041f 203 // TODO: *data_ptr = rf_get_channel_energy();
group-Avnet 0:478cfd88041f 204 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 205 *data_ptr = (int8_t)rf_device->get_last_rssi_dbm();
group-Avnet 0:478cfd88041f 206 break;
group-Avnet 0:478cfd88041f 207
group-Avnet 0:478cfd88041f 208 /*Read status of the link*/
group-Avnet 0:478cfd88041f 209 case PHY_EXTENSION_READ_LINK_STATUS:
group-Avnet 0:478cfd88041f 210 // TODO: *data_ptr = rf_get_link_status();
group-Avnet 0:478cfd88041f 211 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 212 *data_ptr = rf_device->get_last_sqi(); // use SQI as link quality
group-Avnet 0:478cfd88041f 213 break;
group-Avnet 0:478cfd88041f 214
group-Avnet 0:478cfd88041f 215 default:
group-Avnet 0:478cfd88041f 216 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 217 break;
group-Avnet 0:478cfd88041f 218 }
group-Avnet 0:478cfd88041f 219 return 0;
group-Avnet 0:478cfd88041f 220 }
group-Avnet 0:478cfd88041f 221
group-Avnet 0:478cfd88041f 222 static inline void rf_set_mac_address(uint8_t *ptr) {
group-Avnet 0:478cfd88041f 223 tr_debug("%s (%d), adr0=%x, adr1=%x, adr2=%x, adr3=%x, adr4=%x, adr5=%x, adr6=%x, adr7=%x",
group-Avnet 0:478cfd88041f 224 __func__, __LINE__,
group-Avnet 0:478cfd88041f 225 ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7]);
group-Avnet 0:478cfd88041f 226 for(int i = 0; i < 8; i++) {
group-Avnet 0:478cfd88041f 227 stored_mac_address[i] = ptr[i];
group-Avnet 0:478cfd88041f 228 }
group-Avnet 0:478cfd88041f 229 }
group-Avnet 0:478cfd88041f 230
group-Avnet 0:478cfd88041f 231 static inline void rf_get_mac_address(uint8_t *ptr) {
group-Avnet 0:478cfd88041f 232 for(int i = 0; i < 8; i++) {
group-Avnet 0:478cfd88041f 233 ptr[i] = stored_mac_address[i];
group-Avnet 0:478cfd88041f 234 }
group-Avnet 0:478cfd88041f 235 tr_debug("%s (%d), adr0=%x, adr1=%x, adr2=%x, adr3=%x, adr4=%x, adr5=%x, adr6=%x, adr7=%x",
group-Avnet 0:478cfd88041f 236 __func__, __LINE__,
group-Avnet 0:478cfd88041f 237 ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7]);
group-Avnet 0:478cfd88041f 238 }
group-Avnet 0:478cfd88041f 239
group-Avnet 0:478cfd88041f 240 static inline void rf_set_short_adr(uint8_t *ptr) {
group-Avnet 0:478cfd88041f 241 stored_short_adr = (ptr[0] << 8) + ptr[1]; // big-endian
group-Avnet 0:478cfd88041f 242 tr_debug("%s (%d), adr0=%x, adr1=%x, val=%d",
group-Avnet 0:478cfd88041f 243 __func__, __LINE__,
group-Avnet 0:478cfd88041f 244 ptr[0], ptr[1], stored_short_adr);
group-Avnet 0:478cfd88041f 245 }
group-Avnet 0:478cfd88041f 246
group-Avnet 0:478cfd88041f 247 static inline void rf_set_pan_id(uint8_t *ptr) {
group-Avnet 0:478cfd88041f 248 stored_pan_id = (ptr[0] << 8) + ptr[1]; // big-endian
group-Avnet 0:478cfd88041f 249 tr_debug("%s (%d), adr0=%x, adr1=%x, val=%d",
group-Avnet 0:478cfd88041f 250 __func__, __LINE__,
group-Avnet 0:478cfd88041f 251 ptr[0], ptr[1], stored_pan_id);
group-Avnet 0:478cfd88041f 252 }
group-Avnet 0:478cfd88041f 253
group-Avnet 0:478cfd88041f 254 static int8_t rf_address_write(phy_address_type_e address_type, uint8_t *address_ptr)
group-Avnet 0:478cfd88041f 255 {
group-Avnet 0:478cfd88041f 256 switch (address_type)
group-Avnet 0:478cfd88041f 257 {
group-Avnet 0:478cfd88041f 258 /*Set 48-bit address*/
group-Avnet 0:478cfd88041f 259 case PHY_MAC_48BIT:
group-Avnet 0:478cfd88041f 260 /* Not used in this example */
group-Avnet 0:478cfd88041f 261 // betzw - WAS: rf_set_mac_48bit(address_ptr);
group-Avnet 0:478cfd88041f 262 break;
group-Avnet 0:478cfd88041f 263 /*Set 64-bit address*/
group-Avnet 0:478cfd88041f 264 case PHY_MAC_64BIT:
group-Avnet 0:478cfd88041f 265 rf_set_mac_address(address_ptr);
group-Avnet 0:478cfd88041f 266 break;
group-Avnet 0:478cfd88041f 267 /*Set 16-bit address*/
group-Avnet 0:478cfd88041f 268 case PHY_MAC_16BIT:
group-Avnet 0:478cfd88041f 269 rf_set_short_adr(address_ptr);
group-Avnet 0:478cfd88041f 270 break;
group-Avnet 0:478cfd88041f 271 /*Set PAN Id*/
group-Avnet 0:478cfd88041f 272 case PHY_MAC_PANID:
group-Avnet 0:478cfd88041f 273 rf_set_pan_id(address_ptr);
group-Avnet 0:478cfd88041f 274 break;
group-Avnet 0:478cfd88041f 275 }
group-Avnet 0:478cfd88041f 276
group-Avnet 0:478cfd88041f 277 return 0;
group-Avnet 0:478cfd88041f 278 }
group-Avnet 0:478cfd88041f 279
group-Avnet 0:478cfd88041f 280 /* Note: we are in IRQ context */
group-Avnet 0:478cfd88041f 281 static inline void rf_send_signal(int32_t signal) {
group-Avnet 0:478cfd88041f 282 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 283 tr_info("%s (%d): %d", __func__, __LINE__, signal);
group-Avnet 0:478cfd88041f 284 #endif
group-Avnet 0:478cfd88041f 285 rf_ack_sender.signal_set(signal);
group-Avnet 0:478cfd88041f 286 }
group-Avnet 0:478cfd88041f 287
group-Avnet 0:478cfd88041f 288 static phy_link_tx_status_e phy_status;
group-Avnet 0:478cfd88041f 289 /* Note: we are in IRQ context */
group-Avnet 0:478cfd88041f 290 static void rf_handle_ack(uint8_t seq_number)
group-Avnet 0:478cfd88041f 291 {
group-Avnet 0:478cfd88041f 292 /*Received ACK sequence must be equal with transmitted packet sequence*/
group-Avnet 0:478cfd88041f 293 if(tx_sequence == seq_number)
group-Avnet 0:478cfd88041f 294 {
group-Avnet 0:478cfd88041f 295 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 296 tr_info("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 297 #endif
group-Avnet 0:478cfd88041f 298
group-Avnet 0:478cfd88041f 299 /*Call PHY TX Done API*/
group-Avnet 0:478cfd88041f 300 if(device_driver.phy_tx_done_cb){
group-Avnet 0:478cfd88041f 301 phy_status = PHY_LINK_TX_DONE;
group-Avnet 0:478cfd88041f 302 rf_send_signal(RF_SIG_CB_TX_DONE);
group-Avnet 0:478cfd88041f 303 }
group-Avnet 0:478cfd88041f 304 } else {
group-Avnet 0:478cfd88041f 305 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 306 tr_info("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 307 #endif
group-Avnet 0:478cfd88041f 308 }
group-Avnet 0:478cfd88041f 309 }
group-Avnet 0:478cfd88041f 310
group-Avnet 0:478cfd88041f 311 /* Note: we are in IRQ context */
group-Avnet 0:478cfd88041f 312 static inline bool rf_check_mac_address(uint8_t *dest) {
group-Avnet 0:478cfd88041f 313 for(int i = 0; i < 8; i++) {
group-Avnet 0:478cfd88041f 314 if(dest[i] != stored_mac_address[7-i]) return false;
group-Avnet 0:478cfd88041f 315 }
group-Avnet 0:478cfd88041f 316 return true;
group-Avnet 0:478cfd88041f 317 }
group-Avnet 0:478cfd88041f 318
group-Avnet 0:478cfd88041f 319 /* Note: we are in IRQ context */
group-Avnet 0:478cfd88041f 320 /* Returns true if packet should be accepted */
group-Avnet 0:478cfd88041f 321 static bool rf_check_destination(int len, uint8_t *ack_requested) {
group-Avnet 0:478cfd88041f 322 uint8_t frame_type;
group-Avnet 0:478cfd88041f 323 uint16_t dst_pan_id;
group-Avnet 0:478cfd88041f 324 uint16_t dst_short_adr;
group-Avnet 0:478cfd88041f 325 uint8_t dst_addr_mode = 0x0; /*0x00 = no address 0x01 = reserved 0x02 = 16-bit short address 0x03 = 64-bit extended address */
group-Avnet 0:478cfd88041f 326 uint8_t src_addr_mode = 0x0; /*0x00 = no address 0x01 = reserved 0x02 = 16-bit short address 0x03 = 64-bit extended address */
group-Avnet 0:478cfd88041f 327 uint8_t min_size = 3; // FCF & SeqNr
group-Avnet 0:478cfd88041f 328 bool ret = false;
group-Avnet 0:478cfd88041f 329 #if defined(HEAVY_TRACING)
group-Avnet 0:478cfd88041f 330 bool panid_compr = false;
group-Avnet 0:478cfd88041f 331 #endif
group-Avnet 0:478cfd88041f 332
group-Avnet 0:478cfd88041f 333 if(len < 3) {
group-Avnet 0:478cfd88041f 334 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 335 return false;
group-Avnet 0:478cfd88041f 336 }
group-Avnet 0:478cfd88041f 337
group-Avnet 0:478cfd88041f 338 uint16_t fcf = rf_read_16_bit(rf_rx_buf);
group-Avnet 0:478cfd88041f 339 frame_type = ((fcf & MAC_FCF_FRAME_TYPE_MASK) >> MAC_FCF_FRAME_TYPE_SHIFT);
group-Avnet 0:478cfd88041f 340 (*ack_requested) = ((fcf & MAC_FCF_ACK_REQ_BIT_MASK) >> MAC_FCF_ACK_REQ_BIT_SHIFT);
group-Avnet 0:478cfd88041f 341 dst_addr_mode = ((fcf & MAC_FCF_DST_ADDR_MASK) >> MAC_FCF_DST_ADDR_SHIFT);
group-Avnet 0:478cfd88041f 342 src_addr_mode = ((fcf & MAC_FCF_SRC_ADDR_MASK) >> MAC_FCF_SRC_ADDR_SHIFT);
group-Avnet 0:478cfd88041f 343 #if defined(HEAVY_TRACING)
group-Avnet 0:478cfd88041f 344 panid_compr = ((fcf & MAC_FCF_INTRA_PANID_MASK) >> MAC_FCF_INTRA_PANID_SHIFT);
group-Avnet 0:478cfd88041f 345 #endif
group-Avnet 0:478cfd88041f 346
group-Avnet 0:478cfd88041f 347 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 348 tr_info("%s (%d): len=%d, ftype=%x, snr=%x, ack=%d, dst=%x, src=%x, intra=%d", __func__, __LINE__, len, frame_type,
group-Avnet 0:478cfd88041f 349 rf_rx_buf[2], (*ack_requested), dst_addr_mode, src_addr_mode, panid_compr);
group-Avnet 0:478cfd88041f 350 #endif
group-Avnet 0:478cfd88041f 351
group-Avnet 0:478cfd88041f 352 if(frame_type == FC_ACK_FRAME) { // betzw: we support up to two different forms of ACK frames!
group-Avnet 0:478cfd88041f 353 if((len == 3) && (dst_addr_mode == 0x0) && (src_addr_mode == 0x0)) {
group-Avnet 0:478cfd88041f 354 ret = true;
group-Avnet 0:478cfd88041f 355 }
group-Avnet 0:478cfd88041f 356
group-Avnet 0:478cfd88041f 357 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 358 tr_info("%s (%d): ret=%d", __func__, __LINE__, ret);
group-Avnet 0:478cfd88041f 359 #endif
group-Avnet 0:478cfd88041f 360 (*ack_requested) = 0; // Never acknowledge ACK frames
group-Avnet 0:478cfd88041f 361 return ret;
group-Avnet 0:478cfd88041f 362 }
group-Avnet 0:478cfd88041f 363
group-Avnet 0:478cfd88041f 364 switch(dst_addr_mode) {
group-Avnet 0:478cfd88041f 365 case 0x00:
group-Avnet 0:478cfd88041f 366 ret = true; // no check possible;
group-Avnet 0:478cfd88041f 367 break;
group-Avnet 0:478cfd88041f 368 case 0x02:
group-Avnet 0:478cfd88041f 369 min_size += 4; // pan id + short dest adr
group-Avnet 0:478cfd88041f 370
group-Avnet 0:478cfd88041f 371 if(len < 5) {
group-Avnet 0:478cfd88041f 372 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 373 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 374 #endif
group-Avnet 0:478cfd88041f 375 return false;
group-Avnet 0:478cfd88041f 376 }
group-Avnet 0:478cfd88041f 377
group-Avnet 0:478cfd88041f 378 dst_pan_id = rf_read_16_bit(&rf_rx_buf[3]);
group-Avnet 0:478cfd88041f 379 if(dst_pan_id == 0xFFFF) {
group-Avnet 0:478cfd88041f 380 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 381 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 382 #endif
group-Avnet 0:478cfd88041f 383 ret = true;
group-Avnet 0:478cfd88041f 384 break;
group-Avnet 0:478cfd88041f 385 }
group-Avnet 0:478cfd88041f 386
group-Avnet 0:478cfd88041f 387 if(dst_pan_id == stored_pan_id) {
group-Avnet 0:478cfd88041f 388 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 389 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 390 #endif
group-Avnet 0:478cfd88041f 391 ret = true;
group-Avnet 0:478cfd88041f 392 break;
group-Avnet 0:478cfd88041f 393 } else {
group-Avnet 0:478cfd88041f 394 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 395 tr_debug("%s (%d): %d!=%d", __func__, __LINE__, dst_pan_id, stored_pan_id);
group-Avnet 0:478cfd88041f 396 #endif
group-Avnet 0:478cfd88041f 397 }
group-Avnet 0:478cfd88041f 398
group-Avnet 0:478cfd88041f 399 if(len < 7) {
group-Avnet 0:478cfd88041f 400 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 401 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 402 #endif
group-Avnet 0:478cfd88041f 403 return false;
group-Avnet 0:478cfd88041f 404 }
group-Avnet 0:478cfd88041f 405
group-Avnet 0:478cfd88041f 406 dst_short_adr = rf_read_16_bit(&rf_rx_buf[5]);
group-Avnet 0:478cfd88041f 407 if(dst_short_adr == stored_short_adr) {
group-Avnet 0:478cfd88041f 408 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 409 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 410 #endif
group-Avnet 0:478cfd88041f 411 ret = true;
group-Avnet 0:478cfd88041f 412 break;
group-Avnet 0:478cfd88041f 413 } else {
group-Avnet 0:478cfd88041f 414 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 415 tr_debug("%s (%d): %d!=%d", __func__, __LINE__, dst_short_adr, stored_short_adr);
group-Avnet 0:478cfd88041f 416 #endif
group-Avnet 0:478cfd88041f 417 }
group-Avnet 0:478cfd88041f 418 break;
group-Avnet 0:478cfd88041f 419 case 0x03:
group-Avnet 0:478cfd88041f 420 min_size += 10; // pan id + dest mac addr
group-Avnet 0:478cfd88041f 421
group-Avnet 0:478cfd88041f 422 if(len < 5) {
group-Avnet 0:478cfd88041f 423 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 424 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 425 #endif
group-Avnet 0:478cfd88041f 426 return false;
group-Avnet 0:478cfd88041f 427 }
group-Avnet 0:478cfd88041f 428
group-Avnet 0:478cfd88041f 429 dst_pan_id = rf_read_16_bit(&rf_rx_buf[3]);
group-Avnet 0:478cfd88041f 430 if(dst_pan_id == 0xFFFF) {
group-Avnet 0:478cfd88041f 431 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 432 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 433 #endif
group-Avnet 0:478cfd88041f 434 ret = true;
group-Avnet 0:478cfd88041f 435 break;
group-Avnet 0:478cfd88041f 436 }
group-Avnet 0:478cfd88041f 437
group-Avnet 0:478cfd88041f 438 if(dst_pan_id == stored_pan_id) {
group-Avnet 0:478cfd88041f 439 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 440 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 441 #endif
group-Avnet 0:478cfd88041f 442 ret = true;
group-Avnet 0:478cfd88041f 443 break;
group-Avnet 0:478cfd88041f 444 }
group-Avnet 0:478cfd88041f 445
group-Avnet 0:478cfd88041f 446 if(len < 13) {
group-Avnet 0:478cfd88041f 447 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 448 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 449 #endif
group-Avnet 0:478cfd88041f 450 return false;
group-Avnet 0:478cfd88041f 451 }
group-Avnet 0:478cfd88041f 452
group-Avnet 0:478cfd88041f 453 ret = rf_check_mac_address(&rf_rx_buf[5]);
group-Avnet 0:478cfd88041f 454 break;
group-Avnet 0:478cfd88041f 455 default:
group-Avnet 0:478cfd88041f 456 /* not supported */
group-Avnet 0:478cfd88041f 457 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 458 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 459 #endif
group-Avnet 0:478cfd88041f 460 return false;
group-Avnet 0:478cfd88041f 461 }
group-Avnet 0:478cfd88041f 462
group-Avnet 0:478cfd88041f 463 if(ret && (*ack_requested)) {
group-Avnet 0:478cfd88041f 464 rf_rx_sequence = rf_rx_buf[2];
group-Avnet 0:478cfd88041f 465 }
group-Avnet 0:478cfd88041f 466
group-Avnet 0:478cfd88041f 467 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 468 tr_info("%s (%d), ret=%d, ack=%d", __func__, __LINE__, ret, (*ack_requested));
group-Avnet 0:478cfd88041f 469 #endif
group-Avnet 0:478cfd88041f 470 return ret;
group-Avnet 0:478cfd88041f 471 }
group-Avnet 0:478cfd88041f 472
group-Avnet 0:478cfd88041f 473 static uint16_t rf_buffer_len = 0;
group-Avnet 0:478cfd88041f 474 static uint8_t rf_sqi;
group-Avnet 0:478cfd88041f 475 static int8_t rf_rssi;
group-Avnet 0:478cfd88041f 476 /* Note: we are in IRQ context */
group-Avnet 0:478cfd88041f 477 static inline void rf_handle_rx_end(void)
group-Avnet 0:478cfd88041f 478 {
group-Avnet 0:478cfd88041f 479 uint8_t ack_requested = 0;
group-Avnet 0:478cfd88041f 480
group-Avnet 0:478cfd88041f 481 /* Get received data */
group-Avnet 0:478cfd88041f 482 rf_buffer_len = rf_device->read(rf_rx_buf, MAX_PACKET_LEN);
group-Avnet 0:478cfd88041f 483 if(!rf_buffer_len)
group-Avnet 0:478cfd88041f 484 return;
group-Avnet 0:478cfd88041f 485
group-Avnet 0:478cfd88041f 486 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 487 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 488 #endif
group-Avnet 0:478cfd88041f 489
group-Avnet 0:478cfd88041f 490 /* Check if packet should be accepted */
group-Avnet 0:478cfd88041f 491 if(!rf_check_destination(rf_buffer_len, &ack_requested)) {
group-Avnet 0:478cfd88041f 492 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 493 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 494 #endif
group-Avnet 0:478cfd88041f 495 return;
group-Avnet 0:478cfd88041f 496 }
group-Avnet 0:478cfd88041f 497
group-Avnet 0:478cfd88041f 498 /* If waiting for ACK, check here if the packet is an ACK to a message previously sent */
group-Avnet 0:478cfd88041f 499 uint16_t fcf = rf_read_16_bit(rf_rx_buf);
group-Avnet 0:478cfd88041f 500 if(((fcf & MAC_FCF_FRAME_TYPE_MASK) >> MAC_FCF_FRAME_TYPE_SHIFT) == FC_ACK_FRAME) {
group-Avnet 0:478cfd88041f 501 /*Send sequence number in ACK handler*/
group-Avnet 0:478cfd88041f 502 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 503 tr_debug("%s (%d), len=%u", __func__, __LINE__, (unsigned int)rf_buffer_len);
group-Avnet 0:478cfd88041f 504 #endif
group-Avnet 0:478cfd88041f 505 rf_handle_ack(rf_rx_buf[2]);
group-Avnet 0:478cfd88041f 506 return;
group-Avnet 0:478cfd88041f 507 }
group-Avnet 0:478cfd88041f 508
group-Avnet 0:478cfd88041f 509 /* Kick off ACK sending */
group-Avnet 0:478cfd88041f 510 if(ack_requested) {
group-Avnet 0:478cfd88041f 511 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 512 tr_debug("%s (%d), len=%u", __func__, __LINE__, (unsigned int)rf_buffer_len);
group-Avnet 0:478cfd88041f 513 #endif
group-Avnet 0:478cfd88041f 514 rf_send_signal(RF_SIG_ACK_NEEDED);
group-Avnet 0:478cfd88041f 515 }
group-Avnet 0:478cfd88041f 516
group-Avnet 0:478cfd88041f 517 /* Get link information */
group-Avnet 0:478cfd88041f 518 rf_rssi = (int8_t)rf_device->get_last_rssi_dbm();
group-Avnet 0:478cfd88041f 519 rf_sqi = (uint8_t)rf_device->get_last_sqi(); // use SQI as link quality
group-Avnet 0:478cfd88041f 520
group-Avnet 0:478cfd88041f 521 /* Note: Checksum of the packet must be checked and removed before entering here */
group-Avnet 0:478cfd88041f 522 /* TODO - betzw: what to do? */
group-Avnet 0:478cfd88041f 523
group-Avnet 0:478cfd88041f 524 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 525 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 526 #endif
group-Avnet 0:478cfd88041f 527
group-Avnet 0:478cfd88041f 528 /* Send received data and link information to the network stack */
group-Avnet 0:478cfd88041f 529 if( device_driver.phy_rx_cb ){
group-Avnet 0:478cfd88041f 530 rf_send_signal(RF_SIG_CB_RX_RCVD);
group-Avnet 0:478cfd88041f 531 }
group-Avnet 0:478cfd88041f 532 }
group-Avnet 0:478cfd88041f 533
group-Avnet 0:478cfd88041f 534 /* Note: we are in IRQ context */
group-Avnet 0:478cfd88041f 535 static inline void rf_handle_tx_end(void)
group-Avnet 0:478cfd88041f 536 {
group-Avnet 0:478cfd88041f 537 /* Check if this is an ACK sending which is still pending */
group-Avnet 0:478cfd88041f 538 if(rf_ack_sent) {
group-Avnet 0:478cfd88041f 539 rf_ack_sent = false;
group-Avnet 0:478cfd88041f 540 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 541 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 542 #endif
group-Avnet 0:478cfd88041f 543 return; // no need to inform stack
group-Avnet 0:478cfd88041f 544 }
group-Avnet 0:478cfd88041f 545
group-Avnet 0:478cfd88041f 546 /*Call PHY TX Done API*/
group-Avnet 0:478cfd88041f 547 if(device_driver.phy_tx_done_cb){
group-Avnet 0:478cfd88041f 548 phy_status = PHY_LINK_TX_SUCCESS;
group-Avnet 0:478cfd88041f 549 rf_send_signal(RF_SIG_CB_TX_DONE);
group-Avnet 0:478cfd88041f 550 }
group-Avnet 0:478cfd88041f 551 }
group-Avnet 0:478cfd88041f 552
group-Avnet 0:478cfd88041f 553 /* Note: we are in IRQ context */
group-Avnet 0:478cfd88041f 554 static inline void rf_handle_tx_err(void) {
group-Avnet 0:478cfd88041f 555 /*Call PHY TX Done API*/
group-Avnet 0:478cfd88041f 556 if(device_driver.phy_tx_done_cb){
group-Avnet 0:478cfd88041f 557 phy_status = PHY_LINK_TX_FAIL;
group-Avnet 0:478cfd88041f 558 rf_send_signal(RF_SIG_CB_TX_DONE);
group-Avnet 0:478cfd88041f 559 }
group-Avnet 0:478cfd88041f 560 }
group-Avnet 0:478cfd88041f 561
group-Avnet 0:478cfd88041f 562 /* Note: we are in IRQ context */
group-Avnet 0:478cfd88041f 563 static void rf_callback_func(int event) {
group-Avnet 0:478cfd88041f 564 switch(event) {
group-Avnet 0:478cfd88041f 565 case SimpleSpirit1::RX_DONE:
group-Avnet 0:478cfd88041f 566 rf_handle_rx_end();
group-Avnet 0:478cfd88041f 567 break;
group-Avnet 0:478cfd88041f 568 case SimpleSpirit1::TX_DONE:
group-Avnet 0:478cfd88041f 569 rf_handle_tx_end();
group-Avnet 0:478cfd88041f 570 break;
group-Avnet 0:478cfd88041f 571 case SimpleSpirit1::TX_ERR:
group-Avnet 0:478cfd88041f 572 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 573 tr_debug("%s (%d): TX_ERR!!!", __func__, __LINE__);
group-Avnet 0:478cfd88041f 574 #endif
group-Avnet 0:478cfd88041f 575 rf_handle_tx_err();
group-Avnet 0:478cfd88041f 576 break;
group-Avnet 0:478cfd88041f 577 }
group-Avnet 0:478cfd88041f 578 }
group-Avnet 0:478cfd88041f 579
group-Avnet 0:478cfd88041f 580 static void rf_ack_loop(void) {
group-Avnet 0:478cfd88041f 581 static uint16_t buffer[2] = {
group-Avnet 0:478cfd88041f 582 (FC_ACK_FRAME << MAC_FCF_FRAME_TYPE_SHIFT),
group-Avnet 0:478cfd88041f 583 0x0
group-Avnet 0:478cfd88041f 584 };
group-Avnet 0:478cfd88041f 585
group-Avnet 0:478cfd88041f 586 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 587
group-Avnet 0:478cfd88041f 588 do {
group-Avnet 0:478cfd88041f 589 /* Wait for signal */
group-Avnet 0:478cfd88041f 590 osEvent event = rf_ack_sender.signal_wait(0);
group-Avnet 0:478cfd88041f 591
group-Avnet 0:478cfd88041f 592 if(event.status != osEventSignal) {
group-Avnet 0:478cfd88041f 593 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 594 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 595 #endif
group-Avnet 0:478cfd88041f 596 continue;
group-Avnet 0:478cfd88041f 597 }
group-Avnet 0:478cfd88041f 598
group-Avnet 0:478cfd88041f 599 int32_t signals = event.value.signals;
group-Avnet 0:478cfd88041f 600
group-Avnet 0:478cfd88041f 601 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 602 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 603 #endif
group-Avnet 0:478cfd88041f 604
group-Avnet 0:478cfd88041f 605 /* Get Lock */
group-Avnet 0:478cfd88041f 606 rf_if_lock();
group-Avnet 0:478cfd88041f 607
group-Avnet 0:478cfd88041f 608 if(signals & RF_SIG_ACK_NEEDED) {
group-Avnet 0:478cfd88041f 609 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 610 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 611 #endif
group-Avnet 0:478cfd88041f 612
group-Avnet 0:478cfd88041f 613 /* Prepare payload */
group-Avnet 0:478cfd88041f 614 uint8_t *ptr = (uint8_t*)&buffer[1];
group-Avnet 0:478cfd88041f 615 ptr[0] = rf_rx_sequence; // Sequence number
group-Avnet 0:478cfd88041f 616
group-Avnet 0:478cfd88041f 617 /* Wait for device not receiving */
group-Avnet 0:478cfd88041f 618 while(rf_device->is_receiving()) {
group-Avnet 0:478cfd88041f 619 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 620 tr_info("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 621 #endif
group-Avnet 0:478cfd88041f 622 wait_us(10);
group-Avnet 0:478cfd88041f 623 }
group-Avnet 0:478cfd88041f 624
group-Avnet 0:478cfd88041f 625 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 626 tr_debug("%s (%d), hdr=%x, nr=%x", __func__, __LINE__, buffer[0], ptr[0]);
group-Avnet 0:478cfd88041f 627 #endif
group-Avnet 0:478cfd88041f 628
group-Avnet 0:478cfd88041f 629 /* Set information that we have sent an ACK */
group-Avnet 0:478cfd88041f 630 rf_ack_sent = true;
group-Avnet 0:478cfd88041f 631
group-Avnet 0:478cfd88041f 632 /*Send the packet*/
group-Avnet 0:478cfd88041f 633 rf_device->send((uint8_t*)buffer, 3);
group-Avnet 0:478cfd88041f 634
group-Avnet 0:478cfd88041f 635 tr_debug("%s (%d), hdr=%x, nr=%x", __func__, __LINE__, buffer[0], ptr[0]);
group-Avnet 0:478cfd88041f 636 }
group-Avnet 0:478cfd88041f 637
group-Avnet 0:478cfd88041f 638 if(signals & RF_SIG_CB_TX_DONE) {
group-Avnet 0:478cfd88041f 639 device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, phy_status, 0, 0);
group-Avnet 0:478cfd88041f 640 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 641 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 642 #endif
group-Avnet 0:478cfd88041f 643 }
group-Avnet 0:478cfd88041f 644
group-Avnet 0:478cfd88041f 645 if(signals & RF_SIG_CB_RX_RCVD) {
group-Avnet 0:478cfd88041f 646 device_driver.phy_rx_cb(rf_rx_buf, rf_buffer_len, rf_sqi, rf_rssi, rf_radio_driver_id);
group-Avnet 0:478cfd88041f 647 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 648 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 649 #endif
group-Avnet 0:478cfd88041f 650 }
group-Avnet 0:478cfd88041f 651
group-Avnet 0:478cfd88041f 652 /* Release Lock */
group-Avnet 0:478cfd88041f 653 rf_if_unlock();
group-Avnet 0:478cfd88041f 654
group-Avnet 0:478cfd88041f 655 #ifdef HEAVY_TRACING
group-Avnet 0:478cfd88041f 656 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 657 #endif
group-Avnet 0:478cfd88041f 658 } while(true);
group-Avnet 0:478cfd88041f 659 }
group-Avnet 0:478cfd88041f 660
group-Avnet 0:478cfd88041f 661 void NanostackRfPhySpirit1::rf_init(void) {
group-Avnet 0:478cfd88041f 662 #ifndef NDEBUG
group-Avnet 0:478cfd88041f 663 osStatus ret;
group-Avnet 0:478cfd88041f 664 #endif
group-Avnet 0:478cfd88041f 665
group-Avnet 0:478cfd88041f 666 if(rf_device == NULL) {
group-Avnet 0:478cfd88041f 667 rf_device = &SimpleSpirit1::CreateInstance(_spi_mosi, _spi_miso, _spi_sclk, _dev_irq, _dev_cs, _dev_sdn, _brd_led);
group-Avnet 0:478cfd88041f 668 rf_device->attach_irq_callback(rf_callback_func);
group-Avnet 0:478cfd88041f 669
group-Avnet 0:478cfd88041f 670 #ifndef NDEBUG
group-Avnet 0:478cfd88041f 671 ret =
group-Avnet 0:478cfd88041f 672 #endif
group-Avnet 0:478cfd88041f 673 rf_ack_sender.start(rf_ack_loop);
group-Avnet 0:478cfd88041f 674
group-Avnet 0:478cfd88041f 675 #ifndef NDEBUG
group-Avnet 0:478cfd88041f 676 debug_if(!(ret == osOK), "\n\rassert failed in: %s (%d)\n\r", __func__, __LINE__);
group-Avnet 0:478cfd88041f 677 #endif
group-Avnet 0:478cfd88041f 678 }
group-Avnet 0:478cfd88041f 679 }
group-Avnet 0:478cfd88041f 680
group-Avnet 0:478cfd88041f 681 NanostackRfPhySpirit1::NanostackRfPhySpirit1(PinName spi_mosi, PinName spi_miso, PinName spi_sclk,
group-Avnet 0:478cfd88041f 682 PinName dev_irq, PinName dev_cs, PinName dev_sdn, PinName brd_led) :
group-Avnet 0:478cfd88041f 683 _spi_mosi(spi_mosi),
group-Avnet 0:478cfd88041f 684 _spi_miso(spi_miso),
group-Avnet 0:478cfd88041f 685 _spi_sclk(spi_sclk),
group-Avnet 0:478cfd88041f 686 _dev_irq(dev_irq),
group-Avnet 0:478cfd88041f 687 _dev_cs(dev_cs),
group-Avnet 0:478cfd88041f 688 _dev_sdn(dev_sdn),
group-Avnet 0:478cfd88041f 689 _brd_led(brd_led)
group-Avnet 0:478cfd88041f 690 {
group-Avnet 0:478cfd88041f 691 /* Nothing to do */
group-Avnet 0:478cfd88041f 692 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 693 }
group-Avnet 0:478cfd88041f 694
group-Avnet 0:478cfd88041f 695 NanostackRfPhySpirit1::~NanostackRfPhySpirit1()
group-Avnet 0:478cfd88041f 696 {
group-Avnet 0:478cfd88041f 697 /* Nothing to do */
group-Avnet 0:478cfd88041f 698 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 699 }
group-Avnet 0:478cfd88041f 700
group-Avnet 0:478cfd88041f 701 int8_t NanostackRfPhySpirit1::rf_register()
group-Avnet 0:478cfd88041f 702 {
group-Avnet 0:478cfd88041f 703 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 704
group-Avnet 0:478cfd88041f 705 /* Get Lock */
group-Avnet 0:478cfd88041f 706 rf_if_lock();
group-Avnet 0:478cfd88041f 707
group-Avnet 0:478cfd88041f 708 /* Do some initialization */
group-Avnet 0:478cfd88041f 709 rf_init();
group-Avnet 0:478cfd88041f 710
group-Avnet 0:478cfd88041f 711 /* Set pointer to MAC address */
group-Avnet 0:478cfd88041f 712 device_driver.PHY_MAC = stored_mac_address;
group-Avnet 0:478cfd88041f 713
group-Avnet 0:478cfd88041f 714 /* Set driver Name */
group-Avnet 0:478cfd88041f 715 device_driver.driver_description = (char*)"Spirit1 Sub-GHz RF";
group-Avnet 0:478cfd88041f 716
group-Avnet 0:478cfd88041f 717 /*Type of RF PHY is SubGHz*/
group-Avnet 0:478cfd88041f 718 device_driver.link_type = PHY_LINK_15_4_SUBGHZ_TYPE;
group-Avnet 0:478cfd88041f 719
group-Avnet 0:478cfd88041f 720 /*Maximum size of payload*/
group-Avnet 0:478cfd88041f 721 device_driver.phy_MTU = MAX_PACKET_LEN;
group-Avnet 0:478cfd88041f 722
group-Avnet 0:478cfd88041f 723 /*No header in PHY*/
group-Avnet 0:478cfd88041f 724 device_driver.phy_header_length = 0;
group-Avnet 0:478cfd88041f 725
group-Avnet 0:478cfd88041f 726 /*No tail in PHY*/
group-Avnet 0:478cfd88041f 727 device_driver.phy_tail_length = 0;
group-Avnet 0:478cfd88041f 728
group-Avnet 0:478cfd88041f 729 /*Set up driver functions*/
group-Avnet 0:478cfd88041f 730 device_driver.address_write = &rf_address_write;
group-Avnet 0:478cfd88041f 731 device_driver.extension = &rf_extension;
group-Avnet 0:478cfd88041f 732 device_driver.state_control = &rf_interface_state_control;
group-Avnet 0:478cfd88041f 733 device_driver.tx = &rf_trigger_send;
group-Avnet 0:478cfd88041f 734
group-Avnet 0:478cfd88041f 735 /*Set supported channel pages*/
group-Avnet 0:478cfd88041f 736 device_driver.phy_channel_pages = phy_channel_pages;
group-Avnet 0:478cfd88041f 737
group-Avnet 0:478cfd88041f 738 //Nullify rx/tx callbacks
group-Avnet 0:478cfd88041f 739 device_driver.phy_rx_cb = NULL;
group-Avnet 0:478cfd88041f 740 device_driver.phy_tx_done_cb = NULL;
group-Avnet 0:478cfd88041f 741 device_driver.arm_net_virtual_rx_cb = NULL;
group-Avnet 0:478cfd88041f 742 device_driver.arm_net_virtual_tx_cb = NULL;
group-Avnet 0:478cfd88041f 743
group-Avnet 0:478cfd88041f 744 /*Register device driver*/
group-Avnet 0:478cfd88041f 745 rf_radio_driver_id = arm_net_phy_register(&device_driver);
group-Avnet 0:478cfd88041f 746
group-Avnet 0:478cfd88041f 747 /* Release Lock */
group-Avnet 0:478cfd88041f 748 rf_if_unlock();
group-Avnet 0:478cfd88041f 749
group-Avnet 0:478cfd88041f 750 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 751 return rf_radio_driver_id;
group-Avnet 0:478cfd88041f 752 }
group-Avnet 0:478cfd88041f 753
group-Avnet 0:478cfd88041f 754 void NanostackRfPhySpirit1::rf_unregister()
group-Avnet 0:478cfd88041f 755 {
group-Avnet 0:478cfd88041f 756 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 757
group-Avnet 0:478cfd88041f 758 /* Get Lock */
group-Avnet 0:478cfd88041f 759 rf_if_lock();
group-Avnet 0:478cfd88041f 760
group-Avnet 0:478cfd88041f 761 if (rf_radio_driver_id >= 0) {
group-Avnet 0:478cfd88041f 762 arm_net_phy_unregister(rf_radio_driver_id);
group-Avnet 0:478cfd88041f 763 rf_radio_driver_id = -1;
group-Avnet 0:478cfd88041f 764 }
group-Avnet 0:478cfd88041f 765
group-Avnet 0:478cfd88041f 766 /* Release Lock */
group-Avnet 0:478cfd88041f 767 rf_if_unlock();
group-Avnet 0:478cfd88041f 768 }
group-Avnet 0:478cfd88041f 769
group-Avnet 0:478cfd88041f 770 void NanostackRfPhySpirit1::get_mac_address(uint8_t *mac)
group-Avnet 0:478cfd88041f 771 {
group-Avnet 0:478cfd88041f 772 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 773
group-Avnet 0:478cfd88041f 774 /* Get Lock */
group-Avnet 0:478cfd88041f 775 rf_if_lock();
group-Avnet 0:478cfd88041f 776
group-Avnet 0:478cfd88041f 777 if(rf_radio_driver_id >= 0) {
group-Avnet 0:478cfd88041f 778 rf_get_mac_address(mac);
group-Avnet 0:478cfd88041f 779 } else {
group-Avnet 0:478cfd88041f 780 error("NanostackRfPhySpirit1 must be registered to read mac address");
group-Avnet 0:478cfd88041f 781 }
group-Avnet 0:478cfd88041f 782
group-Avnet 0:478cfd88041f 783 /* Release Lock */
group-Avnet 0:478cfd88041f 784 rf_if_unlock();
group-Avnet 0:478cfd88041f 785 }
group-Avnet 0:478cfd88041f 786
group-Avnet 0:478cfd88041f 787 void NanostackRfPhySpirit1::set_mac_address(uint8_t *mac)
group-Avnet 0:478cfd88041f 788 {
group-Avnet 0:478cfd88041f 789 tr_debug("%s (%d)", __func__, __LINE__);
group-Avnet 0:478cfd88041f 790
group-Avnet 0:478cfd88041f 791 /* Get Lock */
group-Avnet 0:478cfd88041f 792 rf_if_lock();
group-Avnet 0:478cfd88041f 793
group-Avnet 0:478cfd88041f 794 if(rf_radio_driver_id < 0) {
group-Avnet 0:478cfd88041f 795 rf_set_mac_address(mac);
group-Avnet 0:478cfd88041f 796 } else {
group-Avnet 0:478cfd88041f 797 error("NanostackRfPhySpirit1 cannot change mac address when running");
group-Avnet 0:478cfd88041f 798 }
group-Avnet 0:478cfd88041f 799
group-Avnet 0:478cfd88041f 800 /* Release Lock */
group-Avnet 0:478cfd88041f 801 rf_if_unlock();
group-Avnet 0:478cfd88041f 802 }