source: ReferenceDesigns/w3_802.11/c/wlan_mac_low_framework/wlan_mac_low.c @ 5490

Last change on this file since 5490 was 5485, checked in by murphpo, 8 years ago

fixing comments in set_phy_samp_rate

File size: 64.9 KB
Line 
1/** @file wlan_mac_low.c
2 *  @brief Low-level WLAN MAC High Framework
3 *
4 *  This contains the low-level code for accessing the WLAN MAC Low Framework.
5 *
6 *  @copyright Copyright 2014-2016, 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 *  @author Chris Hunter (chunter [at] mangocomm.com)
12 *  @author Patrick Murphy (murphpo [at] mangocomm.com)
13 *  @author Erik Welsh (welsh [at] mangocomm.com)
14 */
15/***************************** Include Files *********************************/
16
17// Xilinx / Standard library includes
18#include <xparameters.h>
19#include <xil_io.h>
20#include <xio.h>
21#include <stdlib.h>
22#include <string.h>
23
24// WARP Includes
25#include "w3_userio.h"
26#include "w3_ad_controller.h"
27#include "w3_clock_controller.h"
28#include "w3_iic_eeprom.h"
29#include "radio_controller.h"
30
31// WLAN includes
32#include "wlan_mac_time_util.h"
33#include "wlan_mac_mailbox_util.h"
34#include "wlan_mac_802_11_defs.h"
35#include "wlan_phy_util.h"
36#include "wlan_mac_low.h"
37
38// WLAN Exp includes
39#include "wlan_exp.h"
40
41
42/*************************** Constant Definitions ****************************/
43
44#define DBG_PRINT  0
45
46// Power / RSSI conversion
47#define POW_LOOKUP_SHIFT  3                   // Shift from 10 bit RSSI to 7 bit for lookup
48
49
50/*********************** Global Variable Definitions *************************/
51
52
53/*************************** Functions Prototypes ****************************/
54
55
56/*************************** Variable Definitions ****************************/
57volatile static phy_samp_rate_t   gl_phy_samp_rate;                                 ///< Current PHY sampling rate
58volatile static u32               mac_param_chan;                                   ///< Current channel of the lower-level MAC
59volatile static u8                mac_param_band;                                   ///< Current band of the lower-level MAC
60volatile static u8                mac_param_dsss_en;                                ///< Enable / Disable DSSS when possible
61volatile static s8                mac_param_ctrl_tx_pow;                            ///< Current transmit power (dBm) for control packets
62volatile static u32               mac_param_rx_filter;                              ///< Current filter applied to packet receptions
63volatile static u8                rx_pkt_buf;                                       ///< Current receive buffer of the lower-level MAC
64
65static u32                        cpu_low_status;                                   ///< Status flags that are reported to upper-level MAC
66static u32                        cpu_low_type;                                     ///< wlan_exp CPU_LOW type that is reported to upperp-level MAC
67
68static wlan_ipc_msg_t             ipc_msg_from_high;                                          ///< Buffer for incoming IPC messages
69static u32                        ipc_msg_from_high_payload[MAILBOX_BUFFER_MAX_NUM_WORDS];    ///< Buffer for payload of incoming IPC messages
70
71volatile static u8           allow_new_mpdu_tx;                                     ///< Toggle for allowing new MPDU Tx requests to be processed
72volatile static s8           pkt_buf_pending_tx;                                    ///< Internal state variable for knowing if an MPDU Tx request is pending
73
74// Callback function pointers
75static function_ptr_t        frame_rx_callback;                                     ///< User callback frame receptions
76static function_ptr_t        frame_tx_callback;                                     ///< User callback frame transmissions
77
78static function_ptr_t        beacon_txrx_config_callback;
79static function_ptr_t        mactime_change_callback;
80static function_ptr_t        sample_rate_change_callback;
81
82static function_ptr_t        ipc_low_param_callback;                                ///< User callback for IPC_MBOX_LOW_PARAM ipc calls
83
84// Unique transmit sequence number
85volatile static u64          unique_seq;
86
87// NOTE: this statically allocated space should be larger than the maximum number of attempts
88//     dot11ShortRetryLimit+dot11LongRetryLimit-1
89static wlan_mac_low_tx_details_t  low_tx_details[50]; //TODO make a #define
90
91// Constant LUTs for MCS
92const static u16 mcs_to_n_dbps_nonht_lut[WLAN_MAC_NUM_MCS] = {24, 36, 48, 72, 96, 144, 192, 216};
93const static u16 mcs_to_n_dbps_htmf_lut[WLAN_MAC_NUM_MCS] = {26, 52, 78, 104, 156, 208, 234, 260};
94
95/******************************** Functions **********************************/
96
97
98/*****************************************************************************/
99/**
100 * @brief Initialize MAC Low Framework
101 *
102 * This function initializes the MAC Low Framework by setting
103 * up the hardware and other subsystems in the framework.
104 *
105 * @param   type             - Lower-level MAC type
106 * @return  int              - Initialization status (0 = success)
107 */
108int wlan_mac_low_init(u32 type){
109    u32              status;
110    rx_frame_info_t* rx_frame_info;
111    tx_frame_info_t* tx_frame_info;
112    u32              i;
113
114    mac_param_dsss_en        = 1;
115    mac_param_band           = RC_24GHZ;
116    mac_param_ctrl_tx_pow    = 10;
117    cpu_low_status           = 0;
118    cpu_low_type             = type;
119
120    unique_seq = 0;
121
122    mac_param_rx_filter      = (RX_FILTER_FCS_ALL | RX_FILTER_HDR_ALL);
123
124    frame_rx_callback           = (function_ptr_t) wlan_null_callback;
125    frame_tx_callback           = (function_ptr_t) wlan_null_callback;
126    ipc_low_param_callback      = (function_ptr_t) wlan_null_callback;
127    beacon_txrx_config_callback = (function_ptr_t) wlan_null_callback;
128    mactime_change_callback     = (function_ptr_t) wlan_null_callback;
129    sample_rate_change_callback = (function_ptr_t) wlan_null_callback;
130    allow_new_mpdu_tx        = 1;
131    pkt_buf_pending_tx       = -1; // -1 is an invalid pkt_buf index
132
133    status = w3_node_init();
134
135    if(status != 0) {
136        xil_printf("Error in w3_node_init()! Exiting\n");
137        return -1;
138    }
139
140    // Initialize mailbox
141    init_mailbox();
142
143    // Initialize packet buffers
144    init_pkt_buf();
145
146    // ***************************************************
147    // Initialize Transmit Packet Buffers
148    // ***************************************************
149    for(i = 0; i < NUM_TX_PKT_BUFS; i++){
150        tx_frame_info = (tx_frame_info_t*)TX_PKT_BUF_TO_ADDR(i);
151        switch(i){
152            case TX_PKT_BUF_MPDU_1:
153            case TX_PKT_BUF_MPDU_2:
154            case TX_PKT_BUF_MPDU_3:
155                switch(tx_frame_info->tx_pkt_buf_state){
156                    case TX_PKT_BUF_UNINITIALIZED:
157                    case TX_PKT_BUF_HIGH_CTRL:
158                        // CPU High will initialize
159                        break;
160                    break;
161                    case TX_PKT_BUF_READY:
162                    case TX_PKT_BUF_DONE:
163                        // CPU Low rebooted after finishing old Tx
164                        // No way to know if CPU Low sent TX_DONE(p) message - must reset p.state here
165                        //  Two potential races:
166                        //   -CPU High just rebooted and will also attempt setting p.state=TX_PKT_BUF_HIGH_CTRL
167                        //      No problem if both CPUs set state to TX_PKT_BUF_HIGH_CTRL
168                        //   -CPU High did not reboot and will attempt tx_done_handler(p)
169                        //      If p.state=TX_PKT_BUF_HIGH_CTRL when tx_done_handler(p) runs, CPU High will fail gracefully
170                        //      If p.state set to TX_PKT_BUF_HIGH_CTRL during tx_done_handler(p), CPU High will succeed normally
171                    case TX_PKT_BUF_LOW_CTRL:
172                        // CPU Low rebooted after CPU High submitted packet for Tx
173                        //  Release lock and reset state
174                        //  CPU High will find this TX_PKT_BUF_HIGH_CTRL buffer in next ping/pong update
175                    default:
176                        // Something went wrong if tx_pkt_buf_state is something
177                        // other than one of the tx_pkt_buf_state_t enums. We'll
178                        // attempt to resolve the problem by explicitly setting
179                        // the state.
180                        tx_frame_info->tx_pkt_buf_state = TX_PKT_BUF_HIGH_CTRL;
181                        unlock_tx_pkt_buf(i);
182                    break;
183                }
184            break;
185            case TX_PKT_BUF_BEACON:
186                unlock_tx_pkt_buf(i);
187            break;
188            case TX_PKT_BUF_RTS:
189            case TX_PKT_BUF_ACK_CTS:
190                force_lock_tx_pkt_buf(i);
191                tx_frame_info->tx_pkt_buf_state = TX_PKT_BUF_LOW_CTRL;
192            default:
193            break;
194        }
195    }
196    // ***************************************************
197    // Initialize Receive Packet Buffers
198    // ***************************************************
199    for(i = 0; i < NUM_RX_PKT_BUFS; i++){
200        rx_frame_info = (rx_frame_info_t*)RX_PKT_BUF_TO_ADDR(i);
201        switch(rx_frame_info->rx_pkt_buf_state){
202           case RX_PKT_BUF_UNINITIALIZED:
203           case RX_PKT_BUF_LOW_CTRL:
204           default:
205                // Something went wrong if rx_pkt_buf_state is something
206                // other than one of the rx_pkt_buf_state_t enums. We'll
207                // attempt to resolve the problem by explicitly setting
208                // the state.
209               force_lock_rx_pkt_buf(i);
210               rx_frame_info->rx_pkt_buf_state = RX_PKT_BUF_LOW_CTRL;
211           break;
212           case RX_PKT_BUF_HIGH_CTRL:
213           case RX_PKT_BUF_READY:
214               // CPU Low rebooted after submitting packet for de-encapsulation/logging
215               //  Will be handled by CPU High, either because CPU High is about
216               //  to de-encapsulate/log p or just rebooted and will clean up
217           break;
218        }
219    }
220
221    // Create IPC message to receive into
222    ipc_msg_from_high.payload_ptr = &(ipc_msg_from_high_payload[0]);
223
224    // Point the PHY to an empty Rx Pkt Buffer
225    wlan_mac_low_lock_empty_rx_pkt_buf();
226
227    // Move the PHY's starting address into the packet buffers by PHY_XX_PKT_BUF_PHY_HDR_OFFSET.
228    // This accounts for the metadata located at the front of every packet buffer (Xx_mpdu_info)
229    wlan_phy_rx_pkt_buf_phy_hdr_offset(PHY_RX_PKT_BUF_PHY_HDR_OFFSET);
230    wlan_phy_tx_pkt_buf_phy_hdr_offset(PHY_TX_PKT_BUF_PHY_HDR_OFFSET);
231
232    wlan_mac_reset(1);
233    wlan_radio_init();
234    wlan_phy_init();
235    wlan_mac_hw_init();
236    wlan_mac_reset(0);
237
238    // Initialize the HW info structure
239    init_mac_hw_info();
240
241    // Set the NAV ignore addr to this HW address
242    wlan_mac_low_set_nav_check_addr(get_mac_hw_addr_wlan());
243
244    return 0;
245}
246
247
248
249/*****************************************************************************/
250/**
251 * @brief Finish Initializing MAC Low Framework
252 *
253 * This function finishes the initialization and notifies the upper-level
254 * MAC that it has finished booting.
255 *
256 * @param   None
257 * @return  None
258 */
259void wlan_mac_low_init_finish(){
260
261    //Set the default PHY sample rate to 20 MSps
262    set_phy_samp_rate(PHY_20M);
263
264    // Update the CPU Low status
265    cpu_low_status |= CPU_STATUS_INITIALIZED;
266
267    wlan_mac_low_send_status(CPU_STATUS_REASON_BOOTED);
268
269}
270
271void wlan_mac_low_send_status(u8 cpu_status_reason){
272    wlan_ipc_msg_t ipc_msg_to_high;
273    u32            ipc_msg_to_high_payload[2];
274
275    // Send a message to other processor to say that this processor is initialized and ready
276    ipc_msg_to_high.msg_id            = IPC_MBOX_MSG_ID(IPC_MBOX_CPU_STATUS);
277    ipc_msg_to_high.arg0              = cpu_status_reason;
278    ipc_msg_to_high.num_payload_words = 2;
279    ipc_msg_to_high.payload_ptr       = &(ipc_msg_to_high_payload[0]);
280    ipc_msg_to_high_payload[0]        = cpu_low_status;
281    ipc_msg_to_high_payload[1]        = cpu_low_type;
282
283    write_mailbox_msg(&ipc_msg_to_high);
284}
285
286
287/*****************************************************************************/
288/**
289 * @brief Set the PHY Sampling Rate
290 *
291 * This function should be called to switch the PHY sampling rate between
292 * 10/20/40 MSps.
293 *
294 * @param   phy_samp_rate_t phy_samp_rate
295 * @return  None
296 */
297void set_phy_samp_rate(phy_samp_rate_t phy_samp_rate){
298
299    // Check sample rate argument
300    //     - Must be in [PHY_10M, PHY_20M, PHY_40M]
301    if (!((phy_samp_rate == PHY_10M) || (phy_samp_rate == PHY_20M) || (phy_samp_rate == PHY_40M))) {
302        return;
303    }
304
305    // Set global sample rate variable
306    gl_phy_samp_rate = phy_samp_rate;
307
308    // Assert PHY Tx/Rx and MAC Resets
309    REG_SET_BITS(WLAN_RX_REG_CTRL, WLAN_RX_REG_CTRL_RESET);
310    REG_SET_BITS(WLAN_TX_REG_CFG, WLAN_TX_REG_CFG_RESET);
311    wlan_mac_reset(1);
312
313    // DSSS Rx only supported at 20Msps
314    switch(phy_samp_rate){
315        case PHY_10M:
316        case PHY_40M:
317            // Always disable DSSS when PHY sample rate is not 20 MSps
318            wlan_phy_DSSS_rx_disable();
319        break;
320        case PHY_20M:
321            // Enable DSSS if global variable indicates it should be enabled and RF band allows it
322            if ((mac_param_dsss_en) && (mac_param_band == RC_24GHZ)) {
323                wlan_phy_DSSS_rx_enable();
324            }
325        break;
326    }
327
328    // Configure auto-correlation packet detection
329    //  wlan_phy_rx_pktDet_autoCorr_ofdm_cfg(corr_thresh, energy_thresh, min_dur, post_wait)
330    switch(phy_samp_rate){
331        case PHY_40M:
332            //TODO: The 2 value is suspiciously low
333            wlan_phy_rx_pktDet_autoCorr_ofdm_cfg(200, 2, 15, 0x3F);
334        break;
335        case PHY_10M:
336        case PHY_20M:
337            wlan_phy_rx_pktDet_autoCorr_ofdm_cfg(200, 9, 4, 0x3F);
338        break;
339    }
340
341    // Set post Rx extension
342    //  Number of sample periods post-Rx the PHY waits before asserting Rx END - must be long enough for worst-case
343    //   decoding latency and should result in RX_END asserting 6 usec after the last sample was received
344    switch(phy_samp_rate){
345        case PHY_40M:
346            // 6us Extension
347            wlan_phy_rx_set_extension(6*40);
348        break;
349        case PHY_20M:
350            // 6us Extension
351            wlan_phy_rx_set_extension(6*20);
352        break;
353        case PHY_10M:
354            // 6us Extension
355            wlan_phy_rx_set_extension(6*10);
356        break;
357    }
358
359    // Set Tx duration extension, in units of sample periods
360    switch(phy_samp_rate){
361        case PHY_40M:
362            // 364 20MHz sample periods.
363            // The extra 3 usec properly delays the assertion of TX END to match the assertion of RX END at the receiving node.
364            wlan_phy_tx_set_extension(364);
365
366            // Set extension from last samp output to RF Tx -> Rx transition
367            //     This delay allows the Tx pipeline to finish driving samples into DACs
368            //     and for DAC->RF frontend to finish output Tx waveform
369            wlan_phy_tx_set_txen_extension(100);
370
371            // Set extension from RF Rx -> Tx to un-blocking Rx samples
372            wlan_phy_tx_set_rx_invalid_extension(300);
373        break;
374        case PHY_20M:
375            // 182 20MHz sample periods.
376            // The extra 3 usec properly delays the assertion of TX END to match the assertion of RX END at the receiving node.
377            wlan_phy_tx_set_extension(182);
378
379            // Set extension from last samp output to RF Tx -> Rx transition
380            //     This delay allows the Tx pipeline to finish driving samples into DACs
381            //     and for DAC->RF frontend to finish output Tx waveform
382            wlan_phy_tx_set_txen_extension(50);
383
384            // Set extension from RF Rx -> Tx to un-blocking Rx samples
385            wlan_phy_tx_set_rx_invalid_extension(150);
386        break;
387        case PHY_10M:
388            wlan_phy_tx_set_extension(91);
389
390            // Set extension from last samp output to RF Tx -> Rx transition
391            //     This delay allows the Tx pipeline to finish driving samples into DACs
392            //     and for DAC->RF frontend to finish output Tx waveform
393            wlan_phy_tx_set_txen_extension(25);
394
395            // Set extension from RF Rx -> Tx to un-blocking Rx samples
396            wlan_phy_tx_set_rx_invalid_extension(75);
397        break;
398    }
399
400    // Set RF interface clocking and interp/decimation filters
401    switch(phy_samp_rate){
402        case PHY_40M:
403            // Set ADC_CLK=DAC_CLK=40MHz, interp_rate=decim_rate=1
404            clk_config_dividers(CLK_BASEADDR, 2, (CLK_SAMP_OUTSEL_AD_RFA | CLK_SAMP_OUTSEL_AD_RFB));
405            ad_config_filters(AD_BASEADDR, AD_ALL_RF, 1, 1);
406            ad_spi_write(AD_BASEADDR, (AD_ALL_RF), 0x32, 0x2F);
407            ad_spi_write(AD_BASEADDR, (AD_ALL_RF), 0x33, 0x08);
408        break;
409        case PHY_20M:
410            // Set ADC_CLK=DAC_CLK=40MHz, interp_rate=decim_rate=2
411            clk_config_dividers(CLK_BASEADDR, 2, (CLK_SAMP_OUTSEL_AD_RFA | CLK_SAMP_OUTSEL_AD_RFB));
412            ad_config_filters(AD_BASEADDR, AD_ALL_RF, 2, 2);
413            ad_spi_write(AD_BASEADDR, (AD_ALL_RF), 0x32, 0x27);
414            ad_spi_write(AD_BASEADDR, (AD_ALL_RF), 0x33, 0x08);
415        break;
416        case PHY_10M:
417            // Set ADC_CLK=DAC_CLK=20MHz, interp_rate=decim_rate=2
418            clk_config_dividers(CLK_BASEADDR, 4, (CLK_SAMP_OUTSEL_AD_RFA | CLK_SAMP_OUTSEL_AD_RFB));
419            ad_config_filters(AD_BASEADDR, AD_ALL_RF, 2, 2);
420            ad_spi_write(AD_BASEADDR, (AD_ALL_RF), 0x32, 0x27);
421            ad_spi_write(AD_BASEADDR, (AD_ALL_RF), 0x33, 0x08);
422        break;
423    }
424
425    switch(phy_samp_rate){
426        case PHY_40M:
427            radio_controller_setRadioParam(RC_BASEADDR, RC_ALL_RF, RC_PARAMID_RXLPF_BW, 3);
428            radio_controller_setRadioParam(RC_BASEADDR, RC_ALL_RF, RC_PARAMID_TXLPF_BW, 3);
429        break;
430        case PHY_10M:
431        case PHY_20M:
432            radio_controller_setRadioParam(RC_BASEADDR, RC_ALL_RF, RC_PARAMID_RXLPF_BW, 1);
433            radio_controller_setRadioParam(RC_BASEADDR, RC_ALL_RF, RC_PARAMID_TXLPF_BW, 1);
434        break;
435    }
436
437    // AGC timing: capt_rssi_1, capt_rssi_2, capt_v_db, agc_done
438    switch(phy_samp_rate){
439        case PHY_40M:
440            wlan_agc_set_AGC_timing(10, 30, 90, 96);
441        break;
442        case PHY_10M:
443        case PHY_20M:
444            wlan_agc_set_AGC_timing(1, 30, 90, 96);
445        break;
446    }
447
448    // Call user callback so it can deal with any changes that need to happen due to a change in sampling rate
449    sample_rate_change_callback(gl_phy_samp_rate);
450
451    // Deassert PHY Tx/Rx and MAC Resets
452    REG_CLEAR_BITS(WLAN_RX_REG_CTRL, WLAN_RX_REG_CTRL_RESET);
453    REG_CLEAR_BITS(WLAN_TX_REG_CFG, WLAN_TX_REG_CFG_RESET);
454    wlan_mac_reset(0);
455
456    // Let PHY Tx take control of radio TXEN/RXEN
457    REG_CLEAR_BITS(WLAN_TX_REG_CFG, WLAN_TX_REG_CFG_SET_RC_RXEN);
458    REG_SET_BITS(WLAN_TX_REG_CFG, WLAN_TX_REG_CFG_SET_RC_RXEN);
459}
460
461
462/*****************************************************************************/
463/**
464 * @brief Initialize the DCF Hardware Core
465 *
466 * This function initializes the DCF hardware core.
467 *
468 * @param   None
469 * @return  None
470 */
471void wlan_mac_hw_init(){
472    // Enable blocking of the Rx PHY following good-FCS receptions and bad-FCS receptions
473    //     BLOCK_RX_ON_VALID_RXEND will block the Rx PHY on all RX_END events following valid RX_START events
474    //     This allows the wlan_exp framework to count and log bad FCS receptions
475    //
476    REG_SET_BITS(WLAN_MAC_REG_CONTROL, WLAN_MAC_CTRL_MASK_BLOCK_RX_ON_TX);
477
478    // Enable the NAV counter
479    REG_CLEAR_BITS(WLAN_MAC_REG_CONTROL, (WLAN_MAC_CTRL_MASK_DISABLE_NAV));
480
481    // Set sane defaults for MAC timing values. These will be overwritten by
482    // low-level applications that need to specify these times (e.g. the DCF)
483    wlan_mac_set_slot(9*10);
484    wlan_mac_set_DIFS(28*10);
485    wlan_mac_set_TxDIFS((28*10) - (TX_PHY_DLY_100NSEC));
486    wlan_mac_postTx_timer1_en(0);
487    wlan_mac_postRx_timer2_en(0);
488    wlan_mac_set_NAV_adj(0*10);
489    wlan_mac_set_EIFS(88*10);
490
491    // Set the TU target to 2^32-1 (max value) and hold TU_LATCH in reset
492    //  MAC Low application should re-enabled if needed
493    wlan_mac_set_tu_target(0xFFFFFFFF);
494    wlan_mac_reset_tu_target_latch(1);
495
496    // Clear any stale Rx events
497    wlan_mac_hw_clear_rx_started();
498}
499
500
501
502/*****************************************************************************/
503/**
504 * @brief Send Exception to Upper-Level MAC
505 *
506 * This function generates an IPC message for the upper-level MAC
507 * to tell it that something has gone wrong
508 *
509 * @param u32 reason
510 *  - reason code for the exception
511 * @return None
512 */
513inline void wlan_mac_low_send_exception(u32 reason){
514    wlan_ipc_msg_t ipc_msg_to_high;
515    u32            ipc_msg_to_high_payload[2];
516
517    // Update CPU Low status
518    cpu_low_status |= CPU_STATUS_EXCEPTION;
519
520    // Send an exception to CPU_HIGH along with a reason
521    ipc_msg_to_high.msg_id            = IPC_MBOX_MSG_ID(IPC_MBOX_CPU_STATUS);
522    ipc_msg_to_high.arg0              = (u8)CPU_STATUS_REASON_EXCEPTION;
523    ipc_msg_to_high.num_payload_words = 2;
524    ipc_msg_to_high.payload_ptr       = &(ipc_msg_to_high_payload[0]);
525    ipc_msg_to_high_payload[0]        = cpu_low_status;
526    ipc_msg_to_high_payload[1]        = reason;
527
528    write_mailbox_msg(&ipc_msg_to_high);
529
530    // Set the Hex display with the reason code and flash the LEDs
531    cpu_error_halt(reason);
532}
533
534/*****************************************************************************/
535/**
536 * @brief Poll the Receive Frame Start
537 *
538 * This function will poll the hardware to see if the PHY is currently receiving or
539 * has finished receiving a packet.  This will then dispatch the current RX packet
540 * buffer and PHY details to the frame_rx_callback(). The callback is responsible for
541 * updating the current Rx packet buffer, typically required if the received packet
542 * is passed to CPU High for further processing.
543 *
544 * @param   None
545 * @return  u32              - Status (See MAC Polling defines in wlan_mac_low.h)
546 */
547inline u32 wlan_mac_low_poll_frame_rx(){
548    phy_rx_details_t phy_details;
549
550    volatile u32 mac_hw_status;
551    volatile u32 phy_hdr_params;
552
553    int i = 0;
554
555    u32 return_status = 0;
556
557    // Read the MAC/PHY status
558    mac_hw_status = wlan_mac_get_status();
559
560    // Check if PHY has started a new reception
561    if(mac_hw_status & WLAN_MAC_STATUS_MASK_RX_PHY_STARTED) {
562
563        // Check whether this is an OFDM or DSSS Rx
564        if(wlan_mac_get_rx_phy_sel() == WLAN_MAC_PHY_RX_PHY_HDR_PHY_SEL_DSSS) {
565            // DSSS Rx - PHY Rx length is already valid, other params unused for DSSS
566            phy_details.phy_mode = PHY_MODE_DSSS;
567            phy_details.N_DBPS   = 0;
568
569            // Strip off extra pre-MAC-header bytes used in DSSS frames; this adjustment allows the next
570            //     function to treat OFDM and DSSS payloads the same
571            phy_details.length   = wlan_mac_get_rx_phy_length() - 5;
572            phy_details.mcs      = 0;
573
574            // Call the user callback to handle this Rx, capture return value
575            return_status |= POLL_MAC_STATUS_RECEIVED_PKT;
576            return_status |= frame_rx_callback(rx_pkt_buf, &phy_details);
577
578        } else {
579            // OFDM Rx - must wait for valid PHY header
580            // Order of operations is critical here
581            //  1) Read status first
582            //  2) Read PHY header register second
583            //  3) Check for complete PHY header - continue if complete
584            //  4) Else check for early PHY reset - quit if reset
585
586            while (1) {
587                mac_hw_status = wlan_mac_get_status();
588                phy_hdr_params = wlan_mac_get_rx_phy_hdr_params();
589
590                if(i++ > 1000000) {xil_printf("Stuck in OFDM Rx PHY hdr check: 0x%08x 0x%08x\n", mac_hw_status, phy_hdr_params);}
591
592                if(phy_hdr_params & WLAN_MAC_PHY_RX_PHY_HDR_READY) {
593                    // Rx PHY received enough bytes to decode PHY header
594                    //  Exit loop and check PHY header params
595                    break;
596                }
597                if((mac_hw_status & WLAN_MAC_STATUS_MASK_RX_PHY_ACTIVE) == 0) {
598                    // Rx PHY went idle before asserting RX_PHY_HDR_READY
599                    //  This only happens if the PHY is reset externally, possible if MAC starts a Tx during Rx
600                    //  Only option is to reset RX_STARTED and wait for next Rx
601
602                    // There is a 1-cycle race in this case, because RX_END asserts 1 cycle before RX_PHY_HDR_READY in the
603                    //  case of an invalid HT-SIG. The invalid HT-SIG generates an RX_END_ERROR which causes
604                    //  RX_END to assert. The simple workaround used below is to re-read phy_hdr_params one last time
605                    //  before concluding that the Rx PHY was reset unexpectedly
606                    break;
607                }
608            }
609
610            //  Re-read phy_hdr_params to resolve 1-cycle ambiguity in case of HT-SIG error
611            phy_hdr_params = wlan_mac_get_rx_phy_hdr_params();
612
613            // Decide how to handle this waveform
614            if(phy_hdr_params & WLAN_MAC_PHY_RX_PHY_HDR_READY) {
615                // Received PHY header - decide whether to call MAC callback
616                if( (phy_hdr_params & WLAN_MAC_PHY_RX_PHY_HDR_MASK_UNSUPPORTED) ||
617                    (wlan_mac_get_rx_phy_mode() > 0x2) ) {
618                    // Valid HT-SIG but unsupported waveform
619                    //  Rx PHY will hold ACTIVE until last samp but will not write payload
620                    //  HT-SIG fields (MCS, length) can be safely read here if desired
621                    // Or detected VHT waveform (not supported), did not attempt decoding VHT-SIG
622                    //xil_printf("Quitting - WLAN_MAC_PHY_RX_PHY_HDR_MASK_UNSUPPORTED (MCS = %d, Length = %d)", wlan_mac_get_rx_phy_mcs(), wlan_mac_get_rx_phy_length());
623
624                } else if(phy_hdr_params & WLAN_MAC_PHY_RX_PHY_HDR_MASK_RX_ERROR) {
625                    // Invalid HT-SIG (CRC error, invalid RESERVED or TAIL bits, invalid LENGTH, etc)
626                    //  Rx PHY has already released ACTIVE and will not write payload
627                    //  HT-SIG fields (MCS, length) should not be trusted in this case
628                    //xil_printf("Quitting - WLAN_MAC_PHY_RX_PHY_HDR_MASK_RX_ERROR");
629
630                } else {
631                    // NONHT waveform or HTMF waveform with supported HT-SIG - PHY will write payload
632                    //  Call lower MAC Rx callback
633                    //  Callback can safely return anytime (before or after RX_END)
634
635                    phy_details.phy_mode = wlan_mac_get_rx_phy_mode();
636                    phy_details.length   = wlan_mac_get_rx_phy_length();
637                    phy_details.mcs      = wlan_mac_get_rx_phy_mcs();
638                    phy_details.N_DBPS   = wlan_mac_low_mcs_to_n_dbps(phy_details.mcs, phy_details.phy_mode);
639
640                    return_status |= POLL_MAC_STATUS_RECEIVED_PKT;
641                    return_status |= frame_rx_callback(rx_pkt_buf, &phy_details);
642                }
643            } else {
644                // PHY went idle before PHY_HDR_DONE, probably due to external reset
645                //  The Rx PHY can be reset from software (only used in wlan_phy_init()) or hardware.
646                //  The hardware reset is asserted by the MAC core during Tx. Asserting Tx during Rx is
647                //  impossible with the normal DCF code, as packet det is treated as a busy medium. With a
648                //  custom MAC implementation that allows Tx during Rx this code block will catch the
649                //  unexpected reset events.
650
651                // PHY header cannot be trusted in this case - do nothing and return
652
653            }//END if(PHY_HDR_DONE)
654        } //END if(OFDM Rx)
655
656        // Clear the MAC status register RX_STARTED bit
657        //  By this point the framework and MAC are done with the current waveform, however it was handled.
658        //   The RX_STARTED bit is cleared in every case. It is important to only call clear_rx_started() after
659        //   the RX_STARTED latch has asserted. Calling it any other time creates a race that can miss Rx events
660        wlan_mac_hw_clear_rx_started();
661
662    } //END if(PHY_RX_STARTED)
663
664    return return_status;
665}
666
667/*****************************************************************************/
668/**
669 * @brief Poll for IPC Receptions
670 *
671 * This function is a non-blocking poll for IPC receptions from the upper-level MAC.
672 *
673 * @param   None
674 * @return  None
675 */
676inline void wlan_mac_low_poll_ipc_rx(){
677    // Poll mailbox read msg
678    if (read_mailbox_msg(&ipc_msg_from_high) == IPC_MBOX_SUCCESS) {
679        wlan_mac_low_process_ipc_msg(&ipc_msg_from_high);
680    }
681}
682
683
684
685/*****************************************************************************/
686/**
687 * @brief Process IPC Reception
688 *
689 * This is an internal function to the WLAN MAC Low framework to process
690 * received IPC messages and call the appropriate callback.
691 *
692 * @param   None
693 * @return  None
694 */
695void wlan_mac_low_process_ipc_msg(wlan_ipc_msg_t * msg){
696    wlan_ipc_msg_t           ipc_msg_to_high;
697
698    switch(IPC_MBOX_MSG_ID_TO_MSG(msg->msg_id)){
699
700        //---------------------------------------------------------------------
701        case IPC_MBOX_SET_MAC_TIME:
702            switch(msg->arg0){
703                default:
704                case 0:
705                    //Payload is an absolute MAC time that must be applied
706                    set_mac_time_usec( *(u64*)(msg->payload_ptr) );
707                    mactime_change_callback( (*(s64*)(msg->payload_ptr))-((s64)get_mac_time_usec()) );
708                break;
709                case 1:
710                    //Payload is a MAC time delta that must be applied
711                    apply_mac_time_delta_usec( *(s64*)(msg->payload_ptr));
712                    mactime_change_callback( *(s64*)(msg->payload_ptr));
713                break;
714            }
715        break;
716
717        //---------------------------------------------------------------------
718        case IPC_MBOX_TXRX_BEACON_CONFIGURE: {
719            beacon_txrx_config_callback(msg->payload_ptr);
720        }
721        break;
722
723        //---------------------------------------------------------------------
724        case IPC_MBOX_CPU_STATUS: {
725            if(msg->arg0 == (u8)CPU_STATUS_REASON_BOOTED){
726                // If CPU_HIGH just booted, we should re-inform it of our CPU status
727                wlan_mac_low_send_status(CPU_STATUS_REASON_RESPONSE);
728            }
729        }
730        break;
731
732        //---------------------------------------------------------------------
733        case IPC_MBOX_MEM_READ_WRITE: {
734            switch(msg->arg0){
735                case IPC_REG_WRITE_MODE: {
736                    u32    * payload_to_write = (u32*)((u8*)ipc_msg_from_high_payload + sizeof(ipc_reg_read_write_t));
737
738                    // IMPORTANT: this memcpy assumes the payload provided by CPU high is ready as-is
739                    //     Any byte swapping (i.e. for payloads that arrive over Ethernet) *must* be performed
740                    //     before the payload is passed to this function
741                    memcpy((u8*)(((ipc_reg_read_write_t*)ipc_msg_from_high_payload)->baseaddr),
742                           (u8*)payload_to_write,
743                           (sizeof(u32) * ((ipc_reg_read_write_t*)ipc_msg_from_high_payload)->num_words));
744                }
745                break;
746
747                case IPC_REG_READ_MODE: {
748                    /*
749                    xil_printf("\nCPU Low Read:\n");
750                    xil_printf(" Addr: 0x%08x\n", (u32*)((ipc_reg_read_write*)ipc_msg_from_high_payload)->baseaddr);
751                    xil_printf(" N Wrds: %d\n", ((ipc_reg_read_write*)ipc_msg_from_high_payload)->num_words);
752
753                    xil_printf("Mem[0x%08x] = 0x%08x\n",
754                            (u32*)((ipc_reg_read_write*)ipc_msg_from_high_payload)->baseaddr,
755                            Xil_In32((u32*)((ipc_reg_read_write*)ipc_msg_from_high_payload)->baseaddr));
756                     */
757                    ipc_msg_to_high.msg_id            = IPC_MBOX_MSG_ID(IPC_MBOX_MEM_READ_WRITE);
758                    ipc_msg_to_high.num_payload_words = ((ipc_reg_read_write_t*)ipc_msg_from_high_payload)->num_words;
759                    ipc_msg_to_high.payload_ptr       = (u32*)((ipc_reg_read_write_t*)ipc_msg_from_high_payload)->baseaddr;
760
761                    write_mailbox_msg(&ipc_msg_to_high);
762                }
763                break;
764            }
765        }
766        break;
767
768        //---------------------------------------------------------------------
769        case IPC_MBOX_LOW_PARAM: {
770            switch(msg->arg0){
771                case IPC_REG_WRITE_MODE: {
772                    switch(ipc_msg_from_high_payload[0]){
773                        case LOW_PARAM_BB_GAIN: {
774                            if(ipc_msg_from_high_payload[1] <= 3){
775                                radio_controller_setRadioParam(RC_BASEADDR, RC_ALL_RF, RC_PARAMID_TXGAIN_BB, ipc_msg_from_high_payload[1]);
776                            }
777                        }
778                        break;
779
780                        case LOW_PARAM_LINEARITY_PA: {
781                            if(ipc_msg_from_high_payload[1] <= 3){
782                                radio_controller_setRadioParam(RC_BASEADDR, RC_ALL_RF, RC_PARAMID_TXLINEARITY_PADRIVER, ipc_msg_from_high_payload[1]);
783                            }
784                        }
785                        break;
786
787                        case LOW_PARAM_LINEARITY_VGA: {
788                            if(ipc_msg_from_high_payload[1] <= 3){
789                                radio_controller_setRadioParam(RC_BASEADDR, RC_ALL_RF, RC_PARAMID_TXLINEARITY_VGA, ipc_msg_from_high_payload[1]);
790                            }
791                        }
792                        break;
793
794                        case LOW_PARAM_LINEARITY_UPCONV: {
795                            if(ipc_msg_from_high_payload[1] <= 3){
796                                radio_controller_setRadioParam(RC_BASEADDR, RC_ALL_RF, RC_PARAMID_TXLINEARITY_UPCONV, ipc_msg_from_high_payload[1]);
797                            }
798                        }
799                        break;
800
801                        case LOW_PARAM_AD_SCALING: {
802                            ad_spi_write(AD_BASEADDR, AD_ALL_RF, 0x36, (0x1F & ipc_msg_from_high_payload[1]));
803                            ad_spi_write(AD_BASEADDR, AD_ALL_RF, 0x37, (0x1F & ipc_msg_from_high_payload[2]));
804                            ad_spi_write(AD_BASEADDR, AD_ALL_RF, 0x35, (0x1F & ipc_msg_from_high_payload[3]));
805                        }
806                        break;
807
808                        case LOW_PARAM_PKT_DET_MIN_POWER: {
809                            if( ipc_msg_from_high_payload[1]&0xFF000000 ){
810                                wlan_phy_enable_req_both_pkt_det();
811                                //The value sent from wlan_exp will be unsigned with 0 representing PKT_DET_MIN_POWER_MIN
812                                wlan_mac_low_set_pkt_det_min_power((ipc_msg_from_high_payload[1]&0x000000FF) - PKT_DET_MIN_POWER_MIN);
813
814                            } else {
815                                wlan_phy_disable_req_both_pkt_det();
816                            }
817                        }
818                        break;
819
820                        case LOW_PARAM_PHY_SAMPLE_RATE: {
821                            set_phy_samp_rate(ipc_msg_from_high_payload[1]);
822                        }
823                        break;
824
825                        default: {
826                            ipc_low_param_callback(IPC_REG_WRITE_MODE, ipc_msg_from_high_payload);
827                        }
828                        break;
829                    }
830                }
831                break;
832
833                case IPC_REG_READ_MODE: {
834                    // Read Mode is not supported
835                    //
836                    // NOTE:  This is due to the fact that IPC messages in CPU low can take an infinitely long amount of
837                    //     to return given that the sending and receiving of wireless data takes precedent.  Therefore,
838                    //     it is not good to try to return values from CPU low since there is no guarantee when the values
839                    //     will be available.
840                    //
841                    u32      ret_val                  = 0;
842
843                    ipc_msg_to_high.msg_id            = IPC_MBOX_MSG_ID(IPC_MBOX_LOW_PARAM);
844                    ipc_msg_to_high.num_payload_words = 0;
845                    ipc_msg_to_high.payload_ptr       = (u32 *)&ret_val;
846
847                    write_mailbox_msg(&ipc_msg_to_high);
848                }
849                break;
850            }
851        }
852        break;
853
854        //---------------------------------------------------------------------
855        case IPC_MBOX_CONFIG_CHANNEL: {
856            wlan_mac_low_set_radio_channel(ipc_msg_from_high_payload[0]);
857        }
858        break;
859
860        //---------------------------------------------------------------------
861        case IPC_MBOX_LOW_RANDOM_SEED: {
862            srand(ipc_msg_from_high_payload[0]);
863        }
864        break;
865
866        //---------------------------------------------------------------------
867        case IPC_MBOX_CONFIG_TX_CTRL_POW: {
868            mac_param_ctrl_tx_pow = (s8)ipc_msg_from_high_payload[0];
869        }
870        break;
871
872        //---------------------------------------------------------------------
873        case IPC_MBOX_CONFIG_RX_FILTER: {
874            u32    filter_mode_hi = (u32)ipc_msg_from_high_payload[0];
875            u32    filter_mode_lo = 0;
876
877            if((filter_mode_hi & RX_FILTER_FCS_MASK) == RX_FILTER_FCS_NOCHANGE){
878                filter_mode_lo |= (mac_param_rx_filter & RX_FILTER_FCS_MASK);
879            } else {
880                filter_mode_lo |= (filter_mode_hi & RX_FILTER_FCS_MASK);
881            }
882
883            if((filter_mode_hi & RX_FILTER_HDR_NOCHANGE) == RX_FILTER_HDR_NOCHANGE){
884                filter_mode_lo |= (mac_param_rx_filter & RX_FILTER_HDR_NOCHANGE);
885            } else {
886                filter_mode_lo |= (filter_mode_hi & RX_FILTER_HDR_NOCHANGE);
887            }
888
889            mac_param_rx_filter = filter_mode_lo;
890        }
891        break;
892
893        //---------------------------------------------------------------------
894        case IPC_MBOX_CONFIG_RX_ANT_MODE: {
895            wlan_rx_config_ant_mode(ipc_msg_from_high_payload[0]);
896        }
897        break;
898
899        //---------------------------------------------------------------------
900        case IPC_MBOX_CONFIG_DSSS_EN: {
901            if (ipc_msg_from_high_payload[0] == 1) {
902                // xil_printf("Enabling DSSS\n");
903                wlan_mac_low_DSSS_rx_enable();
904            } else {
905                // xil_printf("Disabling DSSS\n");
906                wlan_mac_low_DSSS_rx_disable();
907            }
908        }
909        break;
910
911        //---------------------------------------------------------------------
912        case IPC_MBOX_TX_MPDU_READY: {
913            u8 tx_pkt_buf;
914            tx_pkt_buf = msg->arg0;
915            if(tx_pkt_buf < NUM_TX_PKT_BUFS){
916                // Message is an indication that a Tx Pkt Buf needs processing
917                if(allow_new_mpdu_tx){
918                    wlan_mac_low_proc_pkt_buf( tx_pkt_buf );
919                } else {
920                    pkt_buf_pending_tx = tx_pkt_buf;
921                }
922            }
923        }
924        break;
925    }
926}
927
928
929
930/*****************************************************************************/
931/**
932 * @brief Disable New MPDU Transmissions
933 *
934 * This function will prevent any future MPDU transmission requests from
935 * being accepted.
936 *
937 * @param   None
938 * @return  None
939 *
940 */
941void wlan_mac_low_disable_new_mpdu_tx(){
942    allow_new_mpdu_tx = 0;
943}
944
945
946
947/*****************************************************************************/
948/**
949 * @brief Enable New MPDU Transmissions
950 *
951 * This function will allow future MPDU transmission requests from
952 * being accepted.
953 *
954 * @param   None
955 * @return  None
956 *
957 */
958void wlan_mac_low_enable_new_mpdu_tx(){
959    if(allow_new_mpdu_tx == 0){
960        allow_new_mpdu_tx = 1;
961        if(pkt_buf_pending_tx != -1){
962            wlan_mac_low_proc_pkt_buf(pkt_buf_pending_tx);
963            pkt_buf_pending_tx = -1;
964        }
965    }
966}
967
968
969
970/*****************************************************************************/
971/**
972 * @brief Set the radio channel
973 *
974 * This function will set the radio channel for CPU LOW
975 *
976 * @param   channel     - Radio channel
977 * @return  None
978 *
979 */
980void wlan_mac_low_set_radio_channel(u32 channel){
981
982    mac_param_chan = channel;
983
984    if (wlan_verify_channel(mac_param_chan) == XST_SUCCESS) {
985        if(mac_param_chan <= 14){
986            mac_param_band = RC_24GHZ;
987
988            // Enable DSSS if global variable indicates it should be enabled and PHY sample rate allows it
989            if ((mac_param_dsss_en) && (gl_phy_samp_rate == PHY_20M)) {
990                wlan_phy_DSSS_rx_enable();
991            }
992        } else {
993            mac_param_band = RC_5GHZ;
994
995            // Always disable DSSS when in the 5 GHZ band
996            wlan_phy_DSSS_rx_disable();
997        }
998
999        if(channel >= 36){
1000            // Adjust Tx baseband gain when switching to 5GHz channels; this adjustment makes
1001            //  the actual Tx power set via the Tx VGA more accurate
1002            radio_controller_setRadioParam(RC_BASEADDR, RC_ALL_RF, RC_PARAMID_TXGAIN_BB, 3);
1003        } else {
1004            radio_controller_setRadioParam(RC_BASEADDR, RC_ALL_RF, RC_PARAMID_TXGAIN_BB, 1);
1005        }
1006
1007        radio_controller_setCenterFrequency(RC_BASEADDR, (RC_ALL_RF), mac_param_band, wlan_mac_low_wlan_chan_to_rc_chan(mac_param_chan));
1008        wlan_mac_reset_NAV_counter();
1009
1010    } else {
1011        xil_printf("Invalid channel selection %d\n", mac_param_chan);
1012    }
1013}
1014
1015
1016
1017/*****************************************************************************/
1018/**
1019 * @brief Enable / Disable DSSS RX
1020 *
1021 * DSSS RX must be disabled when in the 5 GHz band or when the PHY sample rate
1022 * is not 20 MSps.  However, the low framework will maintain what the state
1023 * should be when in the 2.4 GHz band and the PHY sample rate is 20 MSps
1024 *
1025 * @param   None
1026 * @return  None
1027 *
1028 */
1029void wlan_mac_low_DSSS_rx_enable() {
1030    mac_param_dsss_en = 1;
1031
1032    // Only enable DSSS if in 2.4 GHz band and phy sample rate is 20
1033    if ((mac_param_band == RC_24GHZ) && (gl_phy_samp_rate == PHY_20M)) {
1034        wlan_phy_DSSS_rx_enable();
1035    }
1036}
1037
1038
1039void wlan_mac_low_DSSS_rx_disable() {
1040    mac_param_dsss_en = 0;
1041    wlan_phy_DSSS_rx_disable();
1042}
1043
1044
1045
1046/*****************************************************************************/
1047/**
1048 * @brief Process a Tx Packet Buffer for Transmission
1049 *
1050 * This function can be called directly via the IPC_MBOX_TX_MPDU_READY message
1051 * or asynchronously if allow_new_mpdu_tx is enabled.
1052 *
1053 * @param   tx_pkt_buf         - u16 packet buffer index
1054 * @return  None
1055 *
1056 */
1057void wlan_mac_low_proc_pkt_buf(u16 tx_pkt_buf){
1058    u32                      status;
1059    tx_frame_info_t        * tx_frame_info;
1060    mac_header_80211       * tx_80211_header;
1061    u32                      is_locked, owner;
1062    u32                      low_tx_details_size;
1063    wlan_ipc_msg_t           ipc_msg_to_high;
1064    ltg_packet_id_t*         pkt_id;
1065
1066    if(tx_pkt_buf >= NUM_TX_PKT_BUFS){
1067        xil_printf("Error: Tx Pkt Buf index exceeds NUM_TX_PKT_BUFS\n");
1068        return;
1069    }
1070
1071    tx_frame_info = (tx_frame_info_t*)TX_PKT_BUF_TO_ADDR(tx_pkt_buf);
1072
1073    switch(tx_frame_info->tx_pkt_buf_state){
1074        // ---- Normal Tx process - buffer contains packet ready for Tx ----
1075        case TX_PKT_BUF_READY:
1076            if(lock_tx_pkt_buf(tx_pkt_buf) != PKT_BUF_MUTEX_SUCCESS){
1077                wlan_printf(PL_ERROR, "Error: unable to lock TX pkt_buf %d\n", tx_pkt_buf);
1078
1079                get_tx_pkt_buf_status(tx_pkt_buf, &is_locked, &owner);
1080
1081                wlan_printf(PL_ERROR, "    TX pkt_buf %d status: isLocked = %d, owner = %d\n", tx_pkt_buf, is_locked, owner);
1082                tx_frame_info->tx_pkt_buf_state = TX_PKT_BUF_HIGH_CTRL;
1083
1084            } else {
1085
1086                tx_frame_info->tx_pkt_buf_state = TX_PKT_BUF_LOW_CTRL;
1087
1088                tx_frame_info->delay_accept = (u32)(get_mac_time_usec() - tx_frame_info->timestamp_create);
1089
1090                // Get pointer to start of MAC header in packet buffer
1091                tx_80211_header = (mac_header_80211*)(TX_PKT_BUF_TO_ADDR(tx_pkt_buf)+PHY_TX_PKT_BUF_MPDU_OFFSET);
1092
1093                // Insert sequence number here
1094                tx_80211_header->sequence_control = ((tx_80211_header->sequence_control) & 0xF) | ( (unique_seq&0xFFF)<<4 );
1095
1096                if((tx_frame_info->flags) & TX_MPDU_FLAGS_FILL_UNIQ_SEQ){
1097                    // Fill unique sequence number into LTG payload
1098                    pkt_id             = (ltg_packet_id_t*)((u8*)tx_80211_header + sizeof(mac_header_80211));
1099                    pkt_id->unique_seq = unique_seq;
1100                }
1101
1102                //Increment the global unique sequence number
1103                unique_seq++;
1104
1105                // Submit the MPDU for transmission - this callback will return only when the MPDU Tx is
1106                //     complete (after all re-transmissions, ACK Rx, timeouts, etc.)
1107                //
1108                // If a frame_tx_callback is not provided, the wlan_null_callback will always
1109                // return 0 (ie TX_MPDU_RESULT_SUCCESS).
1110                //
1111                status = frame_tx_callback(tx_pkt_buf, low_tx_details);
1112
1113                //Record the total time this MPDU spent in the Tx state machine
1114                tx_frame_info->delay_done = (u32)(get_mac_time_usec() - (tx_frame_info->timestamp_create + (u64)(tx_frame_info->delay_accept)));
1115
1116                low_tx_details_size = (tx_frame_info->num_tx_attempts)*sizeof(wlan_mac_low_tx_details_t);
1117
1118                if(status == TX_MPDU_RESULT_SUCCESS){
1119                    tx_frame_info->tx_result = TX_MPDU_RESULT_SUCCESS;
1120                } else {
1121                    tx_frame_info->tx_result = TX_MPDU_RESULT_FAILURE;
1122                }
1123
1124                tx_frame_info->tx_pkt_buf_state = TX_PKT_BUF_DONE;
1125
1126                //Revert the state of the packet buffer and return control to CPU High
1127                if(unlock_tx_pkt_buf(tx_pkt_buf) != PKT_BUF_MUTEX_SUCCESS){
1128                    wlan_printf(PL_ERROR, "Error: unable to unlock TX pkt_buf %d\n", tx_pkt_buf);
1129                    wlan_mac_low_send_exception(WLAN_ERROR_CODE_CPU_LOW_TX_MUTEX);
1130                    tx_frame_info->tx_pkt_buf_state = TX_PKT_BUF_HIGH_CTRL;
1131                } else {
1132                    ipc_msg_to_high.msg_id =  IPC_MBOX_MSG_ID(IPC_MBOX_TX_MPDU_DONE);
1133
1134                    //Add the per-Tx-event details to the IPC message so CPU High can add them to the log as TX_LOW entries
1135                    if(low_tx_details != NULL){
1136                        ipc_msg_to_high.payload_ptr = (u32*)low_tx_details;
1137
1138                        //Make sure we don't overfill the IPC mailbox with TX_LOW data; truncate the Tx details if necessary
1139                        if(low_tx_details_size < (MAILBOX_BUFFER_MAX_NUM_WORDS << 2)){
1140                            ipc_msg_to_high.num_payload_words = ( low_tx_details_size ) >> 2; // # of u32 words
1141                        } else {
1142                            ipc_msg_to_high.num_payload_words = (((MAILBOX_BUFFER_MAX_NUM_WORDS << 2) / sizeof(wlan_mac_low_tx_details_t)) * sizeof(wlan_mac_low_tx_details_t)) >> 2; // # of u32 words
1143                        }
1144                    } else {
1145                        ipc_msg_to_high.num_payload_words = 0;
1146                        ipc_msg_to_high.payload_ptr = NULL;
1147                    }
1148                    ipc_msg_to_high.arg0 = tx_pkt_buf;
1149                    write_mailbox_msg(&ipc_msg_to_high);
1150                }
1151            }
1152        break;
1153        // ---- Something went wrong - TX_READY message didn't match state of pkt buf ----
1154        default:
1155        case TX_PKT_BUF_LOW_CTRL:
1156            // CPU Low responsible for any LOW_CTRL buffers
1157            //  Don't transmit - just clean up and return
1158            tx_frame_info->tx_pkt_buf_state = TX_PKT_BUF_HIGH_CTRL;
1159        case TX_PKT_BUF_UNINITIALIZED:
1160        case TX_PKT_BUF_DONE:
1161        case TX_PKT_BUF_HIGH_CTRL:
1162            //  CPU High will handle it eventually
1163            //  Ensure CPU Low doesn't own lock then return
1164            unlock_tx_pkt_buf(tx_pkt_buf);
1165        break;
1166    }
1167}
1168
1169
1170
1171/*****************************************************************************/
1172/**
1173 * @brief Notify upper-level MAC of frame reception
1174 *
1175 * Sends an IPC message to the upper-level MAC to notify it that a frame has been
1176 * received and is ready to be processed
1177 *
1178 * @param   None
1179 * @return  None
1180 *
1181 * @note This function assumes it is called in the same context where rx_pkt_buf is still valid.
1182 */
1183void wlan_mac_low_frame_ipc_send(){
1184    wlan_ipc_msg_t ipc_msg_to_high;
1185
1186    ipc_msg_to_high.msg_id            = IPC_MBOX_MSG_ID(IPC_MBOX_RX_MPDU_READY);
1187    ipc_msg_to_high.num_payload_words = 0;
1188    ipc_msg_to_high.arg0              = rx_pkt_buf;
1189
1190    write_mailbox_msg(&ipc_msg_to_high);
1191}
1192
1193
1194
1195/*****************************************************************************/
1196/**
1197 * @brief Set Frame Reception Callback
1198 *
1199 * Tells the framework which function should be called when the PHY begins processing a frame reception
1200 *
1201 * @param   callback         - Pointer to callback function
1202 * @return  None
1203 */
1204inline void wlan_mac_low_set_frame_rx_callback(function_ptr_t callback){
1205    frame_rx_callback = callback;
1206}
1207
1208inline void wlan_mac_low_set_sample_rate_change_callback(function_ptr_t callback){
1209    sample_rate_change_callback = callback;
1210}
1211
1212inline void wlan_mac_low_set_beacon_txrx_config_callback(function_ptr_t callback){
1213    beacon_txrx_config_callback = callback;
1214}
1215
1216inline void wlan_mac_low_set_mactime_change_callback(function_ptr_t callback){
1217    mactime_change_callback = callback;
1218}
1219
1220
1221/*****************************************************************************/
1222/**
1223 * @brief Set Frame Transmission Callback
1224 *
1225 * Tells the framework which function should be called when an MPDU is passed down from the
1226 * upper-level MAC for wireless transmission
1227 *
1228 * @param   callback         - Pointer to callback function
1229 * @return  None
1230 */
1231inline void wlan_mac_low_set_frame_tx_callback(function_ptr_t callback){
1232    frame_tx_callback = callback;
1233}
1234
1235
1236
1237/*****************************************************************************/
1238/**
1239 * @brief Set IPC_MBOX_LOW_PARAM Callback
1240 *
1241 * Tells the framework which function should be called when an ipc message is received for
1242 * the IPC_MBOX_LOW_PARAM command.
1243 *
1244 * @param   callback         - Pointer to callback function
1245 * @return  None
1246 */
1247void wlan_mac_low_set_ipc_low_param_callback(function_ptr_t callback){
1248    ipc_low_param_callback = callback;
1249}
1250
1251
1252
1253/*****************************************************************************/
1254/**
1255 * @brief Various Getter Methods
1256 *
1257 * These functions will get parameters from the low framework.
1258 *
1259 * @param   None
1260 * @return  (see individual function)
1261 */
1262inline u32 wlan_mac_low_get_active_channel(){
1263    return mac_param_chan;
1264}
1265
1266
1267inline s8 wlan_mac_low_get_current_ctrl_tx_pow(){
1268    return mac_param_ctrl_tx_pow;
1269}
1270
1271
1272inline u32 wlan_mac_low_get_current_rx_filter(){
1273    return mac_param_rx_filter;
1274}
1275
1276
1277inline phy_samp_rate_t wlan_mac_low_get_phy_samp_rate() {
1278    return gl_phy_samp_rate;
1279}
1280
1281
1282
1283/*****************************************************************************/
1284/**
1285 * @brief Get the Rx Start Microsecond Timestamp
1286 *
1287 * This function returns the Rx start timestamp of the system
1288 *
1289 * @param   None
1290 * @return  u64              - microsecond timestamp
1291 */
1292inline u64 wlan_mac_low_get_rx_start_timestamp() {
1293    u32 timestamp_high_u32;
1294    u32 timestamp_low_u32;
1295    u64 timestamp_u64;
1296
1297    // RX_START timestamp is captured once per reception - no race condition between 32-bit reads
1298    timestamp_high_u32 = Xil_In32(WLAN_MAC_REG_RX_TIMESTAMP_MSB);
1299    timestamp_low_u32 = Xil_In32(WLAN_MAC_REG_RX_TIMESTAMP_LSB);
1300    timestamp_u64 = (((u64)timestamp_high_u32)<<32) + ((u64)timestamp_low_u32);
1301
1302    return timestamp_u64;
1303}
1304
1305
1306
1307/*****************************************************************************/
1308/**
1309 * @brief Get the Tx Start Microsecond Timestamp
1310 *
1311 * This function returns the Tx start timestamp of the system
1312 *
1313 * @param   None
1314 * @return  u64              - microsecond timestamp
1315 */
1316inline u64 wlan_mac_low_get_tx_start_timestamp() {
1317
1318    u32 timestamp_high_u32;
1319    u32 timestamp_low_u32;
1320    u64 timestamp_u64;
1321
1322    // TX_START timestamp is captured once per transmission - no race condition between 32-bit reads
1323    timestamp_high_u32 = Xil_In32(WLAN_MAC_REG_TX_TIMESTAMP_MSB);
1324    timestamp_low_u32 = Xil_In32(WLAN_MAC_REG_TX_TIMESTAMP_LSB);
1325    timestamp_u64 = (((u64)timestamp_high_u32)<<32) + ((u64)timestamp_low_u32);
1326
1327    return timestamp_u64;
1328}
1329
1330
1331
1332/*****************************************************************************/
1333/**
1334 * @brief Various Setter Methods
1335 *
1336 * These functions will set parameters in the low framework.
1337 *
1338 * @param   (see individual function)
1339 * @return  None
1340 */
1341void wlan_mac_low_set_nav_check_addr(u8* addr) {
1342    Xil_Out32(WLAN_MAC_REG_NAV_CHECK_ADDR_1, *((u32*)&(addr[0])) );
1343    Xil_Out32(WLAN_MAC_REG_NAV_CHECK_ADDR_2, *((u32*)&(addr[4])) );
1344}
1345
1346
1347
1348/*****************************************************************************/
1349/**
1350 * @brief Calculates Rx Power (in dBm)
1351 *
1352 * This function calculates receive power for a given band, RSSI and LNA gain. This
1353 * provides a reasonable estimate of Rx power, accurate to a few dB for standard waveforms.
1354 *
1355 * This function does not use the VGA gain setting or I/Q magnitudes. The PHY should use these
1356 * to refine its own power measurement if needed.
1357 *
1358 * NOTE:  These lookup tables were developed as part of the RF characterization.  See:
1359 *     http://warpproject.org/trac/wiki/802.11/Benchmarks/Rx_Char
1360 *
1361 *
1362 * @param   rssi             - RSSI value from RF frontend
1363 * @param   lna_gain         - Value of LNA gain stage in RF frontend
1364 * @return  int              - Power in dBm
1365 */
1366const s8 pow_lookup_B24[128]  = {-90, -90, -89, -88, -88, -87, -87, -86, -86, -85, -84, -84, -83, -83, -82, -82,
1367                                 -81, -81, -80, -79, -79, -78, -78, -77, -77, -76, -75, -75, -74, -74, -73, -73,
1368                                 -72, -72, -71, -70, -70, -69, -69, -68, -68, -67, -66, -66, -65, -65, -64, -64,
1369                                 -63, -63, -62, -61, -61, -60, -60, -59, -59, -58, -58, -57, -56, -56, -55, -55,
1370                                 -54, -54, -53, -52, -52, -51, -51, -50, -50, -49, -49, -48, -47, -47, -46, -46,
1371                                 -45, -45, -44, -43, -43, -42, -42, -41, -41, -40, -40, -39, -38, -38, -37, -37,
1372                                 -36, -36, -35, -34, -34, -33, -33, -32, -32, -31, -31, -30, -29, -29, -28, -28,
1373                                 -27, -27, -26, -26, -25, -24, -24, -23, -23, -22, -22, -21, -20, -20, -19, -19};
1374
1375const s8 pow_lookup_B5[128]   = {-97, -97, -96, -96, -95, -94, -94, -93, -93, -92, -92, -91, -90, -90, -89, -89,
1376                                 -88, -88, -87, -87, -86, -85, -85, -84, -84, -83, -83, -82, -81, -81, -80, -80,
1377                                 -79, -79, -78, -78, -77, -76, -76, -75, -75, -74, -74, -73, -72, -72, -71, -71,
1378                                 -70, -70, -69, -69, -68, -67, -67, -66, -66, -65, -65, -64, -63, -63, -62, -62,
1379                                 -61, -61, -60, -60, -59, -58, -58, -57, -57, -56, -56, -55, -54, -54, -53, -53,
1380                                 -52, -52, -51, -51, -50, -49, -49, -48, -48, -47, -47, -46, -45, -45, -44, -44,
1381                                 -43, -43, -42, -42, -41, -40, -40, -39, -39, -38, -38, -37, -36, -36, -35, -35,
1382                                 -34, -34, -33, -32, -32, -31, -31, -30, -30, -29, -29, -28, -27, -27, -26, -26};
1383
1384
1385inline int wlan_mac_low_calculate_rx_power(u16 rssi, u8 lna_gain){
1386
1387    u8             band;
1388    int            power     = -100;
1389    u16            adj_rssi  = 0;
1390
1391    band = mac_param_band;
1392
1393    if(band == RC_24GHZ){
1394        switch(lna_gain){
1395            case 0:
1396            case 1:
1397                // Low LNA Gain State
1398                adj_rssi = rssi + (440 << PHY_RX_RSSI_SUM_LEN_BITS);
1399            break;
1400
1401            case 2:
1402                // Medium LNA Gain State
1403                adj_rssi = rssi + (220 << PHY_RX_RSSI_SUM_LEN_BITS);
1404            break;
1405
1406            case 3:
1407                // High LNA Gain State
1408                adj_rssi = rssi;
1409            break;
1410        }
1411
1412        power = pow_lookup_B24[(adj_rssi >> (PHY_RX_RSSI_SUM_LEN_BITS+POW_LOOKUP_SHIFT))];
1413
1414    } else if(band == RC_5GHZ){
1415        switch(lna_gain){
1416            case 0:
1417            case 1:
1418                // Low LNA Gain State
1419                adj_rssi = rssi + (540 << PHY_RX_RSSI_SUM_LEN_BITS);
1420            break;
1421
1422            case 2:
1423                // Medium LNA Gain State
1424                adj_rssi = rssi + (280 << PHY_RX_RSSI_SUM_LEN_BITS);
1425            break;
1426
1427            case 3:
1428                // High LNA Gain State
1429                adj_rssi = rssi;
1430            break;
1431        }
1432
1433        power = pow_lookup_B5[(adj_rssi >> (PHY_RX_RSSI_SUM_LEN_BITS+POW_LOOKUP_SHIFT))];
1434    }
1435
1436    return power;
1437}
1438
1439
1440
1441/*****************************************************************************/
1442/**
1443 * @brief Calculates RSSI from Rx power (in dBm)
1444 *
1445 * This function calculates receive power for a given band, RSSI and LNA gain. This
1446 * provides a reasonable estimate of Rx power, accurate to a few dB for standard waveforms.
1447 *
1448 * This function does not use the VGA gain setting or I/Q magnitudes. The PHY should use these
1449 * to refine its own power measurement if needed.
1450 *
1451 * NOTE:  These lookup tables were developed as part of the RF characterization.  See:
1452 *     http://warpproject.org/trac/wiki/802.11/Benchmarks/Rx_Char
1453 *
1454 *
1455 * @param   rx_pow           - Receive power in dBm
1456 * @return  u16              - RSSI value
1457 *
1458 * @note    rx_pow must be in the range [PKT_DET_MIN_POWER_MIN, PKT_DET_MIN_POWER_MAX] inclusive
1459 */
1460const u16 rssi_lookup_B24[61] = {  1,  16,  24,  40,  56,  72,  80,  96, 112, 128, 144, 152, 168, 184, 200, 208,
1461                                 224, 240, 256, 272, 280, 296, 312, 328, 336, 352, 368, 384, 400, 408, 424, 440,
1462                                 456, 472, 480, 496, 512, 528, 536, 552, 568, 584, 600, 608, 624, 640, 656, 664,
1463                                 680, 696, 712, 728, 736, 752, 768, 784, 792, 808, 824, 840, 856};
1464
1465const u16 rssi_lookup_B5[61]  = { 96, 112, 128, 144, 160, 168, 184, 200, 216, 224, 240, 256, 272, 288, 296, 312,
1466                                 328, 344, 352, 368, 384, 400, 416, 424, 440, 456, 472, 480, 496, 512, 528, 544,
1467                                 552, 568, 584, 600, 608, 624, 640, 656, 672, 680, 696, 712, 728, 736, 752, 768,
1468                                 784, 800, 808, 824, 840, 856, 864, 880, 896, 912, 920, 936, 952};
1469
1470
1471int wlan_mac_low_rx_power_to_rssi(s8 rx_pow){
1472    u8 band;
1473    u16 rssi_val = 0;
1474
1475    band = mac_param_band;
1476
1477    if ((rx_pow <= PKT_DET_MIN_POWER_MAX) && (rx_pow >= PKT_DET_MIN_POWER_MIN)) {
1478        if(band == RC_24GHZ){
1479            rssi_val = rssi_lookup_B24[rx_pow-PKT_DET_MIN_POWER_MIN];
1480        } else if(band == RC_5GHZ){
1481            rssi_val = rssi_lookup_B5[rx_pow-PKT_DET_MIN_POWER_MIN];
1482        }
1483
1484        return rssi_val;
1485
1486    } else {
1487        return -1;
1488    }
1489}
1490
1491
1492
1493/*****************************************************************************/
1494/**
1495 * @brief Set the minimum power for packet detection
1496 *
1497 * @param   rx_pow           - Receive power in dBm
1498 * @return  int              - Status:  0 - Success; -1 - Failure
1499 */
1500int wlan_mac_low_set_pkt_det_min_power(s8 rx_pow){
1501    int rssi_val;
1502
1503    rssi_val = wlan_mac_low_rx_power_to_rssi(rx_pow);
1504
1505    if(rssi_val != -1){
1506        wlan_phy_rx_pktDet_RSSI_cfg( (PHY_RX_RSSI_SUM_LEN-1), (rssi_val << PHY_RX_RSSI_SUM_LEN_BITS), 1);
1507
1508        return  0;
1509    } else {
1510        return -1;
1511    }
1512}
1513
1514
1515
1516/*****************************************************************************/
1517/**
1518 * @brief Search for and Lock Empty Packet Buffer (Blocking)
1519 *
1520 * This is a blocking function for finding and locking an empty rx packet buffer. The low framework
1521 * calls this function after passing a new wireless reception up to CPU High for processing. CPU High
1522 * must unlock Rx packet buffers after processing the received packet. This function loops over all Rx
1523 * packet buffers until it finds one that has been unlocked by CPU High.
1524 *
1525 * By design this function prints a message if it fails to unlock the oldest packet buffer. When this
1526 * occurs it indicates that CPU Low has outrun CPU High, a situation that leads to dropped wireless
1527 * receptions with high probability. The node recovers gracefully from this condition and will
1528 * continue processing new Rx events after CPU High catches up. But seeing this message in the UART
1529 * for CPU Low is a strong indicator the CPU High code is not keeping up with wireless receptions.
1530 *
1531 * @param   None
1532 * @return  None
1533 *
1534 * @note    This function assumes it is called in the same context where rx_pkt_buf is still valid.
1535 */
1536inline void wlan_mac_low_lock_empty_rx_pkt_buf(){
1537    // This function blocks until it safely finds a packet buffer for the PHY RX to store a future reception
1538    rx_frame_info_t* rx_frame_info;
1539    u32 i = 1;
1540
1541    while(1) {
1542        //rx_pkt_buf is the global shared by all contexts which deal with wireless Rx
1543        // Rx packet buffers are used in order. Thus incrementing rx_pkt_buf should
1544        // select the "oldest" packet buffer, the one that is most likely to have already
1545        // been processed and released by CPU High
1546        rx_pkt_buf = (rx_pkt_buf+1) % NUM_RX_PKT_BUFS;
1547        rx_frame_info    = (rx_frame_info_t*) RX_PKT_BUF_TO_ADDR(rx_pkt_buf);
1548
1549        if((rx_frame_info->rx_pkt_buf_state) == RX_PKT_BUF_LOW_CTRL){
1550            // By default Rx pkt buffers are not zeroed out, to save the performance penalty of bzero'ing 2KB
1551            //     However zeroing out the pkt buffer can be helpful when debugging Rx MAC/PHY behaviors
1552            // bzero((void *)(RX_PKT_BUF_TO_ADDR(rx_pkt_buf)), 2048);
1553
1554            // Set the OFDM and DSSS PHYs to use the same Rx pkt buffer
1555            wlan_phy_rx_pkt_buf_ofdm(rx_pkt_buf);
1556            wlan_phy_rx_pkt_buf_dsss(rx_pkt_buf);
1557
1558            if (i > 1) { xil_printf("found in %d iterations.\n", i); }
1559
1560            return;
1561
1562        }
1563
1564        if (i == 1) { xil_printf("Searching for empty packet buff ... "); }
1565        i++;
1566    }
1567}
1568
1569
1570/*****************************************************************************/
1571/**
1572 * @brief Finish PHY Reception
1573 *
1574 * This function polls the MAC status register until the Rx PHY goes idle. The
1575 * return value indicates whether the just-completed reception was good
1576 * (no Rx errors and matching checksum) or bad
1577 *
1578 * @param   None
1579 * @return  u32              - FCS status (RX_MPDU_STATE_FCS_GOOD or RX_MPDU_STATE_FCS_BAD)
1580 */
1581inline u32 wlan_mac_hw_rx_finish() {
1582    u32 mac_hw_status;
1583    int i = 0;
1584
1585    // Wait for the packet to finish
1586    do{
1587        mac_hw_status = wlan_mac_get_status();
1588        if(i++>1000000) {xil_printf("Stuck in wlan_mac_hw_rx_finish! 0x%08x\n", mac_hw_status);}
1589    } while(mac_hw_status & WLAN_MAC_STATUS_MASK_RX_PHY_ACTIVE);
1590
1591    // Check RX_END_ERROR and FCS
1592    if( (mac_hw_status & WLAN_MAC_STATUS_MASK_RX_FCS_GOOD) &&
1593       ((mac_hw_status & WLAN_MAC_STATUS_MASK_RX_END_ERROR) == 0)) {
1594        return 1;
1595
1596    } else {
1597        return 0;
1598
1599    }
1600}
1601
1602
1603
1604/*****************************************************************************/
1605/**
1606 * @brief Force reset backoff counter in MAC hardware
1607 */
1608inline void wlan_mac_reset_backoff_counter() {
1609    Xil_Out32(WLAN_MAC_REG_CONTROL, Xil_In32(WLAN_MAC_REG_CONTROL) | WLAN_MAC_CTRL_MASK_RESET_A_BACKOFF);
1610    Xil_Out32(WLAN_MAC_REG_CONTROL, Xil_In32(WLAN_MAC_REG_CONTROL) & ~WLAN_MAC_CTRL_MASK_RESET_A_BACKOFF);
1611}
1612
1613
1614
1615/*****************************************************************************/
1616/**
1617 * @brief Force reset NAV counter in MAC hardware
1618 */
1619inline void wlan_mac_reset_NAV_counter() {
1620    Xil_Out32(WLAN_MAC_REG_CONTROL, Xil_In32(WLAN_MAC_REG_CONTROL) | WLAN_MAC_CTRL_MASK_RESET_NAV);
1621    Xil_Out32(WLAN_MAC_REG_CONTROL, Xil_In32(WLAN_MAC_REG_CONTROL) & ~WLAN_MAC_CTRL_MASK_RESET_NAV);
1622}
1623
1624
1625
1626/*****************************************************************************/
1627/**
1628 * @brief Convert dBm to Tx Gain Target
1629 *
1630 * This function maps a transmit power (in dBm) to a radio gain target.
1631 *
1632 * @param   s8 power         - Power in dBm
1633 * @return  u8 gain_target   - Gain target in range of [0,63]
1634 */
1635inline u8 wlan_mac_low_dbm_to_gain_target(s8 power){
1636    s8 power_railed;
1637    u8 return_value;
1638
1639    if(power > TX_POWER_MAX_DBM){
1640        power_railed = TX_POWER_MAX_DBM;
1641    } else if( power < TX_POWER_MIN_DBM){
1642        power_railed = TX_POWER_MIN_DBM;
1643    } else {
1644        power_railed = power;
1645    }
1646
1647    // This is only save because 'power' is constrained to less than half the dynamic range of an s8 type
1648    return_value = (u8)((power_railed << 1) + 20);
1649
1650    return return_value;
1651}
1652
1653
1654
1655/*****************************************************************************/
1656/**
1657 * @brief Map the WLAN channel frequencies onto the convention used by the radio controller
1658 */
1659inline u32 wlan_mac_low_wlan_chan_to_rc_chan(u32 mac_channel) {
1660    int return_value = 0;
1661
1662    switch(mac_channel){
1663        // 2.4GHz channels
1664        case 1:
1665        case 2:
1666        case 3:
1667        case 4:
1668        case 5:
1669        case 6:
1670        case 7:
1671        case 8:
1672        case 9:
1673        case 10:
1674        case 11:
1675            return_value = mac_channel;
1676        break;
1677        // 5GHz channels
1678        case 36: // 5180MHz
1679            return_value = 1;
1680        break;
1681        case 40: // 5200MHz
1682            return_value = 2;
1683        break;
1684        case 44: // 5220MHz
1685            return_value = 3;
1686        break;
1687        case 48: // 5240MHz
1688            return_value = 4;
1689        break;
1690    }
1691
1692    return return_value;
1693}
1694
1695
1696
1697/*****************************************************************************/
1698/**
1699 * @brief Convert MCS to number of data bits per symbol
1700 */
1701inline u16 wlan_mac_low_mcs_to_n_dbps(u8 mcs, u8 phy_mode) {
1702
1703    if(phy_mode == PHY_MODE_NONHT && mcs < (sizeof(mcs_to_n_dbps_nonht_lut)/sizeof(mcs_to_n_dbps_nonht_lut[0]))) {
1704        return mcs_to_n_dbps_nonht_lut[mcs];
1705    } else if(phy_mode == PHY_MODE_HTMF && mcs < (sizeof(mcs_to_n_dbps_htmf_lut)/sizeof(mcs_to_n_dbps_htmf_lut[0]))) {
1706        return mcs_to_n_dbps_htmf_lut[mcs];
1707    } else {
1708        xil_printf("ERROR (wlan_mac_low_mcs_to_n_dbps): Invalid PHY_MODE (%d) or MCS (%d)\n", phy_mode, mcs);
1709        return 1; // N_DBPS used as denominator, so better not return 0
1710    }
1711}
1712
1713
1714
1715/*****************************************************************************/
1716/**
1717 * @brief Convert MCS to Control Response MCS
1718 */
1719inline u8 wlan_mac_low_mcs_to_ctrl_resp_mcs(u8 mcs, u8 phy_mode){
1720    // Returns the fastest NON-HT half-rate MCS lower than the provided MCS and no larger that 24Mbps.
1721    //  Valid return values are [0, 2, 4]
1722    u8 return_value = 0;
1723
1724    if(phy_mode == PHY_MODE_NONHT){
1725        return_value = mcs;
1726        if(return_value > 4){ return_value = 4; }
1727        if(return_value % 2){ return_value--;   }
1728    } else if(phy_mode == PHY_MODE_HTMF) {
1729        switch(mcs){
1730            default:
1731            case 0:
1732                return_value = 0;
1733            break;
1734            case 1:
1735                return_value = 2;
1736            break;
1737            case 2:
1738                return_value = 2;
1739            break;
1740            case 3:
1741            case 4:
1742            case 5:
1743            case 6:
1744            case 7:
1745                return_value = 4;
1746            break;
1747        }
1748    }
1749    return return_value;
1750}
1751
1752inline u64 wlan_mac_low_get_unique_seq(){
1753    return unique_seq;
1754}
1755
1756inline void wlan_mac_low_set_unique_seq(u64 curr_unique_seq){
1757    unique_seq = curr_unique_seq;
1758}
1759
1760inline void wlan_mac_hw_clear_rx_started() {
1761    wlan_mac_reset_rx_started(1);
1762    wlan_mac_reset_rx_started(0);
1763
1764    return;
1765}
Note: See TracBrowser for help on using the repository browser.