source: ReferenceDesigns/w3_802.11/c/wlan_mac_low_dcf/wlan_mac_dcf.c

Last change on this file was 6319, checked in by chunter, 3 years ago

1.8.0 release wlan-mac-se

File size: 109.7 KB
Line 
1/** @file wlan_mac_dcf.c
2 *  @brief Distributed Coordination Function
3 *
4 *  This contains code to implement the 802.11 DCF.
5 *
6 *  @copyright Copyright 2013-2019, Mango Communications. All rights reserved.
7 *          Distributed under the Mango Communications Reference Design License
8 *              See LICENSE.txt included in the design archive or
9 *              at http://mangocomm.com/802.11/license
10 *
11 *  This file is part of the Mango 802.11 Reference Design (https://mangocomm.com/802.11)
12 */
13/***************************** Include Files *********************************/
14// Xilinx SDK includes
15#include "xparameters.h"
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include "xio.h"
20#include "xil_cache.h"
21
22
23// WLAN includes
24#include "wlan_platform_common.h"
25#include "wlan_platform_low.h"
26#include "wlan_mac_low.h"
27#include "wlan_mac_802_11_defs.h"
28#include "wlan_phy_util.h"
29#include "wlan_mac_dcf.h"
30#include "wlan_mac_dl_list.h"
31#include "wlan_mac_mgmt_tags.h"
32#include "wlan_mac_common.h"
33#include "wlan_mac_pkt_buf_util.h"
34#include "wlan_mac_low.h"
35#include "wlan_mac_mailbox_util.h"
36#include "wlan_platform_debug_hdr.h"
37
38// WLAN Exp includes
39#include "wlan_exp.h"
40
41
42/*************************** Constant Definitions ****************************/
43#define DBG_PRINT 0
44#define WLAN_EXP_TYPE_DESIGN_80211_CPU_LOW WLAN_EXP_LOW_SW_ID_DCF
45#define DEFAULT_TX_ANTENNA_MODE TX_ANTMODE_SISO_ANTA
46#define RX_LEN_THRESH 200
47
48
49/*********************** Global Variable Definitions *************************/
50
51static volatile u8 gl_eeprom_addr[MAC_ADDR_LEN]; ///< HW address of this node that is stored in the EEPROM
52static volatile mac_timing gl_mac_timing_values; ///< Struct of IFS values for the DCF. These are not constants because they depend on sample rate
53
54// Retry Limits & Backoff parameters
55static volatile u32 gl_stationShortRetryCount; ///< Station Short Retry Count (SSRC) variable
56static volatile u32 gl_stationLongRetryCount; ///< Station Long Retry Count (SLRC) variable
57static volatile u32 gl_cw_exp; ///< Current Contention Window exponent
58static volatile u8 gl_cw_exp_min; ///< Maximum Contention Window exponent
59static volatile u8 gl_cw_exp_max; ///< Minimum Contention Window exponent
60static volatile u32 gl_dot11RTSThreshold; ///< Length threshold (in bytes) for enabling/disabling RTS/CTS protection
61static volatile u32 gl_dot11ShortRetryLimit; ///< Short Retry Limit (i.e. not using RTS/CTS)
62static volatile u32 gl_dot11LongRetryLimit; ///< Long Retry Limit (i.e. using RTS/CTS)
63
64// Variables for shared state between Tx and Rx contexts for RTS/CTS
65static volatile u8 gl_waiting_for_response; ///< Informs the Rx context that Tx is expecting a control response
66static volatile u8 gl_long_mpdu_pkt_buf; ///< Packet buffer index for a long MPDU that should be sent in the frame reception context (i.e. CTS reception)
67
68// Beacon transmission & reception parameters
69volatile beacon_txrx_config_t gl_beacon_txrx_config; ///< Struct with configuration parameters regarding beacons
70volatile u8 gl_dtim_mcast_buffer_enable; ///< Informs the DCF whether or not to buffer multicast transmissions until the DTIM
71volatile u8 gl_dtim_count; ///< DTIM count for the current beacon interval
72
73// Variables for managing Tx packet buffer ready messages
74static dl_list gl_tx_pkt_buf_ready_list_general; ///< List of Tx packet buffer indices for to-be-sent packets in the general packet buffer group
75static dl_list gl_tx_pkt_buf_ready_list_dtim_mcast; ///< List of packet buffer indices for to-be-sent packets in the DTIM multicast packet buffer group
76static dl_list gl_tx_pkt_buf_ready_list_free;   ///< List of unused Tx packet buffers
77static dl_entry gl_tx_pkt_buf_entry[MAX_NUM_PENDING_TX_PKT_BUFS]; ///< Array of entries that will belong to one of the above lists
78static u8 gl_tx_pkt_buf_entry_data[MAX_NUM_PENDING_TX_PKT_BUFS]; ///< Byte array to serve as the data payload for the above entries
79
80// Common Platform Device Info
81platform_common_dev_info_t platform_common_dev_info;
82static u32 gl_tx_analog_latency_1us;
83static u32 gl_rx_analog_latency_1us;
84
85// Pre-calculated CTS durations
86// Array dimensions: [SampRate (0 - 10MSPS, 1 - 20MSPS, 2 - 40MSPS][MCS]
87// calculated via a loop over
88// wlan_ofdm_calc_txtime(sizeof(mac_header_80211_CTS) + WLAN_PHY_FCS_NBYTES, MCS, PHY_MODE_NONHT, SampRate));
89const u8 cts_duration_lookup[3][8] = {
90{94, 78, 70, 62, 62, 54, 54, 54},
91{50, 42, 38, 34, 34, 30, 30, 30},
92{28, 24, 22, 20, 20, 18, 18, 18}
93};
94
95
96// Precalculated durations for short (non-RTS) frames
97static u16 gl_precalc_duration[3][8]; ///< To improve reliability in achieving slot-0 transmissions, we precompute duration fields to insert into frames.
98
99/*************************** Functions Prototypes ****************************/
100
101void process_low_param(u8 mode, u32* payload); ///< Implementation of DCF-specific processing of low params from wlan_exp
102
103/******************************** Functions **********************************/
104
105int main() {
106    // Call the platform-supplied cpu_init() first to setup any
107    //  processor-specific settings to enable sane execution
108    //  of the platform and framework code below
109    wlan_platform_cpu_low_init();
110
111    u32 i, poll_tx_pkt_buf_list_return;
112    wlan_mac_hw_info_t* hw_info;
113
114    xil_printf("\f");
115    xil_printf("----- Mango 802.11 Reference Design -----\n");
116    xil_printf("----- v1.8.0 ----------------------------\n");
117    xil_printf("----- wlan_mac_dcf ----------------------\n");
118    xil_printf("Compiled %s %s\n\n", __DATE__, __TIME__);
119
120    xil_printf("Note: this UART is currently printing from CPU_LOW. To view prints from\n");
121    xil_printf("and interact with CPU_HIGH, raise the right-most User I/O DIP switch bit.\n");
122    xil_printf("This switch can be toggled any time while the design is running.\n\n");
123    xil_printf("------------------------\n");
124
125    wlan_mac_common_malloc_init();
126
127    gl_long_mpdu_pkt_buf = PKT_BUF_INVALID;
128    gl_waiting_for_response = 0;
129
130    gl_beacon_txrx_config.beacon_tx_mode = NO_BEACON_TX;
131    gl_beacon_txrx_config.ts_update_mode = NEVER_UPDATE;
132    gl_dtim_mcast_buffer_enable = 0;
133
134    bzero((void*)gl_beacon_txrx_config.bssid_match, MAC_ADDR_LEN);
135    bzero(gl_precalc_duration, sizeof(gl_precalc_duration));
136
137    gl_dot11ShortRetryLimit = 7;
138    gl_dot11LongRetryLimit = 4;
139
140    gl_cw_exp_min = 4;
141    gl_cw_exp_max = 10;
142
143    gl_dot11RTSThreshold = 2000;
144
145    gl_stationShortRetryCount = 0;
146    gl_stationLongRetryCount = 0;
147
148    wlan_mac_low_init(WLAN_EXP_TYPE_DESIGN_80211_CPU_LOW, __DATE__, __TIME__);
149
150    // Get the device info
151    platform_common_dev_info = wlan_platform_common_get_dev_info();
152
153    // Convert a platform-specific delay into units of microseconds so we can use it later
154    // without having to divide in timing-sensitive applications
155    gl_tx_analog_latency_1us = (platform_common_dev_info.tx_analog_latency_100ns + (10 / 2)) / 10;  //rounding divide by 10
156    gl_rx_analog_latency_1us = (platform_common_dev_info.rx_analog_latency_100ns + (10 / 2)) / 10;  //rounding divide by 10
157
158    gl_cw_exp = gl_cw_exp_min;
159
160    hw_info = get_mac_hw_info();
161    memcpy((void*)gl_eeprom_addr, hw_info->hw_addr_wlan, MAC_ADDR_LEN);
162
163    dl_list_init(&gl_tx_pkt_buf_ready_list_general);
164    dl_list_init(&gl_tx_pkt_buf_ready_list_dtim_mcast);
165    dl_list_init(&gl_tx_pkt_buf_ready_list_free);
166    for(i = 0; i < MAX_NUM_PENDING_TX_PKT_BUFS; i++){
167        gl_tx_pkt_buf_entry[i].data = &(gl_tx_pkt_buf_entry_data[i]);
168        dl_entry_insertEnd(&gl_tx_pkt_buf_ready_list_free,&(gl_tx_pkt_buf_entry[i]));
169    }
170
171    wlan_mac_low_set_frame_rx_callback((void*)frame_receive);
172    wlan_mac_low_set_beacon_txrx_config_callback((void*)configure_beacon_txrx);
173    wlan_mac_low_set_mactime_change_callback((void*)handle_mactime_change);
174    wlan_mac_low_set_ipc_low_param_callback((void*)process_low_param);
175    wlan_mac_low_set_sample_rate_change_callback((void*)handle_sample_rate_change);
176    wlan_mac_low_set_handle_tx_pkt_buf_ready((void*)handle_tx_pkt_buf_ready);
177    wlan_mac_low_set_mcast_buffer_enable_callback((void*)handle_mcast_buffer_enable);
178
179
180    // wlan_mac_low_init() has placed a mutex lock on TX_PKT_BUF_ACK_CTS and
181    // TX_PKT_BUF_RTS already. We should set their packet buffer states to LOW_CTRL
182    ((tx_frame_info_t*)CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, TX_PKT_BUF_ACK_CTS))->tx_pkt_buf_state = TX_PKT_BUF_LOW_CTRL;
183    ((tx_frame_info_t*)CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, TX_PKT_BUF_RTS))->tx_pkt_buf_state = TX_PKT_BUF_LOW_CTRL;
184
185    wlan_mac_low_init_finish();
186
187    // Print DCF information to the terminal
188    xil_printf("------------------------\n");
189    xil_printf("WLAN MAC DCF boot complete: \n");
190    xil_printf("  Serial Number     : W3-a-%05d\n", hw_info->serial_number);
191    xil_printf("  Wireless MAC Addr : %02x:%02x:%02x:%02x:%02x:%02x\n\n", gl_eeprom_addr[0], gl_eeprom_addr[1], gl_eeprom_addr[2], gl_eeprom_addr[3], gl_eeprom_addr[4], gl_eeprom_addr[5]);
192
193    while(1){
194
195        // Poll PHY RX start
196        gl_waiting_for_response = 0;
197        wlan_mac_low_poll_frame_rx();
198
199        // Poll IPC rx
200        wlan_mac_low_poll_ipc_rx();
201
202        // Poll for new Tx Ready
203
204        do {
205            poll_tx_pkt_buf_list_return = poll_tx_pkt_buf_list(PKT_BUF_GROUP_GENERAL);
206        } while( poll_tx_pkt_buf_list_return & POLL_TX_PKT_BUF_LIST_RETURN_TRANSMITTED);
207
208
209        // Poll the timestamp (for periodic transmissions like beacons)
210        poll_tbtt_and_send_beacon();
211    }
212    return 0;
213}
214
215/*****************************************************************************/
216/**
217 * @brief Handle change to DTIM multicast buffer enable bit
218 *
219 * The transition between buffering DTIM multicast packets to not (and vice versa)
220 * requires inspecition of the to-be-sent list of ready packet buffers. This function
221 * calls a subfunction to perform this inspection and toggles the top-level global
222 * variable that indicates whether or not DTIM multicast buffering is enabled.
223 *
224 * @param   u32     enable      1 for enabled buffering, 0 for disabled buffering
225 * @return  None
226 */
227void handle_mcast_buffer_enable(u32 enable){
228    gl_dtim_mcast_buffer_enable = enable;
229    update_tx_pkt_buf_lists();
230}
231
232/*****************************************************************************/
233/**
234 * @brief Update packet buffer lists
235 *
236 * This function will merge the gl_tx_pkt_buf_ready_list_general and gl_tx_pkt_buf_ready_list_dtim_mcast
237 * lists into the gl_tx_pkt_buf_ready_list_general list only when DTIM multicast buffering is disabled.
238 * When enabled, members of gl_tx_pkt_buf_ready_list_general with a multicast RA will be removed from the
239 * list and placed into gl_tx_pkt_buf_ready_list_dtim_mcast.
240 *
241 * @param   None
242 * @return  None
243 */
244void update_tx_pkt_buf_lists(){
245    int iter;
246    u8 pkt_buf;
247    tx_frame_info_t* tx_frame_info;
248
249    dl_entry* curr_entry;
250    dl_entry* next_entry;
251
252    if( (gl_dtim_mcast_buffer_enable == 1) && (gl_beacon_txrx_config.beacon_tx_mode != NO_BEACON_TX) ) {
253        // DTIM buffering is enabled. We need to move any PKT_BUF_GROUP_DTIM_MCAST packets out of gl_tx_pkt_buf_ready_list_general
254        // and into gl_tx_pkt_buf_ready_list_dtim_mcast.
255
256        iter = gl_tx_pkt_buf_ready_list_general.length;
257        next_entry = gl_tx_pkt_buf_ready_list_general.first;
258
259        while( (next_entry != NULL) && (iter-- > 0) ){
260
261            curr_entry = next_entry;
262            next_entry = dl_entry_next(next_entry);
263
264            pkt_buf = *( (u8*)curr_entry->data);
265
266            tx_frame_info = (tx_frame_info_t*)  (CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, pkt_buf));
267            mac_header_80211* header = (mac_header_80211*) (CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, pkt_buf) + PHY_TX_PKT_BUF_MPDU_OFFSET);
268
269            // The pkt_buf_group_t in the frame_info_t cannot be used to find the existing multicast packets in the
270            // general list. When DTIM multicast buffering is disabled, all pkt_buf_group_t are PKT_BUF_GROUP_GENERAL.
271            // So, instead, we will inspect the RA of the to-be-transmitted packets to find ones that are multicast.
272            if(((tx_frame_info->flags & TX_FRAME_INFO_FLAGS_PKT_BUF_PREPARED) == 0) && wlan_addr_mcast(header->address_1)){
273                tx_frame_info->queue_info.pkt_buf_group = PKT_BUF_GROUP_DTIM_MCAST;
274                dl_entry_remove(&gl_tx_pkt_buf_ready_list_general, curr_entry);
275                dl_entry_insertEnd(&gl_tx_pkt_buf_ready_list_dtim_mcast, curr_entry);
276            }
277        }
278    } else if( (gl_dtim_mcast_buffer_enable == 0) || (gl_beacon_txrx_config.beacon_tx_mode == NO_BEACON_TX) ) {
279            // DTIM buffering is disabled. We need to merge gl_tx_pkt_buf_ready_list_general and gl_tx_pkt_buf_ready_list_dtim_mcast and
280            // assigned all packet buffer groups to PKT_BUF_GROUP_GENERAL.
281
282            // It is possible that MAC Tx Controller D is currently paused with a frame to be transmitted. In this context, we can
283            // safely reset the state of that controller and then force the pause bit to 0.
284            wlan_mac_reset_tx_ctrl_D(1);
285            wlan_mac_reset_tx_ctrl_D(0);
286            wlan_mac_pause_tx_ctrl_D(0);
287
288            iter = gl_tx_pkt_buf_ready_list_dtim_mcast.length;
289            next_entry = gl_tx_pkt_buf_ready_list_dtim_mcast.first;
290
291            while( (next_entry != NULL) && (iter-- > 0) ){
292
293                curr_entry = next_entry;
294                next_entry = dl_entry_next(next_entry);
295
296                pkt_buf = *((u8*)curr_entry->data);
297
298                tx_frame_info   = (tx_frame_info_t*)  (CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, pkt_buf));
299                if(((tx_frame_info->flags & TX_FRAME_INFO_FLAGS_PKT_BUF_PREPARED) == 0)){
300                    tx_frame_info->queue_info.pkt_buf_group = PKT_BUF_GROUP_GENERAL;
301                    dl_entry_remove(&gl_tx_pkt_buf_ready_list_dtim_mcast, curr_entry);
302                    dl_entry_insertEnd(&gl_tx_pkt_buf_ready_list_general, curr_entry);
303                }
304            }
305        }
306
307}
308
309/*****************************************************************************/
310/**
311 * @brief Handle sample rate change
312 *
313 * A change in sample rate needs to be reflected in MAC timings. This function is
314 * provides with an argument of what the new sample rate is so that it can make
315 * the appropriate changes.
316 *
317 * @param   u32     phy_samp_rate_t     - Sample rate enum
318 * @return  None
319 */
320void handle_sample_rate_change(phy_samp_rate_t phy_samp_rate){
321    // TODO: Add an argument to specify the phy_mode in case that changes MAC timings
322    u8 idx_phy_mode, idx_mcs;
323    u8 phy_mode, mcs;
324
325    switch(phy_samp_rate){
326        default:
327        case PHY_40M:
328        case PHY_20M:
329            gl_mac_timing_values.t_slot = 9;
330            gl_mac_timing_values.t_sifs = 10;
331            gl_mac_timing_values.t_difs = gl_mac_timing_values.t_sifs + (2*gl_mac_timing_values.t_slot);
332            gl_mac_timing_values.t_eifs = 88;
333            gl_mac_timing_values.t_phy_rx_start_dly = 25; //TODO: This is BW dependent. 20/25 is waveform time.
334            gl_mac_timing_values.t_timeout = gl_mac_timing_values.t_sifs + gl_mac_timing_values.t_slot + gl_mac_timing_values.t_phy_rx_start_dly;
335        break;
336        case PHY_10M:
337            gl_mac_timing_values.t_slot = 13;
338            gl_mac_timing_values.t_sifs = 10;
339            gl_mac_timing_values.t_difs = gl_mac_timing_values.t_sifs + (2*gl_mac_timing_values.t_slot);
340            gl_mac_timing_values.t_eifs = 88;
341            gl_mac_timing_values.t_phy_rx_start_dly = 45;
342            gl_mac_timing_values.t_timeout = gl_mac_timing_values.t_sifs + gl_mac_timing_values.t_slot + gl_mac_timing_values.t_phy_rx_start_dly;
343        break;
344    }
345
346    // MAC timing parameters are in terms of units of 100 nanoseconds
347    wlan_mac_set_slot(gl_mac_timing_values.t_slot*10);
348    wlan_mac_set_DIFS((gl_mac_timing_values.t_difs)*10);
349    wlan_mac_set_TxDIFS(((gl_mac_timing_values.t_difs)*10) - (platform_common_dev_info.tx_analog_latency_100ns + platform_common_dev_info.tx_radio_prep_latency_100ns));
350
351    // Use postTx timer 2 for ACK timeout
352    wlan_mac_set_postTx_timer2(gl_mac_timing_values.t_timeout * 10);
353    wlan_mac_postTx_timer2_en(1);
354
355    // Use postRx timer 1 for SIFS
356    wlan_mac_set_postRx_timer1((gl_mac_timing_values.t_sifs*10)-(platform_common_dev_info.tx_analog_latency_100ns + platform_common_dev_info.tx_radio_prep_latency_100ns));
357    wlan_mac_postRx_timer1_en(1);
358
359    // TODO: NAV adjust needs verification
360    //     NAV adjust time - signed char (Fix8_0) value
361    wlan_mac_set_NAV_adj(0*10);
362    wlan_mac_set_EIFS(gl_mac_timing_values.t_eifs*10);
363
364    // Precompute duration values;
365    for (idx_phy_mode = 1; idx_phy_mode < 3; idx_phy_mode++){
366        for(idx_mcs = 0; idx_mcs < 8; idx_mcs++){
367
368            //Map indices onto PHY mode and MCS.
369            phy_mode = idx_phy_mode;
370            mcs = wlan_mac_low_mcs_to_ctrl_resp_mcs(idx_mcs, phy_mode);
371
372            gl_precalc_duration[idx_phy_mode][idx_mcs] = wlan_ofdm_calc_txtime(sizeof(mac_header_80211_ACK) + WLAN_PHY_FCS_NBYTES, mcs, PHY_MODE_NONHT, wlan_mac_low_get_phy_samp_rate()) + gl_mac_timing_values.t_sifs;
373        }
374    }
375
376}
377
378/*****************************************************************************/
379/**
380 * @brief Update DTIM count
381 *
382 * 10.1.3.2 in 802.11-2012 dictates that MAC Time 0 is, by definition, a DTIM. Based upon this single fact,
383 * a DTIM count can be explicitly calculated according to the current MAC time as well as the DTIM period.
384 * This function successfully does nothing it the beacon_tx_mode is something other than AP_BEACON_TX.
385 *
386 * @param   None
387 * @return  None
388 */
389void update_dtim_count(){
390    u32 current_tu;
391    u32 temp_var;
392    if( gl_beacon_txrx_config.beacon_tx_mode == AP_BEACON_TX ){
393        current_tu = (u32)(get_mac_time_usec()>>10);
394
395        if(gl_beacon_txrx_config.dtim_period != 0){
396            temp_var = ((current_tu/gl_beacon_txrx_config.beacon_interval_tu)+1)%gl_beacon_txrx_config.dtim_period;
397            if(temp_var == 0){
398                gl_dtim_count = 0;
399            } else {
400                gl_dtim_count = gl_beacon_txrx_config.dtim_period - temp_var;
401            }
402
403        } else {
404            gl_dtim_count = 0;
405        }
406    } else {
407        gl_dtim_count = 0;
408    }
409}
410
411/*****************************************************************************/
412/**
413 * @brief Update TU target
414 *
415 * This function sets the TU target to whenever the next TBTT occurs. It only performs
416 * this action if beacon_tx_mode is AP_BEACON_TX or IBSS_BEACON_TX
417 *
418 * @param   u8  recompute   - 0 for updating TU target via addition from previous target, 1 to recompute from MAC time
419 * @return  None
420 */
421void update_tu_target(u8 recompute) {
422    u64 current_tu = (get_mac_time_usec()>>10);
423    if(recompute) {
424        // Re-compute TU target from current MAC time
425
426        // Expensive u64 division
427        u64 tu_target =  gl_beacon_txrx_config.beacon_interval_tu * ((current_tu /  gl_beacon_txrx_config.beacon_interval_tu) + 1);
428
429        wlan_mac_set_tu_target(tu_target);
430
431    } else {
432        // Increment current TU target to the next-future target
433
434        while(1) {
435            u64 current_tu_target = wlan_mac_get_tu_target();
436            if(current_tu_target > current_tu) {
437                // Achieved future target - done
438                break;
439            }
440            else{
441                // Increment target and continue
442                wlan_mac_set_tu_target(current_tu_target + gl_beacon_txrx_config.beacon_interval_tu);
443            }
444        }
445    }
446}
447
448/*****************************************************************************/
449/**
450 * @brief Handle MAC time change
451 *
452 * If the MAC time has changed, we need to ensure that we update the TU target to
453 * to whatever the next TBTT is on the current timebase. Similarly, we must update
454 * the DTIM count for multicast buffering.
455 *
456 * @param   s64     time_delta_usec     - number of microseconds between the current time and the MAC time prior to the change
457 * @return  None
458 */
459void handle_mactime_change(s64 time_delta_usec){
460    update_dtim_count();
461    if((time_delta_usec < 0) || (time_delta_usec > (100*gl_beacon_txrx_config.beacon_interval_tu)) ){
462        //The MAC time change was either very large or moved us backwards in time. Either way, we can't rely on the
463        //"fast" TU target update and must instead explicitly recompute the target based upon the MAC time.
464        update_tu_target(1);
465    } else {
466        update_tu_target(0);
467    }
468    return;
469}
470
471/*****************************************************************************/
472/**
473 * @brief Configure beacon parameters
474 *
475 * The CPU_HIGH application will configure the DCF with whatever parameters it
476 * needs to know about beacon transmissions and receptions.
477 *
478 * @param   u32     phy_samp_rate_t     - Sample rate enum
479 * @return  None
480 */
481void configure_beacon_txrx(beacon_txrx_config_t* beacon_txrx_config){
482    memcpy((void*)&gl_beacon_txrx_config, beacon_txrx_config, sizeof(beacon_txrx_config_t));
483
484    update_tx_pkt_buf_lists();
485
486    if(( gl_beacon_txrx_config.beacon_tx_mode == AP_BEACON_TX ) ||
487       ( gl_beacon_txrx_config.beacon_tx_mode == IBSS_BEACON_TX )){
488
489        //Because we are setting up a new beacon configuration, we should not update the TU target
490        //based upon existing targets. We should instead explicitly recompute the target from the
491        //current MAC time and beacon interval
492        update_tu_target(1);
493        update_dtim_count();
494
495        wlan_mac_reset_tu_target_latch(1);
496        wlan_mac_reset_tu_target_latch(0);
497    }  else {
498        wlan_mac_set_tu_target(0xFFFFFFFF);
499        wlan_mac_reset_tu_target_latch(1);
500    }
501}
502
503/*****************************************************************************/
504/**
505 * @brief Poll for the TBTT and, if appropriate, send a beacon
506 *
507 * This function is the context that will pause the general transmission state machine
508 * (Tx Controller A) and send a beacon on a TBTT boundary. Furthermore. this function
509 * will proceed to send multicast frames after a DTIM beacon. If a second (or more)
510 * TBTTs occur while still in the context of this function, additional beacons and multicast
511 * frames will be sent on the proper boundaries.
512 *
513 * @param   None
514 * @return  None
515 */
516inline void poll_tbtt_and_send_beacon(){
517    u32 mac_tx_ctrl_status;
518    u32 send_beacon_return;
519    u32 prepare_frame_transmit_return;
520    u32 poll_tx_pkt_buf_list_return = 0;
521
522    if(( gl_beacon_txrx_config.beacon_tx_mode == AP_BEACON_TX ) ||
523       ( gl_beacon_txrx_config.beacon_tx_mode == IBSS_BEACON_TX )){
524
525        if( wlan_mac_check_tu_latch() ) {
526            // Current TU >= Target TU
527
528            // Attempt to pause the backoff counter in Tx controller A
529            wlan_mac_pause_tx_ctrl_A(1);
530
531            mac_tx_ctrl_status = wlan_mac_get_tx_ctrl_status();
532
533            // Check if Tx controller A is deferring (now with a paused backoff) or idle (no Tx pending)
534            if(((mac_tx_ctrl_status & WLAN_MAC_TXCTRL_STATUS_MASK_TX_A_STATE) == WLAN_MAC_TXCTRL_STATUS_TX_A_STATE_DEFER) ||
535               ((mac_tx_ctrl_status & WLAN_MAC_TXCTRL_STATUS_MASK_TX_A_STATE) == WLAN_MAC_TXCTRL_STATUS_TX_A_STATE_IDLE)) {
536
537                while( wlan_mac_check_tu_latch() ){
538                    // Note: on the first iteration of this loop, wlan_mac_check_tu_latch() has been called
539                    // twice. This is intentional. This structure ensures we do not toggle the pause state on
540                    // Tx controller A across many mcast transmissions spanning multiple beacon TBTTs
541
542                    prepare_frame_transmit_return = wlan_mac_low_lock_tx_pkt_buf(gl_beacon_txrx_config.beacon_template_pkt_buf);
543
544                    if(prepare_frame_transmit_return & PREPARE_FRAME_TRANSMIT_ERROR_UNEXPECTED_PKT_BUF_STATE){
545                        // Update TU target
546                        //  Changing TU target automatically resets TU_LATCH
547                        //  Latch will assert immediately if Current TU >= new Target TU
548                        update_tu_target(0);
549                        wlan_mac_pause_tx_ctrl_A(0);
550
551                        // Reset Tx Controller D and unpause
552                        wlan_mac_reset_tx_ctrl_D(1);
553                        wlan_mac_reset_tx_ctrl_D(0);
554                        wlan_mac_pause_tx_ctrl_D(0);
555                        return;
556                    }
557                    wlan_mac_low_prepare_frame_transmit( gl_beacon_txrx_config.beacon_template_pkt_buf );
558
559                    send_beacon_return = send_beacon(gl_beacon_txrx_config.beacon_template_pkt_buf);
560                    // Note: the above send_beacon() call will send the IPC message directly to CPU_HIGH
561                    // upon completion. We should not call wlan_mac_low_finish_frame_transmit() for the
562                    // beacon transmission. This slight asymmetry is a byproduct of different handling
563                    // of beacon packet buffer state (e.g. a beacon is TX_PKT_BUF_HIGH_CTRL when a
564                    // TX_LOW is being logged while other MPDUs remain in TX_PKT_BUF_LOW_CTRL for the
565                    // same logging operation).
566
567                    // Update TU target
568                    //  Changing TU target automatically resets TU_LATCH
569                    //  Latch will assert immediately if Current TU >= new Target TU
570                    update_tu_target(0);
571
572                    // Send mcast data here
573                    // We are only allowed to send mcast packets if either of two conditions are met:
574                    //  1) This is a DTIM beacon period
575                    //  2) The frame transmitted just prior the last beacon was a multicast packet whose MAC_FRAME_CTRL2_FLAG_MORE_DATA bit
576                    //     is 1. In this case, we are allowed to continue sending multicast packets in the current beacon interval regardless
577                    //     of DTIM (11.2.1.5.f 802.11-2007)
578                    if( ((send_beacon_return & SEND_BEACON_RETURN_DTIM) && (gl_dtim_mcast_buffer_enable == 1)) ||
579                        ((poll_tx_pkt_buf_list_return & POLL_TX_PKT_BUF_LIST_RETURN_TRANSMITTED) && (poll_tx_pkt_buf_list_return & POLL_TX_PKT_BUF_LIST_RETURN_MORE_DATA)) ||
580                         (poll_tx_pkt_buf_list_return & POLL_TX_PKT_BUF_LIST_RETURN_PAUSED)) {
581
582                        while( gl_tx_pkt_buf_ready_list_dtim_mcast.length > 0 ){
583                            // There is at least one mcast frame for us to send. We will loop over this list until either we have fully emptied it
584                            // or we are forced to buffer until the next DTIM.
585
586                            poll_tx_pkt_buf_list_return = poll_tx_pkt_buf_list(PKT_BUF_GROUP_DTIM_MCAST);
587                            // At this point in the code, either of two conditions have been met:
588                            //  1) An mcast packet has been sent and gl_tx_pkt_buf_ready_list_dtim_mcast.length has been decremented
589                            //  2) An mcast packet has been submitted to MAC Tx Controller D, but a TBTT boundary occured while the
590                            //     core was deferring.
591
592                            if( wlan_mac_check_tu_latch() ){
593                                // We just crossed a TBTT so we should send another beacon. Break
594                                // back to the top of the while( wlan_mac_check_tu_latch() ) loop.
595                                break;
596                            }
597
598                            if( (poll_tx_pkt_buf_list_return & POLL_TX_PKT_BUF_LIST_RETURN_TRANSMITTED) && ((poll_tx_pkt_buf_list_return & POLL_TX_PKT_BUF_LIST_RETURN_MORE_DATA) == 0 ) ) {
599                                // We sent the last mcast packet allowed in this beacon interval. We can now return all the way back to general
600                                // operation.
601                                wlan_mac_pause_tx_ctrl_A(0);
602                                return;
603                            }
604                        }
605                    }
606                }
607            }
608            wlan_mac_pause_tx_ctrl_A(0);
609        }
610    }
611    return;
612}
613
614
615/*****************************************************************************/
616/**
617 * @brief Send a beacon
618 *
619 * This function will send a beacon on Tx Controller C and then send the report
620 * of that message to CPU_HIGH via IPC messages.
621 *
622 * @param   None
623 * @return  None
624 */
625inline u32 send_beacon(u8 tx_pkt_buf){
626    // Note: it is assumed that this function is only called when it is safe to immediately
627    // transmit a beacon throuch MAC support core C. In other words, it is the responsibility
628    // of the calling function to ensure that any pending transmissions through MAC support
629    // core A have been successfully paused.
630
631    u32 return_status = 0;
632    wlan_ipc_msg_t ipc_msg_to_high;
633    wlan_mac_low_tx_details_t  __attribute__ ((aligned (4))) low_tx_details;
634    u32 mac_hw_status;
635    u16 n_slots;
636    u16 n_slots_readback;
637    int tx_gain;
638    u8 mpdu_tx_ant_mask;
639    //Note: This needs to be a volatile to allow the tx_pkt_buf_state to be re-read in the initial while loop below
640    volatile tx_frame_info_t* tx_frame_info = (tx_frame_info_t*) (CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, tx_pkt_buf));
641    mac_header_80211* header = (mac_header_80211*)(CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, tx_pkt_buf) + PHY_TX_PKT_BUF_MPDU_OFFSET);
642    tx_mode_t tx_mode;
643    u32 rx_status;
644    mgmt_tag_template_t* mgmt_tag_tim_template = NULL;
645    u8  tx_has_started = 0;
646
647    if(gl_beacon_txrx_config.dtim_tag_byte_offset != 0){
648        mgmt_tag_tim_template = (mgmt_tag_template_t*)((u8*)tx_frame_info + gl_beacon_txrx_config.dtim_tag_byte_offset);
649    }
650
651    // Compare the length of this frame to the RTS Threshold
652    if(tx_frame_info->length <= gl_dot11RTSThreshold) {
653        tx_mode = TX_MODE_SHORT;
654    } else {
655        tx_mode = TX_MODE_LONG;
656    }
657
658    if(mgmt_tag_tim_template != NULL){
659        if( (gl_beacon_txrx_config.dtim_period != 0) ){
660            // Update the DTIM count
661            mgmt_tag_tim_template->data[0] = gl_dtim_count;  //DTIM Count
662            if(gl_dtim_count == 0){
663                return_status |= SEND_BEACON_RETURN_DTIM;       
664            } 
665
666            //Note: while it is tempting to simply decrement the gl_dtim_count, this can lead to a bug
667            //in the event that a beacon is skipped because a previous beacon is deferred across the following
668            //TBTT. Instead, we should explicitly update the DTIM count according to the current MAC time
669            update_dtim_count();
670
671            //mgmt_tag_tim_template->data[1] = 1;  //DTIM Period -- Note: CPU_HIGH is responsible for filling this in during the TIM update
672
673            //Update the mcast TIM bitmap depending on the state of
674            if(gl_tx_pkt_buf_ready_list_dtim_mcast.length > 0) {
675                mgmt_tag_tim_template->data[2] |= 1;
676                mgmt_tag_tim_template->data[3] |= 1;
677            } else {
678                mgmt_tag_tim_template->data[2] &= 0xFE;
679                mgmt_tag_tim_template->data[3] &= 0xFE;
680            }
681
682        } else {
683            // DTIM buffering is disabled or there is an invalid DTIM period. Set the DTIM count and period to something sane
684            // Note: the mcast bit in the TIM bitmap is owned by CPU_HIGH in this case
685            mgmt_tag_tim_template->data[0] = 0;  //DTIM Count
686            mgmt_tag_tim_template->data[1] = 1;  //DTIM Period
687        }
688    }
689
690    // Configure the Tx antenna selection
691    mpdu_tx_ant_mask = 0;
692
693    switch(tx_frame_info->params.phy.antenna_mode) {
694        case TX_ANTMODE_SISO_ANTA:  mpdu_tx_ant_mask |= 0x1;  break;
695        case TX_ANTMODE_SISO_ANTB:  mpdu_tx_ant_mask |= 0x2;  break;
696        case TX_ANTMODE_SISO_ANTC:  mpdu_tx_ant_mask |= 0x4;  break;
697        case TX_ANTMODE_SISO_ANTD:  mpdu_tx_ant_mask |= 0x8;  break;
698        default:                    mpdu_tx_ant_mask  = 0x1;  break; // Default to RF_A
699    }
700
701    //wlan_mac_tx_ctrl_C_params(pktBuf, antMask, req_backoff, phy_mode, num_slots)
702    switch(gl_beacon_txrx_config.beacon_tx_mode){
703        case AP_BEACON_TX:
704            n_slots = rand_num_slots(RAND_SLOT_REASON_STANDARD_ACCESS);
705            wlan_mac_tx_ctrl_C_params(tx_pkt_buf, mpdu_tx_ant_mask, 0, tx_frame_info->params.phy.phy_mode, n_slots);
706        break;
707        case IBSS_BEACON_TX:
708            n_slots = rand_num_slots(RAND_SLOT_REASON_IBSS_BEACON);
709            wlan_mac_tx_ctrl_C_params(tx_pkt_buf, mpdu_tx_ant_mask, 1, tx_frame_info->params.phy.phy_mode, n_slots);
710        break;
711        case NO_BEACON_TX:
712            return WLAN_FAILURE;
713        break;
714    }
715
716    tx_gain = wlan_platform_tx_power_to_gain_target(tx_frame_info->params.phy.power);
717    wlan_mac_tx_ctrl_C_gains(tx_gain, tx_gain, tx_gain, tx_gain);
718
719    write_phy_preamble(tx_pkt_buf,
720                       tx_frame_info->params.phy.phy_mode,
721                       tx_frame_info->params.phy.mcs,
722                       tx_frame_info->length);
723
724
725    wlan_mac_tx_ctrl_C_start(1);
726    wlan_mac_tx_ctrl_C_start(0);
727
728    // Immediately re-read the current slot count.
729    n_slots_readback = wlan_mac_get_backoff_count_C();
730
731    if((n_slots != n_slots_readback)){
732        // For the first transmission (non-retry) of an MPDU, the number of
733        // slots used by the backoff process is ambiguous. The n_slots we provided
734        // to wlan_mac_tx_ctrl_A_params is only a suggestion. If the medium has been
735        // idle for a DIFS, then there will not be a backoff. Or, if another backoff is
736        // currently running, the MAC Config Core A will inherit that backoff. By
737        // immediately reading back the slot count after starting the core, we can
738        // overwrite the number of slots that we will fill into low_tx_details with
739        // the correct value
740        n_slots = n_slots_readback;
741    }
742
743    tx_frame_info->num_tx_attempts   = 1;
744    tx_frame_info->phy_samp_rate     = wlan_mac_low_get_phy_samp_rate();
745
746    // Here, we are overloading the "enqueue" timestamp to mean something subtly different
747    //  than when it is used for data MPDUs since beacons are not created and enqueued in
748    //  CPU_HIGH. By explicitly filling the current MAC time into the create timestamp,
749    //  we allow CPU_HIGH to determine whether or not a backoff occurred before the beacon transmission
750    //  when it is creating the TX_LOW log entry for the beacon.
751    tx_frame_info->queue_info.enqueue_timestamp  = get_mac_time_usec();
752    tx_frame_info->timestamp_accept  = 0;
753
754    low_tx_details.tx_details_type  = TX_DETAILS_MPDU;
755    low_tx_details.phy_params_mpdu.mcs          = tx_frame_info->params.phy.mcs;
756    low_tx_details.phy_params_mpdu.phy_mode     = tx_frame_info->params.phy.phy_mode;
757    low_tx_details.phy_params_mpdu.power        = tx_frame_info->params.phy.power;
758    low_tx_details.phy_params_mpdu.antenna_mode = tx_frame_info->params.phy.antenna_mode;
759
760    low_tx_details.chan_num = wlan_mac_low_get_active_channel();
761    low_tx_details.cw       = (1 << gl_cw_exp)-1; //(2^(gl_cw_exp) - 1)
762    low_tx_details.ssrc     = gl_stationShortRetryCount;
763    low_tx_details.slrc     = gl_stationLongRetryCount;
764    low_tx_details.src      = 0;
765    low_tx_details.lrc      = 0;
766    low_tx_details.flags    = 0;
767
768    // The pre-Tx backoff may not occur for the initial transmission attempt. If the medium has been idle for >DIFS when
769    //  the first Tx occurs the DCF state machine will not start a backoff. The upper-level MAC should compare the num_slots value
770    //  to the time delta between the accept and start times of the first transmission to determine whether the pre-Tx backoff
771    //  actually occurred.
772    low_tx_details.num_slots = n_slots;
773    low_tx_details.attempt_number = 1;
774
775     // Wait for the MPDU Tx to finish
776    do { // while(tx_status & WLAN_MAC_STATUS_MASK_TX_C_PENDING)
777
778        // Poll the DCF core status register
779        mac_hw_status = wlan_mac_get_status();
780        if( (mac_hw_status & WLAN_MAC_STATUS_MASK_TX_PHY_ACTIVE) && (tx_has_started == 0)){
781            if((tx_frame_info->flags) & TX_FRAME_INFO_FLAGS_FILL_TIMESTAMP){
782                // Insert the TX START timestamp
783                *((u64*)(((u8*)header + 24))) = ((u64)wlan_mac_low_get_tx_start_timestamp())+T_TIMESTAMP_FIELD_OFFSET;
784            }
785            tx_has_started = 1;
786        }
787
788
789        if( mac_hw_status & WLAN_MAC_STATUS_MASK_TX_C_DONE ) {
790            // Transmission is complete
791
792            switch(tx_mode) {
793            //TODO: Resetting the SSRC and/or SLRC needs to be checked back against the standard
794                case TX_MODE_SHORT:
795                    reset_ssrc();
796                    reset_cw();
797                break;
798                case TX_MODE_LONG:
799                    reset_slrc();
800                    reset_cw();
801                break;
802            }
803
804            low_tx_details.tx_start_timestamp_mpdu = wlan_mac_low_get_tx_start_timestamp();
805            low_tx_details.tx_start_timestamp_frac_mpdu = wlan_mac_low_get_tx_start_timestamp_frac();
806
807            // Start a post-Tx backoff using the updated contention window
808            //  If MAC Tx controller A backoff has been paused this backoff request will
809            //   successfully be ignored. If Tx A is idle then this backoff
810            //   will execute and future submission to Tx A may inherit the
811            //   this backoff.
812            // TODO: We should double check whether post-Tx backoffs are appropriate
813            n_slots = rand_num_slots(RAND_SLOT_REASON_STANDARD_ACCESS);
814            wlan_mac_dcf_hw_start_backoff(n_slots);
815
816        } else {
817            // Poll the MAC Rx state to check if a packet was received while our Tx was deferring
818            if (mac_hw_status & WLAN_MAC_STATUS_MASK_RX_PHY_STARTED) {
819                gl_waiting_for_response = 0;
820                rx_status = wlan_mac_low_poll_frame_rx();
821                // Check if the new reception met the conditions to cancel the already-submitted transmission
822                if (((rx_status & FRAME_RX_RET_CANCEL_TX) != 0)) {
823                    // The Rx handler halted this transmission already by resetting the MAC core
824                    // Our return_status should still be considered a success -- we successfully did not
825                    // transmit the beacon. This will tell the TBTT logic to move on to the next beacon interval
826                    // before attempting another beacon transmission.
827
828                    // We will not sent a BEACON_DONE IPC message to CPU_HIGH, so
829                    // tx_frame_info->tx_pkt_buf_state should remain READY
830                    tx_frame_info->tx_pkt_buf_state = TX_PKT_BUF_READY;
831                    if(unlock_tx_pkt_buf(tx_pkt_buf) != PKT_BUF_MUTEX_SUCCESS){
832                        xil_printf("Error: Unable to unlock Beacon packet buffer (beacon cancel)\n");
833                    }
834                    return_status |= SEND_BEACON_RETURN_CANCELLED;
835                    return return_status;
836                }
837
838            } else {
839                // Poll IPC rx
840                // TODO: Need to handle implications of an IPC message changing something like channel
841                wlan_mac_low_poll_ipc_rx();
842            }
843        } // END if(Tx A state machine done)
844    } while( mac_hw_status & WLAN_MAC_STATUS_MASK_TX_C_PENDING );
845
846    tx_frame_info->tx_pkt_buf_state = TX_PKT_BUF_DONE;
847    if(unlock_tx_pkt_buf(tx_pkt_buf) != PKT_BUF_MUTEX_SUCCESS) {
848        xil_printf("Error: Unable to unlock Beacon packet buffer (beacon sent) %d\n", unlock_tx_pkt_buf(tx_pkt_buf));
849    }
850    ipc_msg_to_high.msg_id            = IPC_MBOX_MSG_ID(IPC_MBOX_TX_BEACON_DONE);
851    ipc_msg_to_high.num_payload_words = sizeof(wlan_mac_low_tx_details_t)/sizeof(u32);
852    ipc_msg_to_high.arg0              = tx_pkt_buf;
853    ipc_msg_to_high.payload_ptr       = (u32*)&low_tx_details;
854    write_mailbox_msg(&ipc_msg_to_high);
855
856    //Enough time has passed in the transmission of this beacon that we should see if any new MPDUs
857    //are ready to send. This is particularly important for multicast packets that may need to be sent
858    //immediately folling a DTIM
859    wlan_mac_low_poll_ipc_rx();
860
861    return return_status;
862}
863
864/*****************************************************************************/
865/**
866 * @brief Handles reception of a wireless packet
867 *
868 * This function is called after a good SIGNAL field is detected by either PHY (OFDM or DSSS)
869 *
870 * It is the responsibility of this function to wait until a sufficient number of bytes have been received
871 * before it can start to process those bytes. When this function is called the eventual checksum status is
872 * unknown. The packet contents can be provisionally processed (e.g. prepare an ACK for fast transmission),
873 * but post-reception actions must be conditioned on the eventual FCS status (good or bad).
874 *
875 * NOTE: The timing of this function is critical for correct operation of the 802.11 DCF. It is not
876 *     safe to add large delays to this function (e.g. xil_printf or wlan_usleep)
877 *
878 * Two primary job responsibilities of this function:
879 *  (1): Prepare outgoing ACK packets and instruct the MAC_DCF_HW core whether or not to send ACKs
880 *  (2): Pass up MPDUs (FCS valid or invalid) to CPU_HIGH
881 *
882 * @param   rx_pkt_buf       - Index of the Rx packet buffer containing the newly received packet
883 * @param   phy_details      - Pointer to phy_rx_details struct containing PHY mode, MCS, and Length
884 * @return  u32              - Bit mask of flags indicating various results of the reception
885 */
886u32 frame_receive(u8 rx_pkt_buf, phy_rx_details_t* phy_details) {
887
888    // RX_LEN_THRESH is used to manage a potential pipeline bubble that can be used during a reception
889    // for processing:
890    //   - If the ongoing reception is >RX_LEN_THRESH, we will start
891    //     processing the frame and filling in metadata into the packet
892    //     buffer prior to calling wlan_mac_hw_rx_finish().
893    //   - If the ongoing reception is <RX_LEN_THRESH, we'll immediately
894    //     start polling the PHY with wlan_mac_hw_rx_finish() and,
895    //     if need be, configure a MAC Tx core to send a response.
896    //
897    // This structure handles any risk of response packets (e.g. an ACK) not being configured in time
898    // for the hard SIFS boundary.
899    //
900
901    int i;
902    u32 return_value = 0;
903    u32 tx_length;
904    u8 tx_mcs;
905    u16 cts_duration;
906    u8 unicast_to_me, to_multicast;
907    u8 active_rx_ant;
908    u32 rx_filter;
909    u8 report_to_mac_high;
910    int curr_tx_pow;
911    u8 ctrl_tx_gain;
912    u32 mac_tx_ctrl_status;
913    s64 time_delta;
914
915    u8 mpdu_tx_ant_mask = 0;
916    u8 ack_tx_ant = 0;
917    u8 tx_ant_mask = 0;
918    u8 num_resp_failures = 0;
919
920    rx_finish_state_t rx_finish_state = RX_FINISH_SEND_NONE;
921    tx_pending_state_t tx_pending_state = TX_PENDING_NONE;
922
923    rx_frame_info_t* rx_frame_info;
924    tx_frame_info_t* tx_frame_info;
925    mac_header_80211* rx_header;
926    u8* mac_payload_ptr_u8;
927
928    // Translate Rx pkt buf index into actual memory address
929    void* pkt_buf_addr = (void *) CALC_PKT_BUF_ADDR(platform_common_dev_info.rx_pkt_buf_baseaddr, rx_pkt_buf);
930
931    // Get pointer to MPDU info struct (stored at 0 offset in the pkt buffer)
932    rx_frame_info = (rx_frame_info_t*) pkt_buf_addr;
933
934    // Clear the MPDU info flags
935    rx_frame_info->flags = 0;
936
937    // Apply the mac_header_80211 template to the first bytes of the received MPDU
938    rx_header = (mac_header_80211*)((void*)(pkt_buf_addr + PHY_RX_PKT_BUF_MPDU_OFFSET));
939    mac_payload_ptr_u8 = (u8*)rx_header;
940
941    // Sanity check length value - anything shorter than an ACK must be bogus
942    if((phy_details->length) < (sizeof(mac_header_80211_ACK) + WLAN_PHY_FCS_NBYTES)) {
943        return return_value;
944    }
945
946    // Translate the rate index into the rate code used by the Tx PHY
947    //     This translation is required in case this reception needs to send an ACK, as the ACK
948    //     rate is a function of the rate of the received packet
949    //     The mapping of Rx rate to ACK rate is given in 9.7.6.5.2 of 802.11-2012
950    //
951    tx_mcs = wlan_mac_low_mcs_to_ctrl_resp_mcs(phy_details->mcs, phy_details->phy_mode);
952
953    // Determine which antenna the ACK will be sent from
954    //     The current implementation transmits ACKs from the same antenna over which the previous packet was received
955    //
956    active_rx_ant = (wlan_phy_rx_get_active_rx_ant());
957    tx_ant_mask = 0;
958
959    switch(active_rx_ant){
960        case RX_ACTIVE_ANTA:  tx_ant_mask |= 0x1;  break;
961        case RX_ACTIVE_ANTB:  tx_ant_mask |= 0x2;  break;
962        case RX_ACTIVE_ANTC:  tx_ant_mask |= 0x4;  break;
963        case RX_ACTIVE_ANTD:  tx_ant_mask |= 0x8;  break;
964        default:              tx_ant_mask  = 0x1;  break;            // Default to RF_A
965    }
966
967    // Wait until the PHY has written enough bytes so that the first address field can be processed
968    i = 0;
969    while(wlan_mac_get_last_byte_index() < MAC_HW_LASTBYTE_ADDR1) {
970        if(i++ > 1000000) {
971            xil_printf("Stuck waiting for MAC_HW_LASTBYTE_ADDR1: wlan_mac_get_last_byte_index() = %d\n", wlan_mac_get_last_byte_index());
972            xil_printf(" MAC HW Status: 0x%08x\n", wlan_mac_get_status());
973            xil_printf(" Rx Hdr Params: 0x%08x\n", wlan_mac_get_rx_phy_hdr_params());
974            xil_printf(" Rx PHY Status: 0x%08x\n", Xil_In32(WLAN_RX_STATUS));
975        }
976    };
977
978    // Check the destination address
979    unicast_to_me = wlan_addr_eq(rx_header->address_1, gl_eeprom_addr);
980    to_multicast = wlan_addr_mcast(rx_header->address_1);
981
982    // Prep outgoing ACK just in case it needs to be sent
983    //     ACKs are only sent for non-control frames addressed to this node
984    if(unicast_to_me && !WLAN_IS_CTRL_FRAME(rx_header)) {
985        // Auto TX Delay is in units of 100ns. This delay runs from RXEND of the preceding reception.
986        //     wlan_mac_tx_ctrl_B_params(pktBuf, antMask, req_zeroNAV, preWait_postRxTimer1, preWait_postRxTimer2, preWait_postTxTimer1, phy_mode)
987        wlan_mac_tx_ctrl_B_params(TX_PKT_BUF_ACK_CTS, tx_ant_mask, 0, 1, 0, 0, PHY_MODE_NONHT);
988
989        // ACKs are transmitted with a nominal Tx power used for all control packets
990        ctrl_tx_gain = wlan_platform_tx_power_to_gain_target(wlan_mac_low_get_current_ctrl_tx_pow());
991        wlan_mac_tx_ctrl_B_gains(ctrl_tx_gain, ctrl_tx_gain, ctrl_tx_gain, ctrl_tx_gain);
992
993
994        if((phy_details->length) >= MAC_HW_LASTBYTE_ADDR2){
995            // Wait until the PHY has written enough bytes so that the second address field can be processed
996            // If this is a short reception that does not have a second address, it is still possible to get
997            // to this line of code if there is an FCS error and the WLAN_IS_CTRL_FRAME check above fails.
998            // As such, we sanity check the length of the reception before getting into a potentially infinite
999            // loop.
1000            i = 0;
1001            while(wlan_mac_get_last_byte_index() < MAC_HW_LASTBYTE_ADDR2) {
1002                if(i++ > 1000000) {
1003                    xil_printf("Stuck waiting for MAC_HW_LASTBYTE_ADDR2: wlan_mac_get_last_byte_index() = %d\n", wlan_mac_get_last_byte_index());
1004                    xil_printf(" MAC HW Status: 0x%08x\n", wlan_mac_get_status());
1005                    xil_printf(" Rx Hdr Params: 0x%08x\n", wlan_mac_get_rx_phy_hdr_params());
1006                    xil_printf(" Rx PHY Status: 0x%08x\n", Xil_In32(WLAN_RX_STATUS));
1007                }
1008            };
1009        }
1010
1011        // Construct the ACK frame in the dedicated Tx pkt buf
1012        tx_length = wlan_create_ack_frame((void*)(CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, TX_PKT_BUF_ACK_CTS) + PHY_TX_PKT_BUF_MPDU_OFFSET), rx_header->address_2);
1013
1014        // Write the SIGNAL field for the ACK
1015        write_phy_preamble(TX_PKT_BUF_ACK_CTS, PHY_MODE_NONHT, tx_mcs, tx_length);
1016
1017        rx_finish_state = RX_FINISH_SEND_B;
1018
1019        rx_frame_info->resp_low_tx_details.tx_details_type     = TX_DETAILS_ACK;
1020        rx_frame_info->resp_low_tx_details.phy_params_ctrl.mcs = tx_mcs;
1021
1022        // We let "duration" be equal to the duration field of an ACK. This value is provided explicitly to CPU_HIGH
1023        // in the low_tx_details struct such that CPU_HIGH has can reconstruct the RTS in its log. This isn't critical
1024        // to the operation of the DCF, but is critical for the logging framework.
1025        //
1026        rx_frame_info->resp_low_tx_details.duration = 0;
1027
1028        // This element remains unused during MPDU-only transmissions
1029        rx_frame_info->resp_low_tx_details.phy_params_ctrl.phy_mode     = PHY_MODE_NONHT;
1030        rx_frame_info->resp_low_tx_details.phy_params_ctrl.power        = wlan_mac_low_get_current_ctrl_tx_pow();
1031
1032        switch(tx_ant_mask) {
1033            case 0x1:  ack_tx_ant = TX_ANTMODE_SISO_ANTA; break;
1034            case 0x2:  ack_tx_ant = TX_ANTMODE_SISO_ANTB; break;
1035            case 0x4:  ack_tx_ant = TX_ANTMODE_SISO_ANTC; break;
1036            case 0x8:  ack_tx_ant = TX_ANTMODE_SISO_ANTD; break;
1037            default:   ack_tx_ant = TX_ANTMODE_SISO_ANTA; break;   // Default to RF_A
1038        }
1039
1040        rx_frame_info->resp_low_tx_details.phy_params_ctrl.antenna_mode = ack_tx_ant;
1041
1042    } else if(unicast_to_me && (rx_header->frame_control_1 == MAC_FRAME_CTRL1_SUBTYPE_CTS)){
1043        if(gl_long_mpdu_pkt_buf != PKT_BUF_INVALID) {
1044            // We have an outgoing data frame we should send
1045            //     - Configure the Tx antenna selection
1046            //     - The frame_transmit() context already configured the SIGNAL field,
1047            //       so we do not have to worry about it in this context
1048            //
1049            tx_frame_info = (tx_frame_info_t*) (CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, gl_long_mpdu_pkt_buf));
1050
1051            switch(tx_frame_info->params.phy.antenna_mode) {
1052                case TX_ANTMODE_SISO_ANTA:  mpdu_tx_ant_mask |= 0x1;  break;
1053                case TX_ANTMODE_SISO_ANTB:  mpdu_tx_ant_mask |= 0x2;  break;
1054                case TX_ANTMODE_SISO_ANTC:  mpdu_tx_ant_mask |= 0x4;  break;
1055                case TX_ANTMODE_SISO_ANTD:  mpdu_tx_ant_mask |= 0x8;  break;
1056                default:                    mpdu_tx_ant_mask  = 0x1;  break;   // Default to RF_A
1057            }
1058
1059            // Configure the Tx power - update all antennas, even though only one will be used
1060            curr_tx_pow = wlan_platform_tx_power_to_gain_target(tx_frame_info->params.phy.power);
1061            wlan_mac_tx_ctrl_A_gains(curr_tx_pow, curr_tx_pow, curr_tx_pow, curr_tx_pow);
1062            wlan_mac_tx_ctrl_A_params(gl_long_mpdu_pkt_buf, mpdu_tx_ant_mask, 0, 1, 0, 1, tx_frame_info->params.phy.phy_mode); //Use postRx timer 1 and postTx_timer2
1063
1064            rx_finish_state = RX_FINISH_SEND_A;
1065
1066            return_value |= FRAME_RX_RET_TYPE_CTS;
1067        } else {
1068            //Unexpected CTS to me.
1069            //This clause can execute on a bad FCS (e.g. it's actually a bad FCS ACK)
1070        }
1071    } else if(unicast_to_me && (rx_header->frame_control_1 == MAC_FRAME_CTRL1_SUBTYPE_RTS)){
1072
1073        // We need to send a CTS
1074        //     Auto TX Delay is in units of 100ns. This delay runs from RXEND of the preceding reception.
1075        //     wlan_mac_tx_ctrl_B_params(pktBuf, antMask, req_zeroNAV, preWait_postRxTimer1, preWait_postRxTimer2, preWait_postTxTimer1, phy_mode)
1076        //
1077        wlan_mac_tx_ctrl_B_params(TX_PKT_BUF_ACK_CTS, tx_ant_mask, 1, 1, 0, 0, PHY_MODE_NONHT);
1078
1079        // CTSs are transmitted with a nominal Tx power used for all control packets
1080        ctrl_tx_gain = wlan_platform_tx_power_to_gain_target(wlan_mac_low_get_current_ctrl_tx_pow());
1081        wlan_mac_tx_ctrl_B_gains(ctrl_tx_gain, ctrl_tx_gain, ctrl_tx_gain, ctrl_tx_gain);
1082
1083        //cts_duration = sat_sub(rx_header->duration_id, (gl_mac_timing_values.t_sifs) +
1084        //          wlan_ofdm_calc_txtime(sizeof(mac_header_80211_CTS) + WLAN_PHY_FCS_NBYTES, tx_mcs, PHY_MODE_NONHT, wlan_mac_low_get_phy_samp_rate()));
1085
1086        switch(wlan_mac_low_get_phy_samp_rate()){
1087            case PHY_10M:
1088                cts_duration = sat_sub(rx_header->duration_id, (gl_mac_timing_values.t_sifs) + cts_duration_lookup[0][tx_mcs]);
1089            break;
1090            default:
1091            case PHY_20M:
1092                cts_duration = sat_sub(rx_header->duration_id, (gl_mac_timing_values.t_sifs) + cts_duration_lookup[1][tx_mcs]);
1093            break;
1094            case PHY_40M:
1095                cts_duration = sat_sub(rx_header->duration_id, (gl_mac_timing_values.t_sifs) + cts_duration_lookup[2][tx_mcs]);
1096            break;
1097        }
1098
1099        // Construct the ACK frame in the dedicated Tx pkt buf
1100        tx_length = wlan_create_cts_frame((void*)(CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, TX_PKT_BUF_ACK_CTS) + PHY_TX_PKT_BUF_MPDU_OFFSET),
1101                                          rx_header->address_2,
1102                                          cts_duration);
1103
1104        // Write the SIGNAL field for the CTS
1105        write_phy_preamble(TX_PKT_BUF_ACK_CTS, PHY_MODE_NONHT, tx_mcs, tx_length);
1106
1107        rx_finish_state = RX_FINISH_SEND_B;
1108
1109
1110
1111        rx_frame_info->resp_low_tx_details.tx_details_type     = TX_DETAILS_CTS;
1112        rx_frame_info->resp_low_tx_details.phy_params_ctrl.mcs = tx_mcs;
1113
1114        // We let "duration" be equal to the duration field of an CTS. This value is provided explicitly to CPU_HIGH
1115        // in the low_tx_details struct such that CPU_HIGH has can reconstruct the RTS in its log. This isn't critical
1116        // to the operation of the DCF, but is critical for the logging framework.
1117        rx_frame_info->resp_low_tx_details.duration = cts_duration;
1118
1119        // This element remains unused during MPDU-only transmissions
1120        rx_frame_info->resp_low_tx_details.phy_params_ctrl.phy_mode     = PHY_MODE_NONHT;
1121        rx_frame_info->resp_low_tx_details.phy_params_ctrl.power        = wlan_mac_low_get_current_ctrl_tx_pow();
1122
1123        switch(tx_ant_mask) {
1124            case 0x1:  ack_tx_ant = TX_ANTMODE_SISO_ANTA; break;
1125            case 0x2:  ack_tx_ant = TX_ANTMODE_SISO_ANTB; break;
1126            case 0x4:  ack_tx_ant = TX_ANTMODE_SISO_ANTC; break;
1127            case 0x8:  ack_tx_ant = TX_ANTMODE_SISO_ANTD; break;
1128            default:   ack_tx_ant = TX_ANTMODE_SISO_ANTA; break;   // Default to RF_A
1129        }
1130
1131        rx_frame_info->resp_low_tx_details.phy_params_ctrl.antenna_mode = ack_tx_ant;
1132    }
1133
1134    // Based on the RX length threshold, determine processing order
1135    if((phy_details->length) <= RX_LEN_THRESH) {
1136        if(wlan_mac_hw_rx_finish() == 1){
1137            //FCS was good
1138            rx_frame_info->flags |= RX_FRAME_INFO_FLAGS_FCS_GOOD;
1139        } else {
1140            //FCS was bad
1141            rx_frame_info->flags &= ~RX_FRAME_INFO_FLAGS_FCS_GOOD;
1142        }
1143
1144        if(rx_frame_info->flags & RX_FRAME_INFO_FLAGS_FCS_GOOD){
1145            switch(rx_finish_state) {
1146                case RX_FINISH_SEND_A:
1147                    wlan_mac_tx_ctrl_A_start(1);
1148                    wlan_mac_tx_ctrl_A_start(0);
1149                    tx_pending_state = TX_PENDING_A;
1150                break;
1151
1152                case RX_FINISH_SEND_B:
1153                    wlan_mac_tx_ctrl_B_start(1);
1154                    wlan_mac_tx_ctrl_B_start(0);
1155                    tx_pending_state = TX_PENDING_B;
1156
1157                break;
1158
1159                default:
1160                case RX_FINISH_SEND_NONE:
1161                    // Do nothing
1162                break;
1163            }
1164        }
1165        rx_finish_state = RX_FINISH_SEND_NONE;
1166    }
1167
1168    // Check if this reception is an ACK
1169    //TODO: we could add a unicast to me check here. It should be redundant. Then again, the POLL_MAC_TYPE_CTS does have the unicast requirement
1170    if((rx_header->frame_control_1) == MAC_FRAME_CTRL1_SUBTYPE_ACK){
1171        return_value |= FRAME_RX_RET_TYPE_ACK;
1172    }
1173
1174    // Update metadata about this reception
1175    rx_frame_info->phy_details = *phy_details;
1176
1177    // This reception was a re-transmission by the other node
1178    if ((rx_header->frame_control_2) & MAC_FRAME_CTRL2_FLAG_RETRY) {
1179        rx_frame_info->flags |= RX_FRAME_INFO_FLAGS_RETRY;
1180    }
1181
1182    // Block until the reception is complete, storing the checksum status in the frame_info struct
1183    if ((phy_details->length) > RX_LEN_THRESH) {
1184        if(wlan_mac_hw_rx_finish() == 1){
1185            //FCS was good
1186            rx_frame_info->flags |= RX_FRAME_INFO_FLAGS_FCS_GOOD;
1187        } else {
1188            //FCS was bad
1189            rx_frame_info->flags &= ~RX_FRAME_INFO_FLAGS_FCS_GOOD;
1190        }
1191    }
1192
1193    // Received packet had good checksum
1194    if(rx_frame_info->flags & RX_FRAME_INFO_FLAGS_FCS_GOOD) {
1195        if(unicast_to_me &&
1196                (gl_waiting_for_response == 0) &&
1197                ( (return_value & FRAME_RX_RET_TYPE_CTS) || (return_value & FRAME_RX_RET_TYPE_ACK) )){
1198            rx_frame_info->flags |= RX_FRAME_INFO_UNEXPECTED_RESPONSE;
1199        } else {
1200            rx_frame_info->flags &= ~RX_FRAME_INFO_UNEXPECTED_RESPONSE;
1201        }
1202
1203
1204        // Increment green LEDs
1205        wlan_platform_low_userio_disp_status(USERIO_DISP_STATUS_GOOD_FCS_EVENT);
1206
1207        return_value |= FRAME_RX_RET_STATUS_GOOD;
1208
1209        // Check if this packet should be passed up to CPU High for further processing
1210        rx_filter = wlan_mac_low_get_current_rx_filter();
1211
1212        switch (rx_filter & RX_FILTER_HDR_MASK) {
1213            default:
1214            case RX_FILTER_HDR_ADDR_MATCH_MPDU:
1215                // Non-control packet either addressed to me or addressed to multicast address
1216                report_to_mac_high = (unicast_to_me || to_multicast) && !WLAN_IS_CTRL_FRAME(rx_header);
1217            break;
1218            case RX_FILTER_HDR_ALL_MPDU:
1219                // Any non-control packet
1220                report_to_mac_high = !WLAN_IS_CTRL_FRAME(rx_header);
1221            break;
1222            case RX_FILTER_HDR_ALL:
1223                // All packets (data, management and control; no type or address filtering)
1224                report_to_mac_high = 1;
1225            break;
1226        }
1227
1228        // Sanity check packet length - if the header says non-control but the length is shorter than a full MAC header
1229        // it must be invalid; this should never happen, but better to catch rare events here than corrupt state in CPU High
1230        if (!WLAN_IS_CTRL_FRAME(rx_header) && (phy_details->length < sizeof(mac_header_80211))) {
1231            report_to_mac_high = 0;
1232        }
1233
1234        if(unicast_to_me) {
1235            return_value |= FRAME_RX_RET_ADDR_MATCH;
1236        }
1237
1238        if ((phy_details->length) > RX_LEN_THRESH) {
1239            switch (rx_finish_state) {
1240                case RX_FINISH_SEND_A:
1241                    wlan_mac_tx_ctrl_A_start(1);
1242                    wlan_mac_tx_ctrl_A_start(0);
1243                    tx_pending_state = TX_PENDING_A;
1244                break;
1245
1246                case RX_FINISH_SEND_B:
1247                    wlan_mac_tx_ctrl_B_start(1);
1248                    wlan_mac_tx_ctrl_B_start(0);
1249                    tx_pending_state = TX_PENDING_B;
1250
1251                break;
1252
1253                default:
1254                case RX_FINISH_SEND_NONE:
1255                break;
1256            }
1257        }
1258
1259
1260        // Check to see if this was a beacon and update the MAC time if appropriate
1261        if(rx_header->frame_control_1 == MAC_FRAME_CTRL1_SUBTYPE_BEACON) {
1262           
1263            // If this packet was from our BSS
1264            if(wlan_addr_eq(gl_beacon_txrx_config.bssid_match, rx_header->address_3)){
1265
1266                if(gl_beacon_txrx_config.beacon_tx_mode == IBSS_BEACON_TX){
1267                    // Reset all state in the DCF core - this cancels deferrals and pending transmissions
1268                    wlan_mac_reset_tx_ctrl_C(1);
1269                    wlan_mac_reset_tx_ctrl_C(0);
1270                    return_value |= FRAME_RX_RET_CANCEL_TX;
1271                }
1272
1273                // Move the packet pointer to after the header
1274                mac_payload_ptr_u8 += sizeof(mac_header_80211);
1275
1276                // Calculate the difference between the beacon timestamp and the packet timestamp
1277
1278                // Extract the timestamp from the beacon payload -- this refers to the MAC time of the transmitter at the start
1279                // of the symbol containing the beacon timestamp from the perspective of the transmitter's antenna port.
1280                u64 beacon_timestamp = (s64)(((beacon_probe_frame*)mac_payload_ptr_u8)->timestamp);
1281
1282                // Calculate the timestamp of the very first sample of the reception at the receiver's antenna port.
1283                #define RX_START_LATENCY_1US 23
1284                u64 t_first_pkt_samp = rx_frame_info->timestamp - RX_START_LATENCY_1US - gl_rx_analog_latency_1us;
1285
1286                // Calculate the timestamp of the first symbol containing the beacon timestamp
1287                u64 t_first_timestamp_samp = t_first_pkt_samp + T_TIMESTAMP_FIELD_OFFSET;
1288
1289                // Compare against the timestamp within the beacon and calculate a correction factor for this node's MAC time
1290                // FIXME: this should be made safer against s64 overflows
1291                time_delta = beacon_timestamp - t_first_timestamp_samp;
1292
1293                // Update the MAC time
1294                switch(gl_beacon_txrx_config.ts_update_mode){
1295                    // TODO: notify the MAC Low Framework of this change so that TBTT can be updated (if necessary)
1296                    case NEVER_UPDATE:
1297                    break;
1298                    case ALWAYS_UPDATE:
1299                        apply_mac_time_delta_usec(time_delta);
1300                        handle_mactime_change(time_delta);                                                             
1301                    break;
1302                    case FUTURE_ONLY_UPDATE:
1303                        if(time_delta > 0){
1304                            apply_mac_time_delta_usec(time_delta);
1305                            handle_mactime_change(time_delta);                                                             
1306                        }
1307                    break;
1308                }
1309            }           
1310        }
1311
1312
1313    // Received checksum was bad
1314    } else {
1315        // Increment red LEDs
1316        wlan_platform_low_userio_disp_status(USERIO_DISP_STATUS_BAD_FCS_EVENT);
1317
1318        // Check if this packet should be passed up to CPU High for further processing
1319        rx_filter = wlan_mac_low_get_current_rx_filter();
1320
1321        switch (rx_filter & RX_FILTER_FCS_MASK) {
1322            default:
1323            case RX_FILTER_FCS_GOOD:
1324                report_to_mac_high = 0;
1325            break;
1326            case RX_FILTER_FCS_ALL:
1327                report_to_mac_high = 1;
1328            break;
1329        }
1330    }
1331
1332    // Wait for MAC CFG A or B to finish starting a response transmission
1333    switch(tx_pending_state){
1334        case TX_PENDING_NONE:
1335            // With the new CPU_LOW beacon structure, it is possible to reach this point in the code
1336            // while MAC Support Core A is currently pending on an unrelated MPDU. We should not wait for this
1337            // pending state to clear if tx_pending_state is TX_PENDING_NONE because it never will. A previous
1338            // version of the code relied on the fact that it was impossible for MAC Support Core A to be pending
1339            // At this point
1340        break;
1341
1342        case TX_PENDING_A:
1343
1344            do{
1345                mac_tx_ctrl_status = wlan_mac_get_tx_ctrl_status();
1346
1347                if(((mac_tx_ctrl_status & WLAN_MAC_TXCTRL_STATUS_MASK_TX_A_STATE) == WLAN_MAC_TXCTRL_STATUS_TX_A_STATE_PRE_TX_WAIT) &&
1348                   ((mac_tx_ctrl_status & WLAN_MAC_TXCTRL_STATUS_MASK_POSTRX_TIMER1_RUNNING) == 0)) {
1349                    // This is potentially a bad state. It likely means we were late in processing this reception
1350                    //
1351                    // There is a slight race condition in detecting this state. There is a small 1 or 2 cycle window where this
1352                    // check can inaccurately deem a failed response transmission. As such, we'll require the condition to be met
1353                    // multiple times.
1354                    //
1355                    num_resp_failures++;
1356
1357                    if(num_resp_failures > 2){
1358                        wlan_mac_reset_tx_ctrl_A(1);
1359                        wlan_mac_reset_tx_ctrl_A(0);
1360
1361                        break;
1362                    }
1363                } else if( (mac_tx_ctrl_status & WLAN_MAC_TXCTRL_STATUS_MASK_TX_A_STATE) == WLAN_MAC_TXCTRL_STATUS_TX_A_STATE_DO_TX ){
1364                    // If the PHY is actively running, we can safely quit this context and get back to frame_transmit to get
1365                    // ready for an ACK reception.
1366                    break;
1367                }
1368            } while(mac_tx_ctrl_status & WLAN_MAC_TXCTRL_STATUS_MASK_TX_A_PENDING);
1369
1370        break;
1371
1372        case TX_PENDING_B:
1373            do{
1374                mac_tx_ctrl_status = wlan_mac_get_tx_ctrl_status();
1375
1376                if( mac_tx_ctrl_status & WLAN_MAC_TXCTRL_STATUS_MASK_TX_B_DONE ) {
1377
1378                    if ((mac_tx_ctrl_status & WLAN_MAC_TXCTRL_STATUS_MASK_TX_B_RESULT) == WLAN_MAC_TXCTRL_STATUS_TX_B_RESULT_NO_TX) {
1379                        // The MAC Support Core B has the capability of successfully not transmitting. This is not relevant
1380                        // for ACK transmissions, but it is relevant for CTS transmissions. A CTS will only be sent if the
1381                        // NAV is clear at the time of transmission. This code block handles the case the the support core
1382                        // elected not to transmit the frame.
1383                        //
1384                        rx_frame_info->flags = rx_frame_info->flags & ~RX_FRAME_INFO_FLAGS_CTRL_RESP_TX;
1385                        break;
1386                    }
1387                    if ((mac_tx_ctrl_status & WLAN_MAC_TXCTRL_STATUS_MASK_TX_B_RESULT) == WLAN_MAC_TXCTRL_STATUS_TX_B_RESULT_DID_TX) {
1388                        rx_frame_info->flags |= RX_FRAME_INFO_FLAGS_CTRL_RESP_TX;
1389                        break;
1390                    }
1391                } else if(((mac_tx_ctrl_status & WLAN_MAC_TXCTRL_STATUS_MASK_TX_B_STATE) == WLAN_MAC_TXCTRL_STATUS_TX_B_STATE_PRE_TX_WAIT) &&
1392                          ((mac_tx_ctrl_status & WLAN_MAC_TXCTRL_STATUS_MASK_POSTRX_TIMER1_RUNNING) == 0)){
1393
1394                    // This is potentially a bad state. It likely means we were late in processing this reception
1395                    //
1396                    // There is a slight race condition in detecting this state. There is a small 1 or 2 cycle window where this
1397                    // check can inaccurately deem a failed response transmission. As such, we'll require the condition to be met
1398                    // multiple times.
1399                    //
1400                    num_resp_failures++;
1401
1402                    if(num_resp_failures > 2){
1403                        rx_frame_info->flags = rx_frame_info->flags & ~RX_FRAME_INFO_FLAGS_CTRL_RESP_TX;
1404
1405                        wlan_mac_reset_tx_ctrl_B(1);
1406                        wlan_mac_reset_tx_ctrl_B(0);
1407                        break;
1408                    }
1409                }
1410            } while(mac_tx_ctrl_status & WLAN_MAC_TXCTRL_STATUS_MASK_TX_B_PENDING);
1411        break;
1412    }
1413
1414    if(rx_frame_info->flags & RX_FRAME_INFO_FLAGS_CTRL_RESP_TX) {
1415        rx_frame_info->resp_low_tx_details.tx_start_timestamp_ctrl      = wlan_mac_low_get_tx_start_timestamp();
1416        rx_frame_info->resp_low_tx_details.tx_start_timestamp_frac_ctrl = wlan_mac_low_get_tx_start_timestamp_frac();
1417    }
1418
1419    // This packet should be passed up to CPU_high for further processing
1420    if (report_to_mac_high) {
1421        // Unlock the pkt buf mutex before passing the packet up
1422        //     If this fails, something has gone horribly wrong
1423
1424        rx_frame_info->rx_pkt_buf_state = RX_PKT_BUF_READY;
1425
1426        // Note: at this point in the code, the packet buffer state has been modified to RX_PKT_BUF_READY,
1427        // yet we have not sent the IPC_MBOX_RX_PKT_BUF_READY message. If we happen to reboot here,
1428        // this packet buffer will be abandoned and won't be cleaned up in the boot process. This is a narrow
1429        // race in practice, but step-by-step debugging can accentuate the risk since there can be an arbitrary
1430        // amount of time spent in this window.
1431
1432        if (unlock_rx_pkt_buf(rx_pkt_buf) != PKT_BUF_MUTEX_SUCCESS) {
1433            xil_printf("Error: unable to unlock RX pkt_buf %d\n", rx_pkt_buf);
1434            wlan_mac_low_send_exception(WLAN_ERROR_CODE_CPU_LOW_RX_MUTEX);
1435        } else {
1436            wlan_mac_low_frame_ipc_send();
1437
1438            // Find a free packet buffer and begin receiving packets there (blocks until free buf is found)
1439            wlan_mac_low_lock_empty_rx_pkt_buf();
1440        }
1441    }
1442
1443    wlan_mac_hw_clear_rx_started();
1444    return return_value;
1445}
1446
1447
1448/*****************************************************************************/
1449/**
1450 * @brief Handle a ready message for a Tx packet buffer
1451 *
1452 * When a ready message for a Tx packet buffer is sent from CPU_HIGH, this function
1453 * saves the packet buffer index into one of two global dl_list structs
1454 * (gl_tx_pkt_buf_ready_list_general or gl_tx_pkt_buf_ready_list_dtim_mcast) based
1455 * upon the pkt_buf_group_t in the tx_frame_info_t for that packet buffer.
1456 *
1457 * @param   u8      pkt_buf     - packet buffer index
1458 * @return  int                 - WLAN_SUCCESS or WLAN_FAILURE
1459 */
1460int handle_tx_pkt_buf_ready(u8 pkt_buf){
1461    int return_value = WLAN_SUCCESS;
1462    dl_list* list = NULL;
1463    tx_frame_info_t* tx_frame_info = (tx_frame_info_t*) (CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, pkt_buf));
1464
1465    if(gl_tx_pkt_buf_ready_list_free.length > 0){
1466        dl_entry* entry = gl_tx_pkt_buf_ready_list_free.first;
1467        dl_entry_remove(&gl_tx_pkt_buf_ready_list_free, entry);
1468
1469        *((u8*)(entry->data)) = pkt_buf;
1470
1471        if( (gl_dtim_mcast_buffer_enable == 1) && (gl_beacon_txrx_config.beacon_tx_mode != NO_BEACON_TX) ){
1472            switch(tx_frame_info->queue_info.pkt_buf_group){
1473                case PKT_BUF_GROUP_DTIM_MCAST:
1474                    list = &gl_tx_pkt_buf_ready_list_dtim_mcast;
1475                break;
1476                default:
1477                    xil_printf("handle_tx_pkt_buf_ready: unsupported pkt_buf_group_t");
1478                case PKT_BUF_GROUP_GENERAL:
1479                    list = &gl_tx_pkt_buf_ready_list_general;
1480                break;
1481            }
1482        } else {
1483            list = &gl_tx_pkt_buf_ready_list_general;
1484        }
1485
1486        dl_entry_insertEnd(list, entry);
1487
1488    } else {
1489        return_value = WLAN_FAILURE;
1490    }
1491
1492    return return_value;
1493}
1494
1495/*****************************************************************************/
1496/**
1497 * @brief Poll the packet buffer lists and send
1498 *
1499 * This function attempts to transmit from the head of a specified
1500 * packet buffer group list.
1501 *
1502 * In the case that the packet buffer group argument is PKT_BUF_GROUP_DTIM_MCAST,
1503 * this function is also responsible for setting the MAC_FRAME_CTRL2_FLAG_MORE_DATA
1504 * bit in the frame control 2 byte of the outgoing MAC header. It uses the
1505 * gl_tx_pkt_buf_ready_list_dtim_mcast length to make this determination.
1506 *
1507 * Finally, also in the case of PKT_BUF_GROUP_DTIM_MCAST, this function will recognize
1508 * when frame_transmit_dtim_mcast() terminates without sending the frame (i.e. in
1509 * the event that a TBTT boundary is crossed before the transmission can begin). In this
1510 * case, it knows to not remove the packet from the gl_tx_pkt_buf_ready_list_dtim_mcast
1511 * list and to resume that packet's transmission on the next call to
1512 * poll_tx_pkt_buf_list(PKT_BUF_GROUP_DTIM_MCAST).
1513 *
1514 * @param   pkt_buf_group_t     pkt_buf_group   - PKT_BUF_GROUP_GENERAL or PKT_BUF_GROUP_DTIM_MCAST
1515 * @return  int                                 - 0 for success, -1 for failure
1516 */
1517u32 poll_tx_pkt_buf_list(pkt_buf_group_t pkt_buf_group){
1518    u8 pkt_buf;
1519    dl_entry* entry;
1520    u32 return_value = 0;
1521    static u8 dtim_mcast_paused = 0;
1522
1523    switch(pkt_buf_group){
1524        case PKT_BUF_GROUP_GENERAL:
1525            if(gl_tx_pkt_buf_ready_list_general.length > 0){
1526                entry = gl_tx_pkt_buf_ready_list_general.first;
1527                pkt_buf = *((u8*)(entry->data));
1528
1529                if( wlan_mac_low_prepare_frame_transmit(pkt_buf) == 0 ){
1530                    frame_transmit_general(pkt_buf);
1531
1532                    return_value |= POLL_TX_PKT_BUF_LIST_RETURN_TRANSMITTED;
1533                    wlan_mac_low_finish_frame_transmit(pkt_buf);
1534                } else {
1535                    xil_printf("Error in wlan_mac_low_prepare_frame_transmit(%d)\n", pkt_buf);
1536                }
1537
1538                dl_entry_remove(&gl_tx_pkt_buf_ready_list_general, entry);
1539                dl_entry_insertEnd(&gl_tx_pkt_buf_ready_list_free, entry);
1540            }
1541        break;
1542        case PKT_BUF_GROUP_DTIM_MCAST:
1543            if(gl_tx_pkt_buf_ready_list_dtim_mcast.length > 0){
1544                entry = gl_tx_pkt_buf_ready_list_dtim_mcast.first;
1545                pkt_buf = *((u8*)(entry->data));
1546
1547                // In the special case of sending a DTIM MCAST packet, the DCF is responsible for maintaining the
1548                // MAC_FRAME_CTRL2_FLAG_MORE_DATA bit in the header.
1549                mac_header_80211* header  = (mac_header_80211*)(CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, pkt_buf) + PHY_TX_PKT_BUF_MPDU_OFFSET);
1550
1551                if( gl_tx_pkt_buf_ready_list_dtim_mcast.length == 1 ){
1552                    // If there is a second mcast frame in the READY state, we can safely raise
1553                    // the MAC_FRAME_CTRL2_FLAG_MORE_DATA bit. Otherwise, we will be forced to
1554                    // wait until the next DTIM even if another frame enters the READY state while
1555                    // the current frame is underway.
1556                    header->frame_control_2 &= ~MAC_FRAME_CTRL2_FLAG_MORE_DATA;
1557                } else {
1558                    header->frame_control_2 |= MAC_FRAME_CTRL2_FLAG_MORE_DATA;
1559                    return_value |= POLL_TX_PKT_BUF_LIST_RETURN_MORE_DATA;
1560                }
1561
1562                if(dtim_mcast_paused == 0){
1563                    if( wlan_mac_low_prepare_frame_transmit(pkt_buf) != 0 ){
1564                        xil_printf("Error in wlan_mac_low_prepare_frame_transmit(%d) -- PKT_BUF_GROUP_DTIM_MCAST case\n", pkt_buf);
1565                    }
1566                }
1567
1568                // Note: we have placed an assumption on gl_tx_pkt_buf_ready_list_dtim_mcast here that,
1569                // if a DTIM MCAST transmission has been paused, then packet buffer that has been paused
1570                // is gl_tx_pkt_buf_ready_list_dtim_mcast.first. In other words, gl_tx_pkt_buf_ready_list_dtim_mcast.first
1571                // may not be modified by any other context.
1572                if( frame_transmit_dtim_mcast(pkt_buf, dtim_mcast_paused)&DTIM_MCAST_RETURN_PAUSED ){
1573                    dtim_mcast_paused = 1;
1574                    return_value |= POLL_TX_PKT_BUF_LIST_RETURN_PAUSED;
1575                } else {
1576                    dtim_mcast_paused = 0;
1577
1578
1579                    wlan_mac_low_finish_frame_transmit(pkt_buf);
1580
1581                    return_value |= POLL_TX_PKT_BUF_LIST_RETURN_TRANSMITTED;
1582                    dl_entry_remove(&gl_tx_pkt_buf_ready_list_dtim_mcast, entry);
1583                    dl_entry_insertEnd(&gl_tx_pkt_buf_ready_list_free, entry);
1584
1585                    //We just removed a packet from the to-be-transmitted list.
1586                    //Now is a good time to see if another one is available in
1587                    //the mailbox to refill it.
1588                    wlan_mac_low_poll_ipc_rx();
1589                }
1590            }
1591        break;
1592        case PKT_BUF_GROUP_OTHER:
1593            xil_printf("Error in poll_tx_pkt_buf_list: unsupported argument\n");
1594            return_value |= POLL_TX_PKT_BUF_LIST_RETURN_ERROR;
1595        break;
1596    }
1597
1598    return return_value;
1599}
1600
1601
1602/*****************************************************************************/
1603/**
1604 * @brief Handles transmission of a DTIM multicast packet
1605 *
1606 * This function is called to transmit a multicast packet through Tx Controller D.
1607 * Prior to the PHY starting the waveform, this function must continually poll the
1608 * TU target register to determine if a TBTT boundary has been crossed. If so, it
1609 * must attempt to pause the Tx Controller D and return to the calling context.
1610 *
1611 * Additionally, this function is responsible for polling for IPC receptions
1612 * continually while waiting for the transmission to begin and while the
1613 * transmission is ongoing.
1614 *
1615 * @param   u8      pkt_buf     - Index of the Tx packet buffer containing the packet to transmit
1616 * @param   u8      resume      - 0 to indicate that this is a new MPDU that must be submitted
1617 *                                1 to indicate that this packet should resume a packet already submitted
1618 * @return  u32                 - Bit flags indicating various status messages
1619 */
1620u32 frame_transmit_dtim_mcast(u8 pkt_buf, u8 resume) {
1621    u32 return_value = 0;
1622
1623    //We will make a few variables static. This will make it so that they retain their
1624    //values on the next call to frame_transmit_dtim_mcast in the event that resume == 1
1625    static wlan_mac_low_tx_details_t  __attribute__ ((aligned (4))) low_tx_details;
1626    static tx_mode_t tx_mode;
1627    static u8 tx_has_started;
1628
1629    u32 mac_hw_status;
1630    u32 mac_tx_ctrl_status;
1631
1632    tx_frame_info_t* tx_frame_info = (tx_frame_info_t*) (CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, pkt_buf));
1633
1634    if( resume == 0 ){
1635        int curr_tx_pow;
1636        u16 n_slots = 0;
1637        u16 n_slots_readback = 0;
1638        u8 mpdu_tx_ant_mask = 0;
1639
1640        // Extract waveform params from the tx_frame_info
1641        u8 mcs = tx_frame_info->params.phy.mcs;
1642        u8 phy_mode = (tx_frame_info->params.phy.phy_mode & (PHY_MODE_HTMF | PHY_MODE_NONHT));
1643        u16 length = tx_frame_info->length;
1644
1645        tx_frame_info->num_tx_attempts = 0;
1646        tx_frame_info->phy_samp_rate = (u8)wlan_mac_low_get_phy_samp_rate();
1647
1648        // Compare the length of this frame to the RTS Threshold
1649        // TODO: needs further investigation
1650        if(length <= gl_dot11RTSThreshold) {
1651            tx_mode = TX_MODE_SHORT;
1652        } else {
1653            tx_mode = TX_MODE_LONG;
1654        }
1655
1656        tx_has_started = 0;
1657        (tx_frame_info->num_tx_attempts)++;
1658
1659        // Write the SIGNAL field (interpreted by the PHY during Tx waveform generation)
1660        // This is the SIGNAL field for the MPDU we will eventually transmit. It's possible
1661        // the next waveform we send will be an RTS with its own independent SIGNAL
1662
1663        write_phy_preamble(pkt_buf, phy_mode, mcs, length);
1664
1665        // Configure the Tx antenna selection
1666        mpdu_tx_ant_mask    = 0;
1667
1668        switch(tx_frame_info->params.phy.antenna_mode) {
1669            case TX_ANTMODE_SISO_ANTA:  mpdu_tx_ant_mask |= 0x1;  break;
1670            case TX_ANTMODE_SISO_ANTB:  mpdu_tx_ant_mask |= 0x2;  break;
1671            case TX_ANTMODE_SISO_ANTC:  mpdu_tx_ant_mask |= 0x4;  break;
1672            case TX_ANTMODE_SISO_ANTD:  mpdu_tx_ant_mask |= 0x8;  break;
1673            default:                    mpdu_tx_ant_mask  = 0x1;  break;       // Default to RF_A
1674        }
1675
1676        // Configure the Tx power - update all antennas, even though only one will be used
1677        curr_tx_pow = wlan_platform_tx_power_to_gain_target(tx_frame_info->params.phy.power);
1678        wlan_mac_tx_ctrl_D_gains(curr_tx_pow, curr_tx_pow, curr_tx_pow, curr_tx_pow);
1679
1680        // We speculatively draw a backoff in case the backoff counter is currently 0 but
1681        //  the medium is busy.
1682        n_slots = rand_num_slots(RAND_SLOT_REASON_STANDARD_ACCESS);
1683
1684        // Configure the Tx state machine for this transmission
1685        // wlan_mac_tx_ctrl_D_params(pktBuf, antMask, req_backoff, phy_mode, num_slots)
1686        wlan_mac_tx_ctrl_D_params(pkt_buf, mpdu_tx_ant_mask, 0, phy_mode, n_slots);
1687
1688        // Wait for the Tx PHY to be idle
1689        // Actually waiting here is rare, but handles corner cases like a background ACK transmission at a low rate
1690        // overlapping the attempt to start a new packet transmission
1691        do{
1692            mac_hw_status = wlan_mac_get_status();
1693        } while(mac_hw_status & WLAN_MAC_STATUS_MASK_TX_PHY_ACTIVE);
1694
1695        // Submit the MPDU for transmission - this starts the MAC hardware's MPDU Tx state machine
1696        wlan_mac_tx_ctrl_D_start(1);
1697        wlan_mac_tx_ctrl_D_start(0);
1698
1699        // Immediately re-read the current slot count.
1700        n_slots_readback = wlan_mac_get_backoff_count_D();
1701
1702        if( (n_slots != n_slots_readback) ){
1703            // For the first transmission (non-retry) of an MPDU, the number of
1704            // slots used by the backoff process is ambiguous. The n_slots we provided
1705            // to wlan_mac_tx_ctrl_A_params is only a suggestion. If the medium has been
1706            // idle for a DIFS, then there will not be a backoff. Or, if another backoff is
1707            // currently running, the MAC Config Core A will inherit that backoff. By
1708            // immediately reading back the slot count after starting the core, we can
1709            // overwrite the number of slots that we will fill into low_tx_details with
1710            // the correct value
1711            n_slots = n_slots_readback;
1712        }
1713
1714
1715        low_tx_details.flags                        = 0;
1716        low_tx_details.phy_params_mpdu.mcs          = tx_frame_info->params.phy.mcs;
1717        low_tx_details.phy_params_mpdu.phy_mode     = tx_frame_info->params.phy.phy_mode;
1718        low_tx_details.phy_params_mpdu.power        = tx_frame_info->params.phy.power;
1719        low_tx_details.phy_params_mpdu.antenna_mode = tx_frame_info->params.phy.antenna_mode;
1720
1721        // If RTS/CTS isn't used, these fields should just be ignored
1722        low_tx_details.phy_params_ctrl.power        = tx_frame_info->params.phy.power;
1723        low_tx_details.phy_params_ctrl.antenna_mode = tx_frame_info->params.phy.antenna_mode;
1724
1725        low_tx_details.chan_num = wlan_mac_low_get_active_channel();
1726        low_tx_details.cw       = (1 << gl_cw_exp)-1; //(2^(gl_cw_exp) - 1)
1727        low_tx_details.ssrc     = gl_stationShortRetryCount;
1728        low_tx_details.slrc     = gl_stationLongRetryCount;
1729        low_tx_details.src      = 0;
1730        low_tx_details.lrc      = 0;
1731
1732        // NOTE: the pre-Tx backoff may not occur for the initial transmission attempt. If the medium has been idle for >DIFS when
1733        // the first Tx occurs the DCF state machine will not start a backoff. The upper-level MAC should compare the num_slots value
1734        // to the time delta between the accept and start times of the first transmission to determine whether the pre-Tx backoff
1735        // actually occurred.
1736        low_tx_details.num_slots = n_slots;
1737        low_tx_details.attempt_number = tx_frame_info->num_tx_attempts;
1738
1739    } else {
1740        // There is currently a transmission that whose state is "paused." We should
1741        // resume it without resubmitting it to the core.
1742
1743        wlan_mac_pause_tx_ctrl_D(0);
1744    } //if( resume == 0 )
1745
1746
1747    // Wait for the MPDU Tx to finish
1748    do { // while(tx_status & WLAN_MAC_STATUS_MASK_TX_D_PENDING)
1749
1750        // Poll the DCF core status register
1751        mac_hw_status = wlan_mac_get_status();
1752
1753        // Fill in the timestamp if indicated by the flags, only possible after Tx PHY has started
1754        if ( (mac_hw_status & WLAN_MAC_STATUS_MASK_TX_PHY_ACTIVE) && (tx_has_started == 0)) {
1755            tx_has_started = 1;
1756            low_tx_details.tx_details_type  = TX_DETAILS_MPDU;
1757            low_tx_details.tx_start_timestamp_mpdu = wlan_mac_low_get_tx_start_timestamp();
1758            low_tx_details.tx_start_timestamp_frac_mpdu = wlan_mac_low_get_tx_start_timestamp_frac();
1759
1760        }
1761
1762        // Transmission is complete
1763        if( mac_hw_status & WLAN_MAC_STATUS_MASK_TX_D_DONE ) {
1764            tx_mode = TX_MODE_SHORT;
1765
1766            switch(tx_mode) {
1767                case TX_MODE_SHORT:
1768                    reset_ssrc();
1769                    reset_cw();
1770                break;
1771                case TX_MODE_LONG:
1772                    reset_slrc();
1773                    reset_cw();
1774                break;
1775            }
1776
1777            // Start a post-Tx backoff using the updated contention window
1778            // TODO: Debate merit of software-initiated backoffs in D
1779
1780            //n_slots = rand_num_slots(RAND_SLOT_REASON_STANDARD_ACCESS);
1781            //wlan_mac_dcf_hw_start_backoff(n_slots);
1782
1783            // Send IPC message containing the details about this low-level transmission
1784            wlan_mac_low_send_low_tx_details(pkt_buf, &low_tx_details);
1785            tx_frame_info->tx_result = TX_FRAME_INFO_RESULT_SUCCESS;
1786            return return_value;
1787        } else {
1788            //  This is the same MAC status check performed in the framework wlan_mac_low_poll_frame_rx()
1789            //  It is critical to check the Rx status here using the same status register read that was
1790            //  used in the Tx state checking above. Skipping this and calling wlan_mac_low_poll_frame_rx()
1791            //  directly leads to a race between the Tx status checking above and Rx status checking
1792            if (mac_hw_status & WLAN_MAC_STATUS_MASK_RX_PHY_STARTED) {
1793                wlan_mac_low_poll_frame_rx();
1794            } else {
1795                if (wlan_mac_check_tu_latch() && (tx_has_started == 0)){
1796                    wlan_mac_pause_tx_ctrl_D(1);
1797                    mac_tx_ctrl_status = wlan_mac_get_tx_ctrl_status();
1798                    // Check if Tx controller D is deferring (now with a paused backoff) or idle (no Tx pending)
1799                    // if we lost the race to pause the controller, we will continue on as if we did not observe the TU latch
1800                    if(((mac_tx_ctrl_status & WLAN_MAC_TXCTRL_STATUS_MASK_TX_D_STATE) == WLAN_MAC_TXCTRL_STATUS_TX_D_STATE_DEFER) ||
1801                       ((mac_tx_ctrl_status & WLAN_MAC_TXCTRL_STATUS_MASK_TX_D_STATE) == WLAN_MAC_TXCTRL_STATUS_TX_D_STATE_IDLE)) {
1802                        return_value |= DTIM_MCAST_RETURN_PAUSED;
1803                        return return_value;
1804                    } else {
1805                        wlan_mac_pause_tx_ctrl_D(0);
1806                    }
1807                } else {
1808                    // Poll IPC rx
1809                    // TODO: Need to handle implications of an IPC message changing something like channel
1810                    wlan_mac_low_poll_ipc_rx();
1811                }
1812            }
1813        } // END if(Tx D state machine done)
1814    } while( mac_hw_status & WLAN_MAC_STATUS_MASK_TX_D_PENDING );
1815
1816    return return_value;
1817
1818}
1819
1820/*****************************************************************************/
1821/**
1822 * @brief Handles transmission of a general packet
1823 *
1824 * This function is responsible for using Tx Controller A to send a new MPDU and handle
1825 * any retries that the MPDU may require.
1826 *
1827 * @param   pkt_buf     - Index of the Tx packet buffer containing the packet to transmit
1828 * @return  none
1829 */
1830void frame_transmit_general(u8 pkt_buf) {
1831    u8  mac_cfg_mcs;
1832    u16 mac_cfg_length;
1833    u8  mac_cfg_pkt_buf;
1834    u8  mac_cfg_phy_mode;
1835
1836    u16 rts_header_duration;
1837    u16 cts_header_duration;
1838    wlan_mac_low_tx_details_t  __attribute__ ((aligned (4))) low_tx_details;
1839
1840    u8 req_timeout;
1841
1842    u32 rx_status;
1843    u32 mac_hw_status;
1844    u32 mac_tx_ctrl_status;
1845
1846    int curr_tx_pow;
1847
1848    u8  tx_has_started;
1849
1850    tx_wait_state_t             tx_wait_state;
1851    tx_mode_t                   tx_mode;
1852
1853    u16 short_retry_count = 0;
1854    u16 long_retry_count = 0;
1855    u16 n_slots = 0;
1856    u16 n_slots_readback = 0;
1857    u8 mpdu_tx_ant_mask = 0;
1858    tx_frame_info_t* tx_frame_info = (tx_frame_info_t*) (CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, pkt_buf));
1859    mac_header_80211* header = (mac_header_80211*)(CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, pkt_buf) + PHY_TX_PKT_BUF_MPDU_OFFSET);
1860
1861    // Extract waveform params from the tx_frame_info
1862    u8 mcs = tx_frame_info->params.phy.mcs;
1863    u8 phy_mode = (tx_frame_info->params.phy.phy_mode & (PHY_MODE_HTMF | PHY_MODE_NONHT));
1864    u16 length = tx_frame_info->length;
1865
1866    // This state variable will inform the rest of the frame_transmit function
1867    // on whether the code is actively waiting for an ACK, for an RTS, or not
1868    // waiting for anything.
1869    tx_wait_state = TX_WAIT_NONE;
1870
1871    tx_frame_info->num_tx_attempts = 0;
1872    tx_frame_info->phy_samp_rate = (u8)wlan_mac_low_get_phy_samp_rate();
1873
1874    // Compare the length of this frame to the RTS Threshold
1875    if(length <= gl_dot11RTSThreshold) {
1876        tx_mode = TX_MODE_SHORT;
1877    } else {
1878        tx_mode = TX_MODE_LONG;
1879    }
1880
1881    if((tx_frame_info->flags) & TX_FRAME_INFO_FLAGS_FILL_DURATION){
1882        // ACK_N_DBPS is used to calculate duration of the ACK waveform which might be received in response to this transmission
1883        //  The ACK duration is used to calculate the DURATION field in the MAC header
1884        //  The selection of ACK rate for a given DATA rate is specified in IEEE 802.11-2012 9.7.6.5.2
1885        //ack_mcs = wlan_mac_low_mcs_to_ctrl_resp_mcs(tx_frame_info->params.phy.mcs, tx_frame_info->params.phy.phy_mode);
1886        //ack_phy_mode = PHY_MODE_HTMF;
1887
1888        // Compute and fill in the duration of any time-on-air following this packet's transmission
1889        //     For DATA Tx, DURATION = T_SIFS + T_ACK, where T_ACK is function of the ACK Tx rate
1890        //header->duration_id = wlan_ofdm_calc_txtime(sizeof(mac_header_80211_ACK) + WLAN_PHY_FCS_NBYTES, ack_mcs, ack_phy_mode, wlan_mac_low_get_phy_samp_rate()) + gl_mac_timing_values.t_sifs;
1891        header->duration_id = gl_precalc_duration[tx_frame_info->params.phy.phy_mode][tx_frame_info->params.phy.mcs];
1892    }
1893
1894
1895    // Retry loop
1896    while(1) {
1897        tx_has_started = 0;
1898
1899        (tx_frame_info->num_tx_attempts)++;
1900
1901        // Check if the higher-layer MAC requires this transmission have a post-Tx timeout
1902        req_timeout = ((tx_frame_info->flags) & TX_FRAME_INFO_FLAGS_REQ_TO) != 0;
1903
1904        // Write the SIGNAL field (interpreted by the PHY during Tx waveform generation)
1905        // This is the SIGNAL field for the MPDU we will eventually transmit. It's possible
1906        // the next waveform we send will be an RTS with its own independent SIGNAL
1907
1908        //wlan_phy_set_tx_signal(mpdu_pkt_buf, mpdu_rate, mpdu_length);
1909        write_phy_preamble(pkt_buf, phy_mode, mcs, length);
1910
1911        if ((tx_mode == TX_MODE_LONG) && (req_timeout == 1)) {
1912            // This is a long MPDU that requires an RTS/CTS handshake prior to the MPDU transmission.
1913            tx_wait_state   = TX_WAIT_CTS;
1914
1915            // This is a global pkt_buf index that can be seen by the frame_receive() context.
1916            // frame_receive() needs this to figure out what to send in the event that it receives
1917            // a valid CTS.
1918            gl_long_mpdu_pkt_buf = pkt_buf;
1919
1920            mac_cfg_pkt_buf = TX_PKT_BUF_RTS;
1921            mac_cfg_phy_mode = PHY_MODE_NONHT;
1922
1923            // The rate given to us in the argument of frame_transmit applies to the MPDU. Several
1924            // elements depend on this rate:
1925            //
1926            // 1) The rate of the RTS we will send (fixed NONHT phy mode for CTRL response)
1927            // 2) The rate of the CTS we expect to receive (fixed NONHT phy mode for CTRL response)
1928            // 3) The duration of the RTS/CTS/DATA frames a long with the IFS periods between them
1929            //
1930            // The below switch() sets these elements accordingly.
1931            //
1932
1933            mac_cfg_mcs = wlan_mac_low_mcs_to_ctrl_resp_mcs(mcs, phy_mode);
1934            low_tx_details.phy_params_ctrl.mcs = mac_cfg_mcs;
1935
1936            switch(wlan_mac_low_get_phy_samp_rate()){
1937                case PHY_10M:
1938                    cts_header_duration = cts_duration_lookup[0][mac_cfg_mcs];
1939                break;
1940                default:
1941                case PHY_20M:
1942                    cts_header_duration = cts_duration_lookup[1][mac_cfg_mcs];
1943                break;
1944                case PHY_40M:
1945                    cts_header_duration = cts_duration_lookup[2][mac_cfg_mcs];
1946                break;
1947            }
1948
1949            rts_header_duration = (gl_mac_timing_values.t_sifs) + cts_header_duration +
1950                                  (gl_mac_timing_values.t_sifs) + wlan_ofdm_calc_txtime(length, tx_frame_info->params.phy.mcs, tx_frame_info->params.phy.phy_mode, wlan_mac_low_get_phy_samp_rate()) +
1951                                  header->duration_id;
1952
1953            // We let "duration" be equal to the duration field of an RTS. This value is provided explicitly to CPU_HIGH
1954            // in the low_tx_details struct such that CPU_HIGH has can reconstruct the RTS in its log. This isn't critical
1955            // to the operation of the DCF, but is critical for the logging framework.
1956            low_tx_details.duration = rts_header_duration;
1957
1958            // Construct the RTS frame in the dedicated Tx pkt buf for control frames
1959            mac_cfg_length = wlan_create_rts_frame((void*)(CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, TX_PKT_BUF_RTS) + PHY_TX_PKT_BUF_MPDU_OFFSET),
1960                                                   header->address_1,
1961                                                   header->address_2,
1962                                                   rts_header_duration);
1963
1964            // Write SIGNAL for RTS
1965            //wlan_phy_set_tx_signal(mac_cfg_pkt_buf, mac_cfg_rate, mac_cfg_length);
1966            write_phy_preamble(mac_cfg_pkt_buf, mac_cfg_phy_mode, mac_cfg_mcs, mac_cfg_length);
1967
1968            // Configure the Tx power - update all antennas, even though only one will be used
1969            curr_tx_pow = wlan_mac_low_get_current_ctrl_tx_pow();
1970
1971        } else if((tx_mode == TX_MODE_SHORT) && (req_timeout == 1)) {
1972            // Unicast, no RTS
1973            tx_wait_state = TX_WAIT_ACK;
1974            mac_cfg_mcs = mcs;
1975            mac_cfg_length = length;
1976            mac_cfg_pkt_buf = pkt_buf;
1977            mac_cfg_phy_mode = phy_mode;
1978
1979            // Configure the Tx power - update all antennas, even though only one will be used
1980            curr_tx_pow = wlan_platform_tx_power_to_gain_target(tx_frame_info->params.phy.power);
1981
1982        } else {
1983            // Multicast, short or long
1984            tx_wait_state = TX_WAIT_NONE;
1985            mac_cfg_mcs = mcs;
1986            mac_cfg_length = length;
1987            mac_cfg_pkt_buf = pkt_buf;
1988            mac_cfg_phy_mode = phy_mode;
1989
1990            // Configure the Tx power - update all antennas, even though only one will be used
1991            curr_tx_pow = wlan_platform_tx_power_to_gain_target(tx_frame_info->params.phy.power);
1992        }
1993
1994        wlan_mac_tx_ctrl_A_gains(curr_tx_pow, curr_tx_pow, curr_tx_pow, curr_tx_pow);
1995
1996        // Configure the Tx antenna selection
1997        mpdu_tx_ant_mask = 0;
1998
1999        switch(tx_frame_info->params.phy.antenna_mode) {
2000            case TX_ANTMODE_SISO_ANTA:  mpdu_tx_ant_mask |= 0x1;  break;
2001            case TX_ANTMODE_SISO_ANTB:  mpdu_tx_ant_mask |= 0x2;  break;
2002            case TX_ANTMODE_SISO_ANTC:  mpdu_tx_ant_mask |= 0x4;  break;
2003            case TX_ANTMODE_SISO_ANTD:  mpdu_tx_ant_mask |= 0x8;  break;
2004            default:                    mpdu_tx_ant_mask  = 0x1;  break;       // Default to RF_A
2005        }
2006
2007        if ((tx_frame_info->num_tx_attempts) == 1) {
2008            // This is the first transmission, so we speculatively draw a backoff in case
2009            // the backoff counter is currently 0 but the medium is busy. Prior to all other
2010            // (re)transmissions, an explicit backoff will have been started at the end of
2011            // the previous iteration of this loop.
2012            //
2013            n_slots = rand_num_slots(RAND_SLOT_REASON_STANDARD_ACCESS);
2014
2015
2016
2017            // Configure the DCF core Tx state machine for this transmission
2018            // wlan_mac_tx_ctrl_A_params(pktBuf, antMask, preTx_backoff_slots, preWait_postRxTimer1, preWait_postTxTimer1, postWait_postTxTimer2, phy_mode)
2019            wlan_mac_tx_ctrl_A_params(mac_cfg_pkt_buf, mpdu_tx_ant_mask, n_slots, 0, 0, req_timeout, mac_cfg_phy_mode);
2020
2021        } else {
2022            // This is a retry. We will inherit whatever backoff that is currently running.
2023            // Configure the DCF core Tx state machine for this transmission
2024            // preTx_backoff_slots is 0 here, since the core will have started a post-timeout backoff automatically
2025            wlan_mac_tx_ctrl_A_params(mac_cfg_pkt_buf, mpdu_tx_ant_mask, 0, 0, 0, req_timeout, mac_cfg_phy_mode);
2026        }
2027
2028        // Wait for the Tx PHY to be idle
2029        // Actually waiting here is rare, but handles corner cases like a background ACK transmission at a low rate
2030        // overlapping the attempt to start a new packet transmission
2031        do{
2032            mac_hw_status = wlan_mac_get_status();
2033        } while(mac_hw_status & WLAN_MAC_STATUS_MASK_TX_PHY_ACTIVE);
2034
2035        // Submit the MPDU for transmission - this starts the MAC hardware's MPDU Tx state machine
2036        wlan_mac_tx_ctrl_A_start(1);
2037        wlan_mac_tx_ctrl_A_start(0);
2038
2039        // Immediately re-read the current slot count.
2040        n_slots_readback = wlan_mac_get_backoff_count_A();
2041
2042        // While waiting, fill in the metadata about this transmission attempt, to be used by CPU High in creating TX_LOW log entries
2043        // The phy_params (as opposed to phy_params2) element is used for the MPDU itself. If we are waiting for a CTS and we do not
2044        // receive one, CPU_HIGH will know to ignore this element of low_tx_details (since the MPDU will not be transmitted).
2045
2046        if(((tx_frame_info->num_tx_attempts) == 1) && (n_slots != n_slots_readback)){
2047            // For the first transmission (non-retry) of an MPDU, the number of
2048            // slots used by the backoff process is ambiguous. The n_slots we provided
2049            // to wlan_mac_tx_ctrl_A_params is only a suggestion. If the medium has been
2050            // idle for a DIFS, then there will not be a backoff. Or, if another backoff is
2051            // currently running, the MAC Config Core A will inherit that backoff. By
2052            // immediately reading back the slot count after starting the core, we can
2053            // overwrite the number of slots that we will fill into low_tx_details with
2054            // the correct value
2055            n_slots = n_slots_readback;
2056        }
2057
2058
2059        low_tx_details.flags                        = 0;
2060        low_tx_details.phy_params_mpdu.mcs          = tx_frame_info->params.phy.mcs;
2061        low_tx_details.phy_params_mpdu.phy_mode     = tx_frame_info->params.phy.phy_mode;
2062        low_tx_details.phy_params_mpdu.power        = tx_frame_info->params.phy.power;
2063        low_tx_details.phy_params_mpdu.antenna_mode = tx_frame_info->params.phy.antenna_mode;
2064
2065        // If RTS/CTS isn't used, these fields should just be ignored
2066        low_tx_details.phy_params_ctrl.power        = tx_frame_info->params.phy.power;
2067        low_tx_details.phy_params_ctrl.antenna_mode = tx_frame_info->params.phy.antenna_mode;
2068
2069        low_tx_details.chan_num = wlan_mac_low_get_active_channel();
2070        low_tx_details.cw       = (1 << gl_cw_exp)-1; //(2^(gl_cw_exp) - 1)
2071        low_tx_details.ssrc     = gl_stationShortRetryCount;
2072        low_tx_details.slrc     = gl_stationLongRetryCount;
2073        low_tx_details.src      = short_retry_count;
2074        low_tx_details.lrc      = long_retry_count;
2075
2076        // NOTE: the pre-Tx backoff may not occur for the initial transmission attempt. If the medium has been idle for >DIFS when
2077        // the first Tx occurs the DCF state machine will not start a backoff. The upper-level MAC should compare the num_slots value
2078        // to the time delta between the accept and start times of the first transmission to determine whether the pre-Tx backoff
2079        // actually occurred.
2080        low_tx_details.num_slots      = n_slots;
2081        low_tx_details.attempt_number = tx_frame_info->num_tx_attempts;
2082
2083        // Wait for the MPDU Tx to finish
2084        do { // while(tx_status & WLAN_MAC_STATUS_MASK_TX_A_PENDING)
2085
2086            // Poll the DCF core status register
2087            mac_hw_status = wlan_mac_get_status();
2088
2089            // Fill in the timestamp if indicated by the flags, only possible after Tx PHY has started
2090            if ( (mac_hw_status & WLAN_MAC_STATUS_MASK_TX_PHY_ACTIVE) && (tx_has_started == 0)) {
2091
2092                if((tx_frame_info->flags) & TX_FRAME_INFO_FLAGS_FILL_TIMESTAMP){
2093                    //Note: Probe responses still need their timestamp to be filled in, so this clause remains
2094                    //even though no beacons will be sent here
2095                    // Insert the TX START timestamp
2096                    *((u64*)(((u8*)header + 24))) = ((u64)wlan_mac_low_get_tx_start_timestamp())+ T_TIMESTAMP_FIELD_OFFSET + gl_tx_analog_latency_1us;
2097                }
2098
2099                tx_has_started = 1;
2100
2101                if(req_timeout){
2102                    gl_waiting_for_response = 1;
2103                }
2104
2105                if(tx_wait_state == TX_WAIT_CTS) {
2106                    // This will potentially be overwritten with TX_DETAILS_RTS_MPDU should we make it that far.
2107                    low_tx_details.tx_details_type  = TX_DETAILS_RTS_ONLY;
2108                    low_tx_details.tx_start_timestamp_ctrl = wlan_mac_low_get_tx_start_timestamp();
2109                    low_tx_details.tx_start_timestamp_frac_ctrl = wlan_mac_low_get_tx_start_timestamp_frac();
2110
2111                } else if ((tx_mode == TX_MODE_LONG) && (tx_wait_state == TX_WAIT_ACK)) {
2112                    // NOTE: this clause will overwrite the previous TX_DETAILS_RTS_ONLY state in the event a CTS is received.
2113                    low_tx_details.tx_details_type  = TX_DETAILS_RTS_MPDU;
2114                    low_tx_details.tx_start_timestamp_mpdu = wlan_mac_low_get_tx_start_timestamp();
2115                    low_tx_details.tx_start_timestamp_frac_mpdu = wlan_mac_low_get_tx_start_timestamp_frac();
2116
2117                } else {
2118                    // This is a non-RTS/CTS-protected MPDU transmission
2119                    low_tx_details.tx_details_type  = tx_frame_info->tx_details_type;
2120                    low_tx_details.tx_start_timestamp_mpdu = wlan_mac_low_get_tx_start_timestamp();
2121                    low_tx_details.tx_start_timestamp_frac_mpdu = wlan_mac_low_get_tx_start_timestamp_frac();
2122                }
2123            }
2124
2125            // Transmission is complete
2126            if( mac_hw_status & WLAN_MAC_STATUS_MASK_TX_A_DONE ) {
2127
2128                // Switch on the result of the transmission attempt
2129                //  Safe to read tx_ctrl_status here - TX_A_RESULT is only valid after TX_A_DONE asserts, which just happened
2130                mac_tx_ctrl_status = wlan_mac_get_tx_ctrl_status();
2131                switch (mac_tx_ctrl_status & WLAN_MAC_TXCTRL_STATUS_MASK_TX_A_RESULT) {
2132
2133                    //---------------------------------------------------------------------
2134                    case WLAN_MAC_TXCTRL_STATUS_TX_A_RESULT_NONE:
2135                        // Transmission was immediately successful - this implies no post-Tx timeout was required,
2136                        // so the core didn't wait for any post-Tx receptions (i.e. multicast/broadcast transmission)
2137                        //
2138                        switch(tx_mode) {
2139                            case TX_MODE_SHORT:
2140                                reset_ssrc();
2141                                reset_cw();
2142                            break;
2143                            case TX_MODE_LONG:
2144                                reset_slrc();
2145                                reset_cw();
2146                            break;
2147                        }
2148
2149                        // Start a post-Tx backoff using the updated contention window
2150                        n_slots = rand_num_slots(RAND_SLOT_REASON_STANDARD_ACCESS);
2151                        wlan_mac_dcf_hw_start_backoff(n_slots);
2152                        gl_waiting_for_response = 0;
2153
2154                        // Send IPC message containing the details about this low-level transmission
2155                        wlan_mac_low_send_low_tx_details(pkt_buf, &low_tx_details);
2156                        tx_frame_info->tx_result = TX_FRAME_INFO_RESULT_SUCCESS;
2157                        return;
2158                    break;
2159
2160                    //---------------------------------------------------------------------
2161                    case WLAN_MAC_TXCTRL_STATUS_TX_A_RESULT_RX_STARTED:
2162                        // Transmission ended, followed by a new reception (hopefully a CTS or ACK)
2163
2164                        // Handle the new reception
2165                        rx_status       = wlan_mac_low_poll_frame_rx();
2166                        gl_waiting_for_response = 0;
2167
2168                        gl_long_mpdu_pkt_buf = PKT_BUF_INVALID;
2169
2170                        // Check if the reception is an ACK addressed to this node, received with a valid checksum
2171                        if ((tx_wait_state == TX_WAIT_CTS) &&
2172                            (rx_status & FRAME_RX_RET_STATUS_RECEIVED_PKT) &&
2173                            (rx_status & FRAME_RX_RET_TYPE_CTS) &&
2174                            (rx_status & FRAME_RX_RET_STATUS_GOOD) &&
2175                            (rx_status & FRAME_RX_RET_ADDR_MATCH)) {
2176
2177                            low_tx_details.flags |= TX_DETAILS_FLAGS_RECEIVED_RESPONSE;
2178
2179                            tx_wait_state = TX_WAIT_ACK;
2180
2181                            // We received the CTS, so we can reset our SSRC
2182                            //     NOTE: as per 9.3.3 of 802.11-2012, we do not reset our CW
2183                            //
2184                            reset_ssrc();
2185
2186                            // At this point, the MAC tx state machine has started anew to send a the MPDU itself.
2187                            // This was triggered by the frame_receive() context.  We know that the frame_receive context
2188                            // has started the transmission of the MPDU.  This ensures we are not kicked out of the
2189                            // do-while loop.
2190                            //
2191                            // NOTE: This assignment is better than re-reading wlan_mac_get_status() in the case of a short
2192                            // MPDU, where we may skip the PENDING state directly to DONE without this code context seeing it.
2193                            //
2194                            mac_hw_status |= WLAN_MAC_STATUS_MASK_TX_A_PENDING;
2195
2196                            // Set tx_has_started control variable back to 0 so low_tx_details can be
2197                            // re-evaluated with MPDU Tx information
2198                            tx_has_started = 0;
2199
2200                            continue;
2201
2202                        } else if ((tx_wait_state == TX_WAIT_ACK) &&
2203                                   (rx_status & FRAME_RX_RET_STATUS_RECEIVED_PKT) &&
2204                                   (rx_status & FRAME_RX_RET_TYPE_ACK) &&
2205                                   (rx_status & FRAME_RX_RET_STATUS_GOOD) &&
2206                                   (rx_status & FRAME_RX_RET_ADDR_MATCH)) {
2207
2208                                low_tx_details.flags |= TX_DETAILS_FLAGS_RECEIVED_RESPONSE;
2209
2210                                // Update contention window
2211                                switch(tx_mode) {
2212                                    case TX_MODE_SHORT:
2213                                        reset_ssrc();
2214                                        reset_cw();
2215                                    break;
2216                                    case TX_MODE_LONG:
2217                                        reset_slrc();
2218                                        reset_cw();
2219                                    break;
2220                                }
2221
2222                                // Start a post-Tx backoff using the updated contention window
2223                                n_slots = rand_num_slots(RAND_SLOT_REASON_STANDARD_ACCESS);
2224                                wlan_mac_dcf_hw_start_backoff(n_slots);
2225
2226                                // Send IPC message containing the details about this low-level transmission
2227                                wlan_mac_low_send_low_tx_details(pkt_buf, &low_tx_details);
2228                                tx_frame_info->tx_result = TX_FRAME_INFO_RESULT_SUCCESS;
2229                                return;
2230
2231                        } else {
2232                            // Received a packet immediately after transmitting, but it wasn't the ACK we wanted
2233                            // It could have been our ACK with a bad checksum or a different packet altogether
2234
2235                            switch(tx_wait_state) {
2236                                case TX_WAIT_ACK:
2237                                    // We were waiting for an ACK
2238                                    //   - Depending on the size of the MPDU, we will increment either the SRC or the LRC
2239                                    //
2240                                    header->frame_control_2 = (header->frame_control_2) | MAC_FRAME_CTRL2_FLAG_RETRY;
2241
2242                                    switch(tx_mode) {
2243                                        case TX_MODE_SHORT:
2244                                            increment_src(&short_retry_count);
2245                                        break;
2246                                        case TX_MODE_LONG:
2247                                            increment_lrc(&long_retry_count);
2248                                        break;
2249                                    }
2250                                break;
2251
2252                                case TX_WAIT_CTS:
2253                                    // We were waiting for a CTS but did not get it.
2254                                    //     - Increment the SRC
2255                                    //
2256                                    increment_src(&short_retry_count);
2257                                break;
2258
2259                                case TX_WAIT_NONE:
2260                                    xil_printf("Error: unexpected state");
2261                                break;
2262                            }
2263
2264                            // Start the post-Tx backoff
2265                            n_slots = rand_num_slots(RAND_SLOT_REASON_STANDARD_ACCESS);
2266                            wlan_mac_dcf_hw_start_backoff(n_slots);
2267
2268                            // Send IPC message containing the details about this low-level transmission
2269                            wlan_mac_low_send_low_tx_details(pkt_buf, &low_tx_details);
2270
2271                            // Now we evaluate the SRC and LRC to see if either has reached its maximum
2272                            //     NOTE:  Use >= here to handle unlikely case of retryLimit values changing mid-Tx
2273                            if ((short_retry_count >= gl_dot11ShortRetryLimit) ||
2274                                (long_retry_count >= gl_dot11LongRetryLimit )) {
2275                                gl_waiting_for_response = 0;
2276                                tx_frame_info->tx_result = TX_FRAME_INFO_RESULT_FAILURE;
2277                                return;
2278                            }
2279
2280                            poll_tbtt_and_send_beacon();
2281
2282                            // Poll IPC rx
2283                            // TODO: Need to handle implications of an IPC message changing something like channel
2284                            wlan_mac_low_poll_ipc_rx();
2285
2286
2287                            // Jump to next loop iteration
2288                            continue;
2289                        }
2290                    break;
2291
2292                    //---------------------------------------------------------------------
2293                    case WLAN_MAC_TXCTRL_STATUS_TX_A_RESULT_TIMEOUT:
2294                        // Tx required timeout, timeout expired with no receptions
2295                        gl_waiting_for_response = 0;
2296
2297                        gl_long_mpdu_pkt_buf = PKT_BUF_INVALID;
2298
2299                        switch (tx_wait_state) {
2300                            case TX_WAIT_ACK:
2301                                // We were waiting for an ACK
2302                                //     - Depending on the size of the MPDU, we will increment either the SRC or the LRC
2303                                //
2304                                header->frame_control_2 = (header->frame_control_2) | MAC_FRAME_CTRL2_FLAG_RETRY;
2305
2306                                switch(tx_mode){
2307                                    case TX_MODE_SHORT:
2308                                        increment_src(&short_retry_count);
2309                                    break;
2310                                    case TX_MODE_LONG:
2311                                        increment_lrc(&long_retry_count);
2312                                    break;
2313                                }
2314                            break;
2315
2316                            case TX_WAIT_CTS:
2317                                // We were waiting for a CTS but did not get it.
2318                                //     - Increment the SRC
2319                                increment_src(&short_retry_count);
2320                            break;
2321
2322                            case TX_WAIT_NONE:
2323                                xil_printf("Error: unexpected state");
2324                            break;
2325                        }
2326
2327                        // Start the post-Tx backoff
2328                        n_slots = rand_num_slots(RAND_SLOT_REASON_STANDARD_ACCESS);
2329                        wlan_mac_dcf_hw_start_backoff(n_slots);
2330
2331                        // Send IPC message containing the details about this low-level transmission
2332                        wlan_mac_low_send_low_tx_details(pkt_buf, &low_tx_details);
2333
2334                        // Now we evaluate the SRC and LRC to see if either has reached its maximum
2335                        if ((short_retry_count == gl_dot11ShortRetryLimit) ||
2336                            (long_retry_count  == gl_dot11LongRetryLimit )) {
2337                            tx_frame_info->tx_result = TX_FRAME_INFO_RESULT_FAILURE;
2338                            return;
2339                        }
2340                        poll_tbtt_and_send_beacon();
2341
2342                        // Poll IPC rx
2343                        // TODO: Need to handle implications of an IPC message changing something like channel
2344                        wlan_mac_low_poll_ipc_rx();
2345
2346                        // Jump to next loop iteration
2347                        continue;
2348                    break;
2349                }
2350
2351            // else for if(mac_hw_status & WLAN_MAC_STATUS_MASK_TX_A_DONE)
2352            } else {
2353                //  This is the same MAC status check performed in the framework wlan_mac_low_poll_frame_rx()
2354                //  It is critical to check the Rx status here using the same status register read that was
2355                //  used in the Tx state checking above. Skipping this and calling wlan_mac_low_poll_frame_rx()
2356                //  directly leads to a race between the Tx status checking above and Rx status checking
2357                if ((tx_has_started == 0) && (mac_hw_status & WLAN_MAC_STATUS_MASK_RX_PHY_STARTED)) {
2358                    gl_waiting_for_response = 0;
2359                    rx_status = wlan_mac_low_poll_frame_rx();
2360                } else{
2361                    if(tx_has_started == 0) poll_tbtt_and_send_beacon();
2362
2363                    // Poll IPC rx
2364                    // TODO: Need to handle implications of an IPC message changing something like channel
2365                    wlan_mac_low_poll_ipc_rx();
2366                }
2367            } // END if(Tx A state machine done)
2368        } while( mac_hw_status & WLAN_MAC_STATUS_MASK_TX_A_PENDING );
2369    } // end retransmission loop
2370    gl_waiting_for_response = 0;
2371    return;
2372}
2373
2374
2375
2376/*****************************************************************************/
2377/**
2378 * @brief Increment Short Retry Count
2379 *
2380 * This function increments the short retry count. According to Section 9.3.3
2381 * of 802.11-2012, incrementing the short retry count also causes the
2382 * the following:
2383 *      1) An increment of the station short retry count
2384 *      2) An increase of the contention window (which is technically dependent
2385 *         on the station count incremented in the first step)
2386 *
2387 * @param   src_ptr          - Pointer to short retry count
2388 * @return  None
2389 */
2390inline void increment_src(u16* src_ptr){
2391    // Increment the Short Retry Count
2392    (*src_ptr)++;
2393
2394    gl_stationShortRetryCount = sat_add32(gl_stationShortRetryCount, 1);
2395
2396    if (gl_stationShortRetryCount == gl_dot11ShortRetryLimit) {
2397        reset_cw();
2398    } else {
2399        gl_cw_exp = WLAN_MIN(gl_cw_exp + 1, gl_cw_exp_max);
2400    }
2401}
2402
2403
2404
2405/*****************************************************************************/
2406/**
2407 * @brief Increment Long Retry Count
2408 *
2409 * This function increments the long retry count. According to Section 9.3.3
2410 * of 802.11-2012, incrementing the long retry count also causes the
2411 * the following:
2412 *      1) An increment of the station long retry count
2413 *      2) An increase of the contention window (which is technically dependent
2414 *         on the station count incremented in the first step)
2415 *
2416 * @param   src_ptr          - Pointer to long retry count
2417 * @return  None
2418 */
2419inline void increment_lrc(u16* lrc_ptr){
2420    // Increment the Long Retry Count
2421    (*lrc_ptr)++;
2422
2423    gl_stationLongRetryCount = sat_add32(gl_stationLongRetryCount, 1);
2424
2425    if(gl_stationLongRetryCount == gl_dot11LongRetryLimit){
2426        reset_cw();
2427    } else {
2428        gl_cw_exp = WLAN_MIN(gl_cw_exp + 1, gl_cw_exp_max);
2429    }
2430}
2431
2432
2433
2434/*****************************************************************************/
2435/**
2436 * @brief Reset Station Short Retry Count
2437 *
2438 * @param   None
2439 * @return  None
2440 *
2441 * @note    Resetting the SSRC does not necessarily indicate that the contention window should be reset.
2442 *     e.g., the reception of a valid CTS.
2443 */
2444inline void reset_ssrc(){
2445    gl_stationShortRetryCount = 0;
2446}
2447
2448
2449
2450/*****************************************************************************/
2451/**
2452 * @brief Reset Station Long Retry Count
2453 *
2454 * @param   None
2455 * @return  None
2456 */
2457inline void reset_slrc(){
2458    gl_stationLongRetryCount = 0;
2459}
2460
2461
2462
2463/*****************************************************************************/
2464/**
2465 * @brief Reset Contention Window
2466 *
2467 * @param   None
2468 * @return  None
2469 */
2470inline void reset_cw(){
2471    gl_cw_exp = gl_cw_exp_min;
2472}
2473
2474
2475
2476/*****************************************************************************/
2477/**
2478 * @brief Generate a random number in the range set by the current contention window
2479 *
2480 * When reason is RAND_SLOT_REASON_IBSS_BEACON the random draw is taken from the range
2481 * [0, 2*CWmin], used for pre-beacon backoffs in IBSS (per 802.11-2012 10.1.3.3)
2482 *
2483 * @param   reason           - Code for the random draw; must be RAND_SLOT_REASON_STANDARD_ACCESS or RAND_SLOT_REASON_IBSS_BEACON
2484 * @return  u32              - Random integer based on reason
2485 */
2486inline u32 rand_num_slots(u8 reason){
2487    // Generates a uniform random value between [0, (2^(gl_cw_exp) - 1)], where gl_cw_exp is a positive integer
2488    // This function assumed RAND_MAX = 2^31.
2489    // | gl_cw_exp |    CW       |
2490    // |     4     |  [0,   15]  |
2491    // |     5     |  [0,   31]  |
2492    // |     6     |  [0,   63]  |
2493    // |     7     |  [0,  123]  |
2494    // |     8     |  [0,  255]  |
2495    // |     9     |  [0,  511]  |
2496    // |    10     |  [0, 1023]  |
2497    //
2498    volatile u32 n_slots;
2499
2500    switch(reason) {
2501        case RAND_SLOT_REASON_STANDARD_ACCESS:
2502            n_slots = ((unsigned int)rand() >> (32 - (gl_cw_exp + 1)));
2503        break;
2504
2505        case RAND_SLOT_REASON_IBSS_BEACON:
2506            // Section 10.1.3.3 of 802.11-2012: Backoffs prior to IBSS beacons are drawn from [0, 2*CWmin]
2507            n_slots = ((unsigned int)rand() >> (32 - (gl_cw_exp_min + 1 + 1)));
2508        break;
2509    }
2510
2511    return n_slots;
2512}
2513
2514
2515
2516/*****************************************************************************/
2517/**
2518 * @brief Start a backoff
2519 *
2520 * This function will start a backoff.  If a backoff is already running, the backoff-start attempt
2521 * will be safely ignored and the function will do nothing.
2522 *
2523 * @param   num_slots        - Duration of backoff interval, in units of slots
2524 * @return  None
2525 */
2526void wlan_mac_dcf_hw_start_backoff(u16 num_slots) {
2527    // WLAN_MAC_REG_SW_BACKOFF_CTRL:
2528    //     b[15:0] : Num slots
2529    //     b[31]   : Start backoff
2530
2531    // Write num_slots and toggle start
2532    Xil_Out32(WLAN_MAC_REG_SW_BACKOFF_CTRL, (num_slots & 0xFFFF) | 0x80000000);
2533    Xil_Out32(WLAN_MAC_REG_SW_BACKOFF_CTRL, (num_slots & 0xFFFF));
2534}
2535
2536/*****************************************************************************/
2537/**
2538 * @brief Process DCF Low Parameters
2539 *
2540 * This method is part of the IPC_MBOX_LOW_PARAM parameter processing in the low framework.  It
2541 * will process DCF specific low parameters.
2542 *
2543 * @param   mode             - Mode to process parameter:  IPC_REG_WRITE_MODE or IPC_REG_READ_MODE
2544 * @param   payload          - Pointer to parameter and arguments
2545 * @return  none
2546 */
2547void process_low_param(u8 mode, u32* payload){
2548
2549    switch(mode){
2550        case IPC_REG_WRITE_MODE: {
2551            switch(payload[0]){
2552
2553                //---------------------------------------------------------------------
2554                case LOW_PARAM_DCF_RTS_THRESH: {
2555                    gl_dot11RTSThreshold = payload[1];
2556                }
2557                break;
2558
2559                //---------------------------------------------------------------------
2560                case LOW_PARAM_DCF_DOT11SHORTRETRY: {
2561                    gl_dot11ShortRetryLimit = payload[1];
2562                }
2563                break;
2564
2565                //---------------------------------------------------------------------
2566                case LOW_PARAM_DCF_DOT11LONGRETRY: {
2567                    gl_dot11LongRetryLimit = payload[1];
2568                }
2569                break;
2570
2571                //---------------------------------------------------------------------
2572                case LOW_PARAM_DCF_CW_EXP_MIN: {
2573                    gl_cw_exp_min = payload[1];
2574                }
2575                break;
2576
2577                //---------------------------------------------------------------------
2578                case LOW_PARAM_DCF_CW_EXP_MAX: {
2579                    gl_cw_exp_max = payload[1];
2580                }
2581                break;
2582
2583                //---------------------------------------------------------------------
2584                default: {}
2585                break;
2586            }
2587        }
2588        break;
2589
2590        case IPC_REG_READ_MODE: {
2591            // Not supported.  See comment in wlan_mac_low.c for IPC_REG_READ_MODE mode.
2592        }
2593        break;
2594
2595        default: {
2596            xil_printf("Unknown mode 0x%08x\n", mode);
2597        }
2598        break;
2599    }
2600
2601    return;
2602}
Note: See TracBrowser for help on using the repository browser.