Changes between Version 11 and Version 12 of 802.11/app_notes/FDD-NoMAC


Ignore:
Timestamp:
Feb 15, 2017, 11:16:31 AM (7 years ago)
Author:
chunter
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • 802.11/app_notes/FDD-NoMAC

    v11 v12  
    152152Finally the NoMAC application must be modified to support simultaneous Tx and Rx operations. In the reference code NoMAC implements two callback functions, {{{frame_transmit()}}} and {{{frame_receive()}}}. The lower MAC framework calls these functions to handle new Tx and Rx events. By default these callbacks block during a Tx/Rx event until the corresponding PHY event is complete. In order to support FDD operation these functions must be generalized to not block during PHY events. Instead the callbacks are responsible for starting the Tx/Rx processing and new functions are implemented to finish Tx/Rx processing.
    153153
    154 '''TODO'''
     154Fundamentally, FDD changes NoMAC so that Tx and Rx events no longer occur in complete atomic contexts. The NoMAC code still has to operate serially while the Tx and Rx operations operate in parallels. We will need a few new global variables to help us track whether we are currently transmitting and/or receiving and, if so, which packet buffers are currently being used. Add the following to the top of {{{wlan_mac_nomac.c}}}:
     155
     156{{{#!c
     157typedef enum {TX_STATE_IDLE, TX_STATE_PENDING} tx_state_t;
     158typedef enum {RX_STATE_IDLE, RX_STATE_PENDING} rx_state_t;
     159
     160tx_state_t                                                         tx_state;
     161u8                                                                         pending_tx_pkt_buf;
     162rx_state_t                                                         rx_state;
     163u8                                                                         pending_rx_pkt_buf;
     164}}}
     165
     166Next, we will update the ```frame_transmit()``` function such that it immediately returns after submitting the packet to the MAC Tx Controller rather than wait for the PHY to finish. Replace ```frame_transmit()``` with the following:
     167
     168{{{#!c
     169int frame_transmit(u8 pkt_buf) {
     170    // The pkt_buf, rate, and length arguments provided to this function specifically relate to
     171    // the MPDU that the WLAN MAC LOW framework wants to send.
     172
     173    u8 tx_gain;
     174
     175    tx_state = TX_STATE_PENDING;
     176    pending_tx_pkt_buf = pkt_buf;
     177
     178    tx_frame_info_t   * tx_frame_info       = (tx_frame_info_t*) (TX_PKT_BUF_TO_ADDR(pkt_buf));
     179    u8                  mpdu_tx_ant_mask    = 0;
     180
     181    // Extract waveform params from the tx_frame_info
     182    u8  mcs      = tx_frame_info->params.phy.mcs;
     183    u8  phy_mode = (tx_frame_info->params.phy.phy_mode & (PHY_MODE_HTMF | PHY_MODE_NONHT));
     184    u16 length   = tx_frame_info->length;
     185
     186    // Write the PHY premable (SIGNAL or L-SIG/HT-SIG) to the packet buffer
     187    write_phy_preamble(pkt_buf, phy_mode, mcs, length);
     188
     189    // Set the antenna mode
     190    switch(tx_frame_info->params.phy.antenna_mode) {
     191        case TX_ANTMODE_SISO_ANTA:  mpdu_tx_ant_mask |= 0x1;  break;
     192        case TX_ANTMODE_SISO_ANTB:  mpdu_tx_ant_mask |= 0x2;  break;
     193        case TX_ANTMODE_SISO_ANTC:  mpdu_tx_ant_mask |= 0x4;  break;
     194        case TX_ANTMODE_SISO_ANTD:  mpdu_tx_ant_mask |= 0x8;  break;
     195        default:                    mpdu_tx_ant_mask  = 0x1;  break;      // Default to RF_A
     196    }
     197
     198    // Fill in the number of attempts to transmit the packet
     199    tx_frame_info->num_tx_attempts  = 1;
     200
     201    // Update tx_frame_info with current PHY sampling rate
     202    tx_frame_info->phy_samp_rate        = (u8)wlan_mac_low_get_phy_samp_rate();
     203
     204    // Convert the requested Tx power (dBm) to a Tx gain setting for the radio
     205    tx_gain = wlan_mac_low_dbm_to_gain_target(tx_frame_info->params.phy.power);
     206
     207    // Set the MAC HW control parameters
     208    //  args: (pktBuf, antMask, preTx_backoff_slots, preWait_postRxTimer1, preWait_postTxTimer1, postWait_postTxTimer2, phy_mode)
     209    wlan_mac_tx_ctrl_A_params(pkt_buf, mpdu_tx_ant_mask, 0, 0, 0, 0, phy_mode);
     210
     211    // Set Tx Gains - use same gain for all RF interfaces
     212    wlan_mac_tx_ctrl_A_gains(tx_gain, tx_gain, tx_gain, tx_gain);
     213
     214    // Before we mess with any PHY state, we need to make sure it isn't actively
     215    //  transmitting. For example, it may be sending an ACK when we get to this part of the code
     216    while (wlan_mac_get_status() & WLAN_MAC_STATUS_MASK_TX_PHY_ACTIVE) {}
     217
     218    // Submit the MPDU for transmission - this starts the MAC hardware's MPDU Tx state machine
     219    wlan_mac_tx_ctrl_A_start(1);
     220    wlan_mac_tx_ctrl_A_start(0);
     221
     222    return TX_FRAME_INFO_RESULT_SUCCESS;
     223}
     224}}}
     225
     226Now we need a function that will "finish" the transmission with everything that used to take place after {{{wlan_mac_tx_ctrl_A_start()}}} from NoMAC's original {{{frame_transmit()}}}. This function should poll the status of the transmission and immediately quit if the transmission is still ongoing. Add the following function to {{{wlan_mac_nomac.c}}} and be sure to add a new declaration for it in the header file:
     227
     228{{{#!c
     229void finish_frame_transmit(){
     230        wlan_mac_low_tx_details_t low_tx_details = {0};
     231    u32 mac_tx_ctrl_status;
     232
     233    tx_frame_info_t   * tx_frame_info       = (tx_frame_info_t*) (TX_PKT_BUF_TO_ADDR(pending_tx_pkt_buf));
     234
     235    // Extract waveform params from the tx_frame_info
     236    u8  mcs      = tx_frame_info->params.phy.mcs;
     237    u8  phy_mode = (tx_frame_info->params.phy.phy_mode & (PHY_MODE_HTMF | PHY_MODE_NONHT));
     238
     239    // Get the MAC HW status
     240        mac_tx_ctrl_status = wlan_mac_get_tx_ctrl_status();
     241
     242        if(mac_tx_ctrl_status & WLAN_MAC_TXCTRL_STATUS_MASK_TX_A_DONE){
     243
     244            // Fill in the Tx low details
     245                low_tx_details.phy_params_mpdu.mcs          = mcs;
     246                low_tx_details.phy_params_mpdu.phy_mode     = phy_mode;
     247                low_tx_details.phy_params_mpdu.power        = tx_frame_info->params.phy.power;
     248                low_tx_details.phy_params_mpdu.antenna_mode = tx_frame_info->params.phy.antenna_mode;
     249                low_tx_details.chan_num                     = wlan_mac_low_get_active_channel();
     250                low_tx_details.num_slots                    = 0;
     251                low_tx_details.cw                           = 0;
     252                low_tx_details.attempt_number                           = 1;
     253                low_tx_details.tx_start_timestamp_mpdu = wlan_mac_low_get_tx_start_timestamp();
     254                low_tx_details.tx_start_timestamp_frac_mpdu = wlan_mac_low_get_tx_start_timestamp_frac();
     255                low_tx_details.tx_details_type                          = TX_DETAILS_MPDU;
     256
     257                // Send IPC message containing the details about this low-level transmission
     258                wlan_mac_low_send_low_tx_details(pending_tx_pkt_buf, &low_tx_details);
     259                wlan_mac_low_finish_frame_transmit(pending_tx_pkt_buf);
     260                tx_state = TX_STATE_IDLE;
     261        }
     262}
     263}}}
     264
     265Next, we need to perform a similar dissection of the {{{frame_receive()}}} context to quit early before the reception has finished. Note: it is important to return the value {{{FRAME_RX_RET_SKIP_RX_STARTED_RESET}}} from this context to prevent the MAC Low Framework from resetting the PHY while the reception is still ongoing. Replace {{{frame_receive()}}} with the following:
     266
     267{{{#!c
     268u32 frame_receive(u8 rx_pkt_buf, phy_rx_details_t* phy_details){
     269
     270    void              * pkt_buf_addr        = (void *) RX_PKT_BUF_TO_ADDR(rx_pkt_buf);
     271    rx_frame_info_t   * rx_frame_info       = (rx_frame_info_t *) pkt_buf_addr;
     272
     273    rx_state = RX_STATE_PENDING;
     274    pending_rx_pkt_buf = rx_pkt_buf;
     275
     276    // Fill in the MPDU info fields for the reception. These values are known at RX_START. The other fields below
     277    //  must be written after RX_END
     278    rx_frame_info->flags          = 0;
     279    rx_frame_info->phy_details    = *phy_details;
     280    rx_frame_info->channel        = wlan_mac_low_get_active_channel();
     281    rx_frame_info->phy_samp_rate  = (u8)wlan_mac_low_get_phy_samp_rate();
     282    rx_frame_info->timestamp      = wlan_mac_low_get_rx_start_timestamp();
     283    rx_frame_info->timestamp_frac = wlan_mac_low_get_rx_start_timestamp_frac();
     284
     285    return FRAME_RX_RET_SKIP_RX_STARTED_RESET;
     286}
     287}}}
     288
     289Next, we need to finish the frame reception in another function. Like {{{finish_frame_transmit()}}} from above, this function should immediately quit if the PHY is still receiving a frame. Add the following function to {{{wlan_mac_nomac.c}}} and declare it in NoMAC's header:
     290
     291{{{
     292#!c
     293void finish_frame_receive(){
     294
     295    void              * pkt_buf_addr        = (void *) RX_PKT_BUF_TO_ADDR(pending_rx_pkt_buf);
     296    rx_frame_info_t   * rx_frame_info       = (rx_frame_info_t *) pkt_buf_addr;
     297
     298        u32 mac_hw_status = wlan_mac_get_status();
     299
     300        if(mac_hw_status & (WLAN_MAC_STATUS_MASK_RX_PHY_ACTIVE | WLAN_MAC_STATUS_MASK_RX_PHY_WRITING_PAYLOAD)){
     301                // The PHY is not finished receiving. Jump back to main()
     302                return;
     303        } else {
     304
     305                if(wlan_mac_hw_rx_finish() == 1){
     306                        //FCS was good
     307                        rx_frame_info->flags |= RX_FRAME_INFO_FLAGS_FCS_GOOD;
     308                } else {
     309                        //FCS was bad
     310                        rx_frame_info->flags &= ~RX_FRAME_INFO_FLAGS_FCS_GOOD;
     311                }
     312
     313                // Update the rest of the frame_info fields using post-Rx information
     314                rx_frame_info->ant_mode = wlan_phy_rx_get_active_rx_ant();
     315                rx_frame_info->cfo_est  = wlan_phy_rx_get_cfo_est();
     316                rx_frame_info->rf_gain  = wlan_phy_rx_get_agc_RFG(rx_frame_info->ant_mode);
     317                rx_frame_info->bb_gain  = wlan_phy_rx_get_agc_BBG(rx_frame_info->ant_mode);
     318                rx_frame_info->rx_power = wlan_mac_low_calculate_rx_power(wlan_phy_rx_get_pkt_rssi(rx_frame_info->ant_mode), wlan_phy_rx_get_agc_RFG(rx_frame_info->ant_mode));
     319
     320                // Increment the LEDs based on the FCS status
     321                if(rx_frame_info->flags & RX_FRAME_INFO_FLAGS_FCS_GOOD){
     322                        green_led_index = (green_led_index + 1) % NUM_LEDS;
     323                        userio_write_leds_green(USERIO_BASEADDR, (1 << green_led_index));
     324                } else {
     325                        red_led_index = (red_led_index + 1) % NUM_LEDS;
     326                        userio_write_leds_red(USERIO_BASEADDR, (1 << red_led_index));
     327                }
     328
     329                rx_frame_info->rx_pkt_buf_state = RX_PKT_BUF_READY;
     330                if (unlock_rx_pkt_buf(pending_rx_pkt_buf) != PKT_BUF_MUTEX_SUCCESS) {
     331                        xil_printf("Error: unable to unlock RX pkt_buf %d\n", pending_rx_pkt_buf);
     332                        wlan_mac_low_send_exception(WLAN_ERROR_CODE_CPU_LOW_RX_MUTEX);
     333                } else {
     334
     335                        wlan_mac_low_frame_ipc_send();
     336
     337                        // Find a free packet buffer and begin receiving packets there (blocks until free buf is found)
     338                        wlan_mac_low_lock_empty_rx_pkt_buf();
     339                }
     340
     341                wlan_mac_hw_clear_rx_started(); //FDD-NoMAC
     342                rx_state = RX_STATE_IDLE;
     343        }
     344}
     345}}}
     346
     347Finally, we will call our new functions for finishing Tx or Rx events from the primary while loop in {{{main()}}}. Replace the existing while loop with the following:
     348
     349{{{#!c
     350    while(1){
     351        switch(rx_state){
     352                case RX_STATE_IDLE:
     353                        // Poll PHY RX start
     354                                wlan_mac_low_poll_frame_rx();
     355                break;
     356                case RX_STATE_PENDING:
     357                        finish_frame_receive();
     358                        break;
     359        }
     360
     361        switch(tx_state){
     362                        case TX_STATE_IDLE:
     363                                // Poll IPC rx for a new tx packet
     364                                wlan_mac_low_poll_ipc_rx();
     365                        break;
     366                        case TX_STATE_PENDING:
     367                                //Finish any ongoing transmission
     368                                finish_frame_transmit();
     369                        break;
     370        }
     371    }
     372}}}
     373
     374----
     375
     376=== 4. Evaluation with Experiments Framework ===
    155377
    156378----