- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# /space/home/slher/rel/Beken/v6_4_5/macsw/ip/lmac/src/ps/ps.c

Go to the documentation of this file.

    00001
    00020 /*
    00021  * INCLUDE FILES
    00022  ****************************************************************************************
    00023  */
    00024 #include "ps.h"
    00025 #include "mac_ie.h"
    00026 #include "sta_mgmt.h"
    00027 #include "vif_mgmt.h"
    00028 #include "mm.h"
    00029 #include "co_utils.h"
    00030 #include "co_status.h"
    00031 #include "dbg.h"
    00032 #include "txl_frame.h"
    00033 #include "phy.h"
    00034 #include "tpc.h"
    00035
    00036 #if (NX_DPSM)
    00037 #include "td.h"
    00038 #endif //(NX_DPSM)
    00039
    00040 #if NX_POWERSAVE
    00041
    00042 /*
    00043  * DEFINES
    00044  ****************************************************************************************
    00045  */
    00046
    00048 #define PS_TX_ERROR_MAX      (3)
    00049
    00050 /*
    00051  * GLOBAL VARIABLES
    00052  ****************************************************************************************
    00053  */
    00055 struct ps_env_tag ps_env;
    00056
    00057 /*
    00058  * FUNCTION DEFINITIONS
    00059  ****************************************************************************************
    00060  */
    00072 static uint8_t ps_send_pspoll(struct vif_info_tag *vif)
    00073 {
    00074     struct txl_frame_desc_tag *frame;
    00075     struct mac_hdr_ctrl *buf;
    00076     struct tx_hd *thd;
    00077     struct sta_info_tag *sta = &sta_info_tab[vif->u.sta.ap_id];
    00078     int txtype;
    00079
    00080     // Allocate a frame descriptor from the TX path
    00081     txtype = vif_mgmt_get_txtype(vif);
    00082     frame = txl_frame_get(txtype, MAC_PSPOLL_FRAME_SIZE);
    00083     if (frame == NULL)
    00084         return CO_FAIL;
    00085
    00086     // update Tx power in policy table
    00087     tpc_update_frame_tx_power(vif, frame);
    00088
    00089     // Get the buffer pointer
    00090     buf = txl_buffer_payload_get(&frame->txdesc);
    00091
    00092     // Fill-in the frame
    00093     buf->fctl = MAC_FCTRL_PSPOLL;
    00094     buf->durid = (0x3 << 14) | sta->aid;
    00095     buf->addr1 = sta->mac_addr;
    00096     buf->addr2 = vif->mac_addr;
    00097
    00098     // HW shall not modify the DUR/AID field for a PS-poll
    00099     thd = &frame->txdesc.lmac.hw_desc->thd;
    00100     thd->macctrlinfo2 |= DONT_TOUCH_DUR | TS_VALID_BIT | (MAC_FCTRL_PSPOLL >> 1);
    00101
    00102     #if (NX_CHNL_CTXT || NX_P2P)
    00103     // Set VIF and STA indexes
    00104     frame->txdesc.host.vif_idx = sta->inst_nbr;
    00105     frame->txdesc.host.staid   = sta->staid;
    00106     #endif //(NX_CHNL_CTXT || NX_P2P)
    00107
    00108     // Push the frame for TX
    00109     txl_frame_push(frame, AC_VO);
    00110
    00111     return CO_OK;
    00112 }
    00113
    00130 static bool ps_check_tx_status(struct vif_info_tag *vif, uint32_t status,
    00131                                cfm_func_ptr cfm)
    00132 {
    00133     // Indicate if confirmation can be handled
    00134     bool handle_cfm = true;
    00135
    00136     // Check if an error has occured during the NULL frame transmission
    00137     if (!(status & FRAME_SUCCESSFUL_TX_BIT))
    00138     {
    00139         // Increase number of errors
    00140         vif->u.sta.ps_retry++;
    00141
    00142         // Check if maximum number of retries has been reached
    00143         if (vif->u.sta.ps_retry == PS_TX_ERROR_MAX)
    00144         {
    00145             #if (NX_CONNECTION_MONITOR)
    00146             // Inform the host that the link has been lost
    00147             mm_send_connection_loss_ind(vif);
    00148             #endif //(NX_CONNECTION_MONITOR)
    00149             //#else continue
    00150         }
    00151         else
    00152         {
    00153             // Send a new NULL frame
    00154             txl_frame_send_null_frame(vif->u.sta.ap_id, cfm, vif);
    00155
    00156             // Wait for next confirmation
    00157             handle_cfm = false;
    00158         }
    00159     }
    00160
    00161     return (handle_cfm);
    00162 }
    00163
    00177 static void ps_enable_cfm(void *env, uint32_t status)
    00178 {
    00179     // Check if an error has occurred during the NULL frame transmission
    00180     if (!ps_check_tx_status((struct vif_info_tag *)env, status, ps_enable_cfm))
    00181     {
    00182         return;
    00183     }
    00184
    00185     if (ps_env.cfm_cnt)
    00186     {
    00187         // Decrease the number of expected confirmations
    00188         ps_env.cfm_cnt--;
    00189     }
    00190
    00191     // Check if all confirmations have been received
    00192     if (ps_env.cfm_cnt == 0)
    00193     {
    00194         #if NX_UAPSD
    00195         // Check if UAPSD is in use
    00196         if (ps_env.uapsd_on)
    00197         {
    00198             struct vif_info_tag *vif =
    00199                 (struct vif_info_tag *)co_list_pick(&vif_mgmt_env.used_list);
    00200
    00201             mm_timer_set(&ps_env.uapsd_timer, ke_time() + ps_env.uapsd_timeout);
    00202             ps_env.uapsd_tmr_on = true;
    00203             while (vif != NULL)
    00204             {
    00205                 if ((vif->type == VIF_STA) && vif->active  && vif->u.sta.uapsd_queues)
    00206                     vif->prevent_sleep &= ~PS_VIF_WAITING_EOSP;
    00207
    00208                 // Go to next entry
    00209                 vif = (struct vif_info_tag *)co_list_next(&vif->list_hdr);
    00210             }
    00211         }
    00212         #endif
    00213
    00214         #if (NX_DPSM)
    00215         if (PS_DPSM_STATE_GET(ON) && PS_DPSM_STATE_GET(RESUMING))
    00216         {
    00217             // Resume RESUMING bit
    00218             PS_DPSM_STATE_CLEAR(RESUMING);
    00219             // Clear PAUSE bit
    00220             PS_DPSM_STATE_CLEAR(PAUSE);
    00221             TRACE_STA(PS, "{VIF-%d} PS mode resumed", ((struct vif_info_tag *)env)->index);
    00222         }
    00223         else
    00224         #endif //(NX_DPSM)
    00225         {
    00226             // Set the PS environment variable
    00227             ps_env.ps_on = true;
    00228             TRACE_STA(PS, "{VIF-%d} PS mode enabled", ((struct vif_info_tag *)env)->index);
    00229
    00230             // Send the confirmation
    00231             ke_msg_send_basic(MM_SET_PS_MODE_CFM, ps_env.taskid, TASK_MM);
    00232         }
    00233
    00234         #if (NX_DPSM)
    00235         if (PS_DPSM_STATE_GET(SET_MODE_REQ))
    00236         {
    00237             // Reset SET_MODE_REQ bit
    00238             PS_DPSM_STATE_CLEAR(SET_MODE_REQ);
    00239             // Set PS Mode as required by the application
    00240             ps_set_mode(ps_env.next_mode, ps_env.taskid);
    00241         }
    00242         #endif //(NX_DPSM)
    00243     }
    00244 }
    00245
    00259 static void ps_disable_cfm(void *env, uint32_t status)
    00260 {
    00261     // Check if an error has occurred during the NULL frame transmission
    00262     if (!ps_check_tx_status((struct vif_info_tag *)env, status, ps_disable_cfm))
    00263     {
    00264         return;
    00265     }
    00266
    00267     if (ps_env.cfm_cnt)
    00268     {
    00269         // Decrease the number of expected confirmations
    00270         ps_env.cfm_cnt--;
    00271     }
    00272
    00273     // Check if all confirmations have been received
    00274     if (ps_env.cfm_cnt == 0)
    00275     {
    00276         struct vif_info_tag *vif =
    00277             (struct vif_info_tag *)co_list_pick(&vif_mgmt_env.used_list);
    00278
    00279         #if NX_UAPSD
    00280         // Clear the UAPSD timer
    00281         mm_timer_clear(&ps_env.uapsd_timer);
    00282         ps_env.uapsd_tmr_on = false;
    00283         #endif
    00284
    00285         while (vif != NULL)
    00286         {
    00287             if ((vif->type == VIF_STA) && vif->active)
    00288             {
    00289                 vif->prevent_sleep &= ~(PS_VIF_WAITING_BCMC | PS_VIF_WAITING_UC | PS_VIF_WAITING_EOSP);
    00290             }
    00291
    00292             // Go to next entry
    00293             vif = (struct vif_info_tag *)co_list_next(&vif->list_hdr);
    00294         }
    00295
    00296         #if (NX_DPSM)
    00297         // Check if DPSM is ON and if Pause was requested
    00298         if (PS_DPSM_STATE_GET(ON) && PS_DPSM_STATE_GET(PAUSING))
    00299         {
    00300             // Resume PAUSING bit
    00301             PS_DPSM_STATE_CLEAR(PAUSING);
    00302             // Set PAUSE bit
    00303             PS_DPSM_STATE_SET(PAUSE);
    00304             TRACE_STA(PS, "{VIF-%d} PS mode paused", ((struct vif_info_tag *)env)->index);
    00305         }
    00306         else
    00307         #endif //(NX_DPSM)
    00308         {
    00309             // Set the PS environment variable
    00310             ps_env.ps_on = false;
    00311             TRACE_STA(PS, "{VIF-%d} PS mode disabled", ((struct vif_info_tag *)env)->index);
    00312
    00313             // Send the confirmation
    00314             ke_msg_send_basic(MM_SET_PS_MODE_CFM, ps_env.taskid, TASK_MM);
    00315         }
    00316
    00317         #if (NX_DPSM)
    00318         if (PS_DPSM_STATE_GET(SET_MODE_REQ))
    00319         {
    00320             // Reset SET_MODE_REQ bit
    00321             PS_DPSM_STATE_CLEAR(SET_MODE_REQ);
    00322             // Set PS Mode as required by the application
    00323             ps_set_mode(ps_env.next_mode, ps_env.taskid);
    00324         }
    00325         #endif //(NX_DPSM)
    00326     }
    00327 }
    00328
    00329 #if (NX_DPSM)
    00330
    00340 static void ps_dpsm_update(bool pause)
    00341 {
    00342     // VIF Entry variable used to parse list of created VIFs
    00343     struct vif_info_tag *vif;
    00344     // Function called when sent NULL frame is ACKed by AP
    00345     cfm_func_ptr cfm ;
    00346
    00347     PROF_PS_DPSM_UPDATE_SET();
    00348
    00349     // Request to pause Power Save Mode
    00350     if (pause)
    00351     {
    00352         cfm = ps_disable_cfm;
    00353
    00354         // Keep in mind that pause has been requested
    00355         PS_DPSM_STATE_SET(PAUSING);
    00356
    00357         // Disallow channel switching
    00358         ps_env.prevent_sleep |= PS_PSM_PAUSED;
    00359
    00360         PROF_PS_PAUSE_SET();
    00361     }
    00362     // Request to resume Power Save Mode
    00363     else
    00364     {
    00365         cfm = ps_enable_cfm;
    00366
    00367         // Keep in mind that resume has been requested
    00368         PS_DPSM_STATE_SET(RESUMING);
    00369
    00370         // Allow channel switching
    00371         ps_env.prevent_sleep &= ~PS_PSM_PAUSED;
    00372
    00373         PROF_PS_PAUSE_CLR();
    00374     }
    00375
    00376     // Update macCntrl1Reg.pwrMgt bit
    00377     nxmac_pwr_mgt_setf((uint8_t)(pause == false));
    00378
    00379     // Reset the confirmation counter
    00380     ps_env.cfm_cnt = 0;
    00381
    00382     // Go through the list of STA VIF
    00383     vif = (struct vif_info_tag *)co_list_pick(&vif_mgmt_env.used_list);
    00384
    00385     while (vif)
    00386     {
    00387         if ((vif->type == VIF_STA) && vif->active
    00388             #if (NX_CHNL_CTXT)
    00389             && chan_is_tx_allowed(vif)
    00390             #endif //(NX_CHNL_CTXT)
    00391            )
    00392         {
    00393             // Reset number of retries for this transmission
    00394             vif->u.sta.ps_retry = 0;
    00395             // We expect one more confirmation
    00396             ps_env.cfm_cnt++;
    00397
    00398             // Send a NULL frame to indicate to the AP that we are sleeping
    00399             txl_frame_send_null_frame(vif->u.sta.ap_id, cfm, vif);
    00400         }
    00401
    00402         // Go to next entry
    00403         vif = (struct vif_info_tag *)co_list_next(&vif->list_hdr);
    00404     }
    00405
    00406     // If no NULL frame has been sent, directly call the cfm function
    00407     if (ps_env.cfm_cnt == 0)
    00408     {
    00409         cfm(NULL, FRAME_SUCCESSFUL_TX_BIT);
    00410     }
    00411
    00412     PROF_PS_DPSM_UPDATE_CLR();
    00413 }
    00414 #endif //(NX_DPSM)
    00415
    00416 #if (NX_UAPSD)
    00417
    00426 static void ps_uapsd_timer_handle(void *env)
    00427 {
    00428     bool sta_active = false;
    00429     // Go through the list of STA VIF
    00430     struct vif_info_tag *vif = (struct vif_info_tag *)co_list_pick(&vif_mgmt_env.used_list);
    00431
    00432     while (vif != NULL)
    00433     {
    00434         if ((vif->type == VIF_STA) && vif->active && vif->u.sta.uapsd_queues
    00435             #if NX_CHNL_CTXT
    00436             && chan_is_tx_allowed(vif)
    00437             #endif
    00438            )
    00439         {
    00440             // Send a trigger frame to all APs with which U-APSD is used
    00441             sta_active = true;
    00442
    00443             // Check if we need to send the frame
    00444             if (ke_time_past(vif->u.sta.uapsd_last_rxtx + ps_env.uapsd_timeout/2))
    00445             {
    00446                 #if (NX_P2P)
    00447                 if (vif->p2p && !p2p_is_present(vif->p2p_index))
    00448                 {
    00449                     // If GO is absent no need to send trigger frame, assume that Service
    00450                     // Period has been paused and it will be restarted when GO is present
    00451                     // (cf ps_p2p_absence_update)
    00452                     vif->u.sta.sp_paused = true;
    00453                 }
    00454                 else
    00455                 #endif //(NX_P2P)
    00456                 if (txl_frame_send_qosnull_frame(vif->u.sta.ap_id,
    00457                                                  vif->u.sta.uapsd_tid << MAC_QOSCTRL_UP_OFT,
    00458                                                  NULL, NULL) == CO_OK)
    00459                 {
    00460                     TRACE_STA(PS, "{VIF-%d} start periodic UAPSD Service Period",
    00461                               vif->index);
    00462                     vif->prevent_sleep |= PS_VIF_WAITING_EOSP;
    00463                     vif->u.sta.uapsd_last_rxtx = ke_time();
    00464                 }
    00465             }
    00466         }
    00467
    00468         // Go to next entry
    00469         vif = (struct vif_info_tag *)co_list_next(&vif->list_hdr);
    00470     }
    00471
    00472     // Check if at least one STA is active
    00473     if (sta_active)
    00474     {
    00475         // Restart the UAPSD Timer
    00476         mm_timer_set(&ps_env.uapsd_timer, ke_time() + ps_env.uapsd_timeout);
    00477     }
    00478     else
    00479     {
    00480         // UAPSD timer is not active anymore
    00481         ps_env.uapsd_tmr_on = false;
    00482     }
    00483 }
    00484 #endif //(NX_UAPSD)
    00485
    00486 void ps_init(void)
    00487 {
    00488     // Fully reset the PS environment variable
    00489     memset(&ps_env, 0, sizeof(ps_env));
    00490
    00491     #if (NX_UAPSD)
    00492     // Initialize mm_timer used for UAPSD
    00493     ps_env.uapsd_timer.cb = ps_uapsd_timer_handle;
    00494     #endif //(NX_UAPSD)
    00495 }
    00496
    00497 void ps_set_mode(uint8_t mode, ke_task_id_t taskid)
    00498 {
    00499     struct vif_info_tag *vif;
    00500     cfm_func_ptr cfm;
    00501
    00502     // Save the ID of the requester
    00503     ps_env.taskid = taskid;
    00504
    00505     #if (NX_DPSM)
    00506     // If update has been required internally, wait for end of procedure
    00507     if (PS_DPSM_STATE_GET(ON) && (PS_DPSM_STATE_GET(PAUSING) || PS_DPSM_STATE_GET(RESUMING)))
    00508     {
    00509         // Keep mode in mind
    00510         ps_env.next_mode = mode;
    00511         // Set SET_MODE_REQ bit to 1
    00512         PS_DPSM_STATE_SET(SET_MODE_REQ);
    00513
    00514         return;
    00515     }
    00516     #endif //(NX_DPSM)
    00517
    00518     if (mode == PS_MODE_OFF)
    00519     {
    00520         // Set the confirmation function pointer
    00521         cfm = ps_disable_cfm;
    00522
    00523         #if (NX_DPSM)
    00524         // Clear DPSM state
    00525         ps_env.dpsm_state = 0;
    00526         #endif //(NX_DPSM)
    00527
    00528         // PS mode is disabled, then the macCntrl1Reg.pwrMgt bit must be set to 0,
    00529         // in order to reset the PM bit in Frame Control from now on.
    00530         nxmac_pwr_mgt_setf(0);
    00531     }
    00532     else
    00533     {
    00534         // Set the confirmation function pointer
    00535         cfm = ps_enable_cfm;
    00536
    00537         #if (NX_DPSM)
    00538         // Check if Dynamic Power Save mode is required
    00539         if (mode == PS_MODE_ON_DYN)
    00540         {
    00541             // Set DPSM ON bit
    00542             PS_DPSM_STATE_SET(ON);
    00543         }
    00544         #endif //(NX_DPSM)
    00545
    00546         // PS mode is enabled, then the macCntrl1Reg.pwrMgt bit must be set to 1,
    00547         // all the frames must have their PM bit set to 1 in Frame Control field.
    00548         nxmac_pwr_mgt_setf(1);
    00549     }
    00550
    00551     // Reset the confirmation counter
    00552     ps_env.cfm_cnt = 0;
    00553     #if NX_UAPSD
    00555     ps_env.uapsd_on = false;
    00556     #endif
    00557
    00558     // Go through the list of STA VIF
    00559     vif = (struct vif_info_tag *)co_list_pick(&vif_mgmt_env.used_list);
    00560
    00561     while (vif != NULL)
    00562     {
    00563         if ((vif->type == VIF_STA) && vif->active
    00564             #if NX_CHNL_CTXT
    00565             && chan_is_tx_allowed(vif)
    00566             #endif
    00567             )
    00568         {
    00569             // Reset number of retries for this transmission
    00570             vif->u.sta.ps_retry = 0;
    00571             // We expect one more confirmation
    00572             ps_env.cfm_cnt++;
    00573
    00574             #if NX_UAPSD
    00575             // Check if UAPSD is enabled for this interface
    00576             if (vif->u.sta.uapsd_queues)
    00577                 ps_env.uapsd_on = true;
    00578             #endif
    00579
    00580             // Send a NULL frame to indicate to the AP that we are sleeping
    00581             txl_frame_send_null_frame(vif->u.sta.ap_id, cfm, vif);
    00582         }
    00583
    00584         // Go to next entry
    00585         vif = (struct vif_info_tag *)co_list_next(&vif->list_hdr);
    00586     }
    00587
    00588     // Check if are waiting for some confirmations before updating our state
    00589     if (ps_env.cfm_cnt == 0)
    00590     {
    00591         // Call confirmation function
    00592         cfm(NULL, FRAME_SUCCESSFUL_TX_BIT);
    00593     }
    00594 }
    00595
    00607 #if (!RW_MESH_EN)
    00608 __INLINE
    00609 #endif //(!RW_MESH_EN)
    00610 bool ps_check_tim(uint32_t a_tim, uint16_t aid)
    00611 {
    00612     // Value used to read the TIM element
    00613     uint8_t mask;
    00614     unsigned int n, n1, n2;
    00615
    00616     // Now we check if some unicast traffic is buffered
    00617     // Compute the byte index of this AID
    00618     n = aid / 8;
    00619
    00620     // Compute the bit corresponding to this AID inside the byte
    00621     mask = CO_BIT(aid & 0x7);
    00622
    00623     // Now we need to compute the start and end byte indexes present in the TIM
    00624     n1 = co_read8p(a_tim + MAC_TIM_BMPC_OFT) & 0xFE;
    00625     n2 = co_read8p(a_tim + MAC_TIM_LEN_OFT) + n1 - 4;
    00626
    00627     // First check if the AID byte is present in the bitmap
    00628     if ((n < n1) || (n > n2))
    00629     {
    00630         return false;
    00631     }
    00632
    00633     // Byte is present, now computes its offset in the bitmap array
    00634     n -= n1;
    00635
    00636     if (co_read8p(a_tim + MAC_TIM_BMP_OFT + n) & mask)
    00637     {
    00638         return true;
    00639     }
    00640
    00641     return false;
    00642 }
    00643
    00644 void ps_check_beacon(uint32_t tim, uint16_t len, struct vif_info_tag *vif)
    00645 {
    00646     uint16_t aid = sta_info_tab[vif->u.sta.ap_id].aid;
    00647
    00648     // Beacon was received
    00649     vif->prevent_sleep &= ~PS_VIF_WAITING_BCN;
    00650
    00651     // Check if we are in PS mode
    00652     if (!ps_env.ps_on)
    00653         return;
    00654
    00655     #if (NX_DPSM)
    00656     if (PS_DPSM_STATE_GET(PAUSE))
    00657         return;
    00658     #endif //(NX_DPSM)
    00659
    00660     // Check if TIM is present
    00661     if (tim == 0)
    00662         return;
    00663
    00664     PROF_PS_CHECK_BCN_SET();
    00665
    00666     // First check if there is some BC/MC traffic buffered by the AP
    00667     if (!vif->u.sta.dont_wait_bcmc)
    00668     {
    00669         int bcmc_octet = vif->u.sta.bssid_index / 8;
    00670         int bcmc_bit = vif->u.sta.bssid_index % 8;
    00671         if (co_read8p(tim + MAC_TIM_BMPC_OFT + bcmc_octet) & CO_BIT(bcmc_bit))
    00672         {
    00673             vif->prevent_sleep |= PS_VIF_WAITING_BCMC;
    00674             TRACE_STA(PS, "{VIF-%d} AP has BroadCast/Multicast traffic buffered",
    00675                       vif->index);
    00676         }
    00677         else
    00678             vif->prevent_sleep &= ~PS_VIF_WAITING_BCMC;
    00679     }
    00680
    00681     // Check if unicast traffic is present
    00682     if (ps_check_tim(tim, aid))
    00683     {
    00684         TRACE_STA(PS, "{VIF-%d} AP has traffic buffered for us", vif->index);
    00685
    00686         #if NX_UAPSD
    00687         if ((vif->u.sta.uapsd_queues & PS_ALL_UAPSD_ACS) == PS_ALL_UAPSD_ACS)
    00688         {
    00689             // All ACs are uapsd-enabled: send a QoS Null on a VO TID
    00690             if (txl_frame_send_qosnull_frame(vif->u.sta.ap_id,
    00691                                              TID_7 << MAC_QOSCTRL_UP_OFT,
    00692                                              NULL, NULL) == CO_OK)
    00693             {
    00694                 vif->prevent_sleep |= PS_VIF_WAITING_EOSP;
    00695                 TRACE_STA(PS, "Start UAPSD Service Period");
    00696             }
    00697         }
    00698         else
    00699         #endif
    00700         {
    00701             // Since some ACs are not uapsd-enabled the TIM only refers to the
    00702             // ACs configured to use 802.11 Legacy power save mode
    00703             if (ps_send_pspoll(vif) == CO_OK)
    00704             {
    00705                 vif->prevent_sleep |= PS_VIF_WAITING_UC;
    00706                 TRACE_STA(PS, "Send PS-POLL");
    00707             }
    00708         }
    00709     }
    00710     else
    00711     {
    00712         #if NX_UAPSD
    00713         if ((vif->u.sta.uapsd_queues & PS_ALL_UAPSD_ACS) == PS_ALL_UAPSD_ACS)
    00714         {
    00715             vif->prevent_sleep &= ~PS_VIF_WAITING_EOSP;
    00716         }
    00717         else
    00718         #endif
    00719             vif->prevent_sleep &= ~PS_VIF_WAITING_UC;
    00720     }
    00721
    00722     PROF_PS_CHECK_BCN_CLR();
    00723 }
    00724
    00725 void ps_check_frame(uint8_t *frame, uint32_t statinfo, struct vif_info_tag *vif)
    00726 {
    00727     struct mac_hdr *machdr = (struct mac_hdr *)frame;
    00728     uint16_t framectrl = machdr->fctl;
    00729
    00730     // Check if we are in PS mode
    00731     if (!ps_env.ps_on)
    00732         return;
    00733
    00734     // Check if the frame is individually or group addressed
    00735     if (MAC_ADDR_GROUP(&machdr->addr1))
    00736     {
    00737         // Check if other group frames will follow this one
    00738         if (!(framectrl & MAC_FCTRL_MOREDATA) || vif->u.sta.dont_wait_bcmc)
    00739             // No more group frames, allow going back to sleep
    00740             vif->prevent_sleep &= ~PS_VIF_WAITING_BCMC;
    00741     }
    00742     else
    00743     {
    00744         #if (NX_UAPSD)
    00745         bool uapsd_frame = false;
    00746         #endif
    00747
    00748         // Unicast frame - Ensure that the frame is for us
    00749         if (statinfo & RX_HD_ADDRMIS)
    00750             return;
    00751
    00752         PROF_PS_CHECK_RX_SET();
    00753
    00754         #if (NX_UAPSD)
    00755         if (ps_env.uapsd_on)
    00756         {
    00757             // Check if it is a QoS-data frame
    00758             if ((framectrl & MAC_FCTRL_QOS_DATA) == MAC_FCTRL_QOS_DATA)
    00759             {
    00760                 uint16_t qos;
    00761                 uint8_t tid;
    00762
    00763                 // Compute the QoS control field offset in the frame
    00764                 if ((framectrl & MAC_FCTRL_TODS_FROMDS) == MAC_FCTRL_TODS_FROMDS)
    00765                 {
    00766                     struct mac_hdr_long_qos *hdr = (struct mac_hdr_long_qos *)machdr;
    00767                     qos = hdr->qos;
    00768                 }
    00769                 else
    00770                 {
    00771                     struct mac_hdr_qos *hdr = (struct mac_hdr_qos *)machdr;
    00772                     qos = hdr->qos;
    00773                 }
    00774
    00775                 // Get the QoS control field in the frame and the TID
    00776                 tid = (qos & MAC_QOSCTRL_UP_MSK) >> MAC_QOSCTRL_UP_OFT;
    00777
    00778                 // Check if UAPSD is enabled for this TID
    00779                 if (vif->u.sta.uapsd_queues & CO_BIT(mac_tid2ac[tid]))
    00780                 {
    00781                     // Frame is serviced in a UAPSD service period
    00782                     uapsd_frame = true;
    00783
    00784                     // Save the time of this reception
    00785                     vif->u.sta.uapsd_last_rxtx = ke_time();
    00786
    00787                     // UAPSD is enabled for this TID, check if EOSP is set
    00788                     if (qos & MAC_QOSCTRL_EOSP)
    00789                     {
    00790                         // End of service period, we can go to sleep again
    00791                         vif->prevent_sleep &= ~PS_VIF_WAITING_EOSP;
    00792                         TRACE_STA(PS, "{VIF-%d} EOSP received", vif->index);
    00793                     }
    00794                 }
    00795             }
    00796             else if ((framectrl & MAC_FCTRL_TYPE_MASK) == MAC_FCTRL_MGT_T)
    00797             {
    00798                 // Management frames are supposed to be sent in AC_VO,
    00799                 // so if VO is UAPSD enabled, we consider them as
    00800                 // UAPSD frames
    00801                 if (vif->u.sta.uapsd_queues & CO_BIT(AC_VO))
    00802                 {
    00803                     // Frame is serviced in a UAPSD service period
    00804                     uapsd_frame = true;
    00805
    00806                     // Save the time of this reception
    00807                     vif->u.sta.uapsd_last_rxtx = ke_time();
    00808                 }
    00809             }
    00810         }
    00811
    00812         // Check the more data bit (except if we received the frame in
    00813         // a UAPSD service period, as in that case we rely on the EOSP
    00814         // to wait or not for new frames)
    00815         if (!uapsd_frame)
    00816         #endif //(NX_UAPSD)
    00817         {
    00818             #if (NX_DPSM)
    00819             // Update Traffic Detection statistics for PS
    00820             td_pck_ps_ind(vif->index, true);
    00821             #endif //(NX_DPSM)
    00822
    00823             TRACE_STA(PS, "{VIF-%d} received PS frame. (more data = %d)",
    00824                       vif->index, (framectrl & MAC_FCTRL_MOREDATA));
    00825
    00826             if (framectrl & MAC_FCTRL_MOREDATA)
    00827             {
    00828                 #if (NX_DPSM)
    00829                 if (!PS_DPSM_STATE_GET(PAUSE))
    00830                 #endif //(NX_DPSM)
    00831                 {
    00832                     if (ps_send_pspoll(vif) != CO_OK)
    00833                     {
    00834                         // Allow going back to sleep
    00835                         vif->prevent_sleep &= ~PS_VIF_WAITING_UC;
    00836                     }
    00837                 }
    00838             }
    00839             else
    00840             {
    00841                 // Allow going back to sleep
    00842                 vif->prevent_sleep &= ~PS_VIF_WAITING_UC;
    00843             }
    00844         }
    00845
    00846         PROF_PS_CHECK_RX_CLR();
    00847     }
    00848 }
    00849
    00850 #if (NX_UAPSD || NX_DPSM)
    00851 bool ps_check_tx_frame(uint8_t staid, uint8_t tid)
    00852 {
    00853     struct sta_info_tag *sta;
    00854     struct vif_info_tag *vif;
    00855     bool is_trigger = false;
    00856     #if (NX_DPSM)
    00857     bool skip_stat = false;
    00858     #endif
    00859
    00860     // Check if we are in PS mode
    00861     if (!ps_env.ps_on)
    00862         return false;
    00863
    00864     // Check if destination STA is known
    00865     if (staid == 0xFF)
    00866         return false;
    00867
    00868     // Check if TID is valid (indicating that the frame is QoS frame)
    00869     if (tid == 0xFF)
    00870         return false;
    00871
    00872     // Retrieve the associated VIF entry
    00873     sta = &sta_info_tab[staid];
    00874     vif = &vif_info_tab[sta->inst_nbr];
    00875
    00876     // Check if the frame is individually or group addressed
    00877     if ((vif->type != VIF_STA) || !vif->active)
    00878         return false;
    00879
    00880     PROF_PS_CHECK_TX_SET();
    00881
    00882     #if (NX_UAPSD)
    00883     // Check if UAPSD is enabled for this TID
    00884     if (vif->u.sta.uapsd_queues & CO_BIT(mac_tid2ac[tid]))
    00885     {
    00886         // UAPSD is enabled for this TID, we will have to wait for the EOSP
    00887         vif->prevent_sleep |= PS_VIF_WAITING_EOSP;
    00888         is_trigger = true;
    00889
    00890         // Save the time of this transmission
    00891         vif->u.sta.uapsd_last_rxtx = ke_time();
    00892
    00893         #if NX_DPSM
    00894         // When all the queues are UAPSD enabled, we don't want to increase PS
    00895         // traffic statistics in order not to active DPSM for the UAPSD traffic.
    00896         if ((vif->u.sta.uapsd_queues & PS_ALL_UAPSD_ACS) != PS_ALL_UAPSD_ACS)
    00897             skip_stat = true;
    00898         #endif
    00899     }
    00900     #endif //(NX_UAPSD)
    00901
    00902     #if (NX_DPSM)
    00903     if (!skip_stat)
    00904         // Update Traffic Detection statistics for PS
    00905         td_pck_ps_ind(vif->index, false);
    00906     #endif //(NX_DPSM)
    00907
    00908     PROF_PS_CHECK_TX_CLR();
    00909     return is_trigger;
    00910 }
    00911 #endif //(NX_UAPSD || NX_DPSM)
    00912
    00913 #if (NX_UAPSD)
    00914 void ps_uapsd_set(struct vif_info_tag *vif, uint8_t hw_queue, bool uapsd)
    00915 {
    00916     if (uapsd)
    00917     {
    00918         // Set the corresponding bit in the VIF parameters
    00919         vif->u.sta.uapsd_queues |= CO_BIT(hw_queue);
    00920
    00921         // Check if U-APSD timer is already enabled
    00922         if (ps_env.ps_on && !ps_env.uapsd_tmr_on)
    00923         {
    00924             // UAPSD is used
    00925             ps_env.uapsd_on = true;
    00926
    00927             mm_timer_set(&ps_env.uapsd_timer, ke_time() + ps_env.uapsd_timeout);
    00928             ps_env.uapsd_tmr_on = true;
    00929         }
    00930     }
    00931     else
    00932     {
    00933         vif->u.sta.uapsd_queues &= ~CO_BIT(hw_queue);
    00934     }
    00935
    00936     // Get the TID to be used for the trigger frame transmission
    00937     if (vif->u.sta.uapsd_queues)
    00938     {
    00939         uint8_t ac2tid[AC_MAX] = {TID_2, TID_0, TID_5, TID_7};
    00940         uint8_t ac_highest = 31 - co_clz(vif->u.sta.uapsd_queues);
    00941         vif->u.sta.uapsd_tid = ac2tid[ac_highest];
    00942     }
    00943 }
    00944 #endif //(NX_UAPSD)
    00945
    00946 #if (NX_DPSM)
    00947 void ps_traffic_status_update(uint8_t vif_index, uint8_t new_status)
    00948 {
    00949     // VIF Information
    00950     struct vif_info_tag *vif;
    00951     // Indicate if some traffic has been detected on one VIF
    00952     bool has_traffic = (new_status != 0);
    00953     // Indicate if PS is currently paused or not
    00954     bool is_ps_paused;
    00955
    00956     // Verify that PS and DPSM module is ON
    00957     if (!ps_env.ps_on || !PS_DPSM_STATE_GET(ON))
    00958         return;
    00959
    00960     // Verify that DPSM is not a transition state
    00961     if (PS_DPSM_STATE_GET(PAUSING) || PS_DPSM_STATE_GET(RESUMING))
    00962         return;
    00963
    00964     if (!has_traffic)
    00965     {
    00966         // Go through the list of used VIFs in order to know if there is another VIF with traffic
    00967         vif = (struct vif_info_tag *)co_list_pick(&vif_mgmt_env.used_list);
    00968
    00969         while (vif)
    00970         {
    00971             // Skip provided VIF
    00972             if (vif->index != vif_index)
    00973             {
    00974                 // Consider only active STA VIFs
    00975                 if (vif->active && (vif->type == VIF_STA))
    00976                 {
    00977                     if (td_get_ps_status(vif->index))
    00978                     {
    00979                         has_traffic = true;
    00980                         break;
    00981                     }
    00982                 }
    00983             }
    00984
    00985             // Get next VIF
    00986             vif = (struct vif_info_tag *)co_list_next(&vif->list_hdr);
    00987         };
    00988     }
    00989
    00990     // Check current DPSM state
    00991     is_ps_paused = PS_DPSM_STATE_GET(PAUSE);
    00992
    00993     // Based on traffic detection status and current DPSM state, pause or not PS mode
    00994     if (has_traffic)
    00995     {
    00996         // Traffic has been detected, pause PS mode if not already done
    00997         if (!is_ps_paused)
    00998         {
    00999             ps_dpsm_update(true);
    01000         }
    01001     }
    01002     else
    01003     {
    01004         // No traffic has been detected, go back to PSM if not already done
    01005         if (is_ps_paused)
    01006         {
    01007             ps_dpsm_update(false);
    01008         }
    01009     }
    01010 }
    01011 #endif //(NX_DPSM)
    01012
    01013 #if (NX_P2P && NX_UAPSD)
    01014 void ps_p2p_absence_update(struct vif_info_tag *vif, bool absent)
    01015 {
    01016     if (!vif->active)
    01017         return;
    01018
    01019     if (vif->type == VIF_STA)
    01020     {
    01021         if (absent)
    01022         {
    01023             if (vif->prevent_sleep & PS_VIF_WAITING_EOSP)
    01024             {
    01025                 // Pause UAPSD service period
    01026                 vif->u.sta.sp_paused = true;
    01027                 vif->prevent_sleep &= ~PS_VIF_WAITING_EOSP;
    01028             }
    01029         }
    01030         else
    01031         {
    01032             // When a Service Period is interrupted by a NoA, the CLI should
    01033             // retriggers the GO when the absence period is over.
    01034             if (vif->u.sta.sp_paused)
    01035             {
    01036                 // Restart UAPSD service period
    01037                 vif->u.sta.sp_paused = false;
    01038                 if (txl_frame_send_qosnull_frame(vif->u.sta.ap_id,
    01039                                                  vif->u.sta.uapsd_tid << MAC_QOSCTRL_UP_OFT,
    01040                                                  NULL, NULL) == CO_OK)
    01041                 {
    01042                     vif->prevent_sleep |= PS_VIF_WAITING_EOSP;
    01043                     vif->u.sta.uapsd_last_rxtx = ke_time();
    01044                 }
    01045             }
    01046         }
    01047     }
    01048     #if NX_UMAC_PRESENT && NX_P2P_GO
    01049     else if ((vif->type == VIF_AP) && absent)
    01050     {
    01051         // On going service period must be stopped when NOA starts
    01052         struct sta_info_tag *sta = (struct sta_info_tag *)co_list_pick(&vif->sta_list);
    01053
    01054         while (sta != NULL)
    01055         {
    01056             if (sta->ps_service_period & UAPSD_SERVICE_PERIOD)
    01057             {
    01058                 if (sta->ps_service_period & UAPSD_SERVICE_PERIOD_HOST)
    01059                     mm_traffic_req_ind(sta->staid, PS_SP_INTERRUPTED, true);
    01060                 sta->ps_service_period = NO_SERVICE_PERIOD;
    01061             }
    01062             sta = (struct sta_info_tag *)sta->list_hdr.next;
    01063         }
    01064     }
    01065     #endif // NX_P2P_GO
    01066 }
    01067 #endif //(NX_P2P && NX_UAPSD)
    01068
    01069 #if (NX_UAPSD && NX_UMAC_PRESENT)
    01070 void ps_check_tx_trigger_sent(struct hostdesc *hostdesc, uint32_t tx_status)
    01071 {
    01072     struct vif_info_tag *vif;
    01073
    01074     if (!(hostdesc->flags & TXU_CNTRL_UASPD_TRIGGER) ||
    01075         !(tx_status & FRAME_SUCCESSFUL_TX_BIT))
    01076         return;
    01077
    01078     vif = &vif_info_tab[hostdesc->vif_idx];
    01079     vif->prevent_sleep |= PS_VIF_WAITING_EOSP;
    01080 }
    01081
    01082 #endif //(NX_UAPSD && NX_UMAC_PRESENT)
    01083
    01084 #endif
    01085