#ifndef mac_ca_ca_h #define mac_ca_ca_h /* Cesar project {{{ * * Copyright (C) 2007 Spidcom * * <<>> * * }}} */ /** * \file mac/ca/ca.h * \brief Channel Access public interface. * \ingroup mac_ca */ #include "mac/common/mfs.h" #include "hal/phy/forward.h" #include "mac/common/config.h" #include "mac/common/store.h" /* Forward declaration. */ typedef struct ca_t ca_t; /** Number of schedules in the schedule table. * At a given time, we can store: * - the schedule for the last beacon period which was not released yet; * - the schedule for the current beacon period, created by mixing the * current persistent schedule with the non-persistent one; * - the schedule for the future beacon period using the current persistent * schedule for which we have no non-persistent schedule; * - the persistent preview schedule, also without non-persistent schedule. * * Moreover, to update the schedules without altering the used ones, the upper * layer may need four other schedules. */ #define CA_SCHEDULE_NB 8 /** Schedule maximum size. * One transmitted schedule can have a maximum of 64 allocation entries, but * Channel Access schedules are composed from: * - a persistent schedule, * - a non-persistent schedule, * - optional holes between allocations. * * This is quite space consuming, and most of time, much less entries will be * used... * * Actually, a schedule can not be that big, because of the limited beacon * payload size. The beacon payload is 128 byte long, the session allocation * information (SAI) which generate the much data in our implementation is a * SAI with start time, is 4 byte long, and generate two entries. Therefore, * only 64 entries are needed. */ #define CA_SCHEDULE_SIZE 64 /** Beacon period circular buffer size. * Current schedule can be valid for 8 beacon periods. Preview schedule can * be valid after 7 period. An additional slot is required for the circular * buffer function. */ #define CA_BEACON_PERIOD_NB 16 /** Beacon period entry. */ struct ca_beacon_period_t { /** Beacon period start date. */ u32 start_date; /** Schedule index in Channel Access table. */ uint schedule_index; }; typedef struct ca_beacon_period_t ca_beacon_period_t; /** Channel Access schedule entry. */ struct ca_allocation_t { /** Allocation end date as an offset from the beacon period start. */ u32 end_offset_tck:24; /** GLID of this allocation. * - 0xff: local CSMA allocation, * - 0xfe: shared CSMA allocation, * - 0xfd: discover beacon allocation, * - 0xfc: contention free period initialisation, * - 0xf8-0xfb: reserved by the Homeplug standard, * - 0x80-0xf7: GLID, * - 0x00: defined by this layer: hole, unusable allocation. */ u32 glid:8; }; typedef struct ca_allocation_t ca_allocation_t; /** Channel Access schedule. * It should contains allocations from the persistent schedule, the * non-persistent schedule and also entries for holes. Consecutive shared * CSMA allocations should be merged in one allocation by the upper layer. */ struct ca_schedule_t { /** Coexistence mode for this schedule. */ mac_coexistence_mode_t coexistence_mode; /** EKS/NEK pair to use. */ uint nek_switch; /** Number of used allocations in this schedule. */ uint allocations_nb; /** Table of allocations. */ ca_allocation_t allocations[CA_SCHEDULE_SIZE]; }; typedef struct ca_schedule_t ca_schedule_t; /** Channel Access parameters for next ACCESS event. * This structure is read by PB Processing to prepare its new MPDU. */ struct ca_access_param_t { /** Scheduled MFS borrowed reference or NULL if none. If NULL, only * access_date and cw_start_date are initialised. */ mfs_tx_t *mfs; /** Programmed ACCESS date. Does not include anticipation, but does * include backoff. */ u32 access_date; /** Contention window start date. This is used to compute slot count. */ u32 cw_start_date; /** Beacon period start. Should be used to locate a tonemap. */ uint beacon_period_start_date; /** Available time. */ uint duration_tck; /** Does it occurs during a contention free period? This flag is used to * know if a frame might be transmitted right after this one and we have * to hurry. */ bool cfp:1; /** Use an hybrid frame control? */ bool hybrid:1; }; typedef struct ca_access_param_t ca_access_param_t; /** Allocation parameters for current allocation. * This structure is read by BP Processing to setup RX. */ struct ca_access_alloc_param_t { /** Coexistence mode. */ mac_coexistence_mode_t coexistence_mode; /** Hybrid frame control. */ bool hybrid; /** EKS/NEK pair to use. */ uint nek_switch; }; typedef struct ca_access_alloc_param_t ca_access_alloc_param_t; BEGIN_DECLS /** * Initialise ca and return its context. * \param phy phy context * \param config global mac configuration * \param store MFS and STA store * \return ca context */ ca_t * ca_init (phy_t *phy, mac_config_t *config, mac_store_t *store); /** * Uninitialise a ca context. * \param ctx ca context */ void ca_uninit (ca_t *ctx); /** * Called on activation to find the currently used allocation. * \param ctx ca context * \param date current date * \param anticipation_tck ACCESS event anticipation * \return pointer to internal new allocation parameters */ const ca_access_alloc_param_t * ca_access_activate (ca_t *ctx, u32 date, uint anticipation_tck); /** * Called on deactivation to cancel any programmed access. * \param ctx ca context */ void ca_access_deactivate (ca_t *ctx); /** * Temporary disable any access update until an explicit access * reprogramming is requested. * \param ctx ca context * * This avoid an MFS update to reprogram access if a access change is * following. */ void ca_access_hold (ca_t *ctx); /** * Restart VCS. * \param ctx ca context * \param start_date VCS start date * \param length_tck VCS length * \param anticipation_tck ACCESS event anticipation * \param eifs true if this is an EIFS * * Restart the Virtual Carrier Sense timer for a given length. The ca layer * will use its schedule to find the next transmit opportunity after the VCS * expiration. The hardware will programmed with an anticipation in order to * take extra computation depending on the current state into account. * * If this is an EIFS, the medium is idle after VCS expiration if it lands in * the same allocation. In other cases, this depends of the current * allocation. */ void ca_access_vcs_restart (ca_t *ctx, u32 start_date, uint length_tck, uint anticipation_tck, bool eifs); /** * Program hardware ACCESS timer. * \param ctx ca context * \param date expiration date * \param anticipation_tck ACCESS event anticipation * * Program the hardware ACCESS timer, ignoring VCS. This can be used for * responses or bursts where we know we have the medium access. */ void ca_access_program (ca_t *ctx, u32 date, uint anticipation_tck); /** * Update next ACCESS information for the given grant. * \param ctx ca context * \param mfs granted MFS or NULL for any MFS * \param date grant start date * \param duration_tck grant duration * * Grants are given by CCo with RTS/CTS with immediate grant flag set, or by * bidirectional bursts. * * This function does not program the hardware timer, it only update * information delivered when an ACCESS event occurs. */ void ca_access_grant (ca_t *ctx, mfs_tx_t *mfs, u32 date, uint duration_tck); /** * Defer ACCESS until end of allocation or new segments to send. * \param ctx ca context * \param date current date * \param anticipation_tck ACCESS event anticipation * * This function should be called when no segment can be sent. */ void ca_access_defer (ca_t *ctx, u32 date, uint anticipation_tck); /** * Called at the AIFS start in order to set up access for next allocation. * \param ctx ca context * \return pointer to internal new allocation parameters */ const ca_access_alloc_param_t * ca_access_aifs (ca_t *ctx); /** * Get ACCESS parameters. * \param ctx ca context * \return pointer to internal access parameter structure * * This structure is valid just after the ACCESS event. */ const ca_access_param_t * ca_access_get_param (ca_t *ctx); /** * Update backoff after a deferral. * \param ctx ca context * \param slot_counter hardware slot counter value at the time of deferral * * If a FC is received after an ACCESS in CSMA, we did not get the medium. * This is a backoff deferral. If we lost the PRP, this is not counted as a * backoff deferral because backoff procedure is not entered. * * If a collision is inferred (no acknowledgement), this is also a backoff * deferral. */ void ca_backoff_deferred (ca_t *ctx, int slot_counter); /** * Update backoff after a success. * \param ctx ca context * * Will reset the backoff procedure for the next transmission. This is called * when the MPDU has been sent and no collision is inferred. */ void ca_backoff_success (ca_t *ctx); /** * Cancel a backoff initialisation. * \param ctx ca context * * Called when the backoff parameters were finally not used. */ void ca_backoff_cancel (ca_t *ctx); /** * Register an MFS with the Channel Access, so it can be sent. * \param ctx ca context * \param mfs the MFS to add */ void ca_mfs_add (ca_t *ctx, mfs_tx_t *mfs); /** * Unregister an MFS from the Channel Access, so that it can no longer be * sent. * \param ctx ca context * \param mfs the MFS to remove * \return true if successful * * If unsuccessful, the caller should try later because the MFS is currently * been used for a transmission. */ bool ca_mfs_remove (ca_t *ctx, mfs_tx_t *mfs); /** * Update Channel Access after a MFS update. * \param ctx ca context * \param mfs the updated MFS * * When a MFS is updated, this can change its priority. The Channel Access * layer must update its priority queue and may change the MFS which was * chosen for the next transmission. */ void ca_mfs_update (ca_t *ctx, mfs_tx_t *mfs); /** * Hold any transmission on this MFS until the next beacon period. * \param ctx ca context * \param mfs the MFS to hold */ void ca_mfs_hold (ca_t *ctx, mfs_tx_t *mfs); /** * Retrieve a pointer to a schedule table entry. * \param ctx ca context * \param index schedule index in [0..CA_SCHEDULE_NB) * \return the requested schedule * * This should only be done if the schedule is not currently used. */ ca_schedule_t * ca_alloc_get_schedule (ca_t *ctx, uint index); /** * Update the beacon periods. * \param ctx ca context * \param beacon_periods pointer to the updated beacon periods table * \param beacon_periods_nb number of beacon periods * * To make a smooth update, the currently used beacon periods should not have * been updated (same start time, same schedule index). A non-smooth update * could trigger an extra computation of the next access. */ void ca_alloc_update_beacon_periods (ca_t *ctx, ca_beacon_period_t *beacon_periods, uint beacon_periods_nb); END_DECLS #endif /* mac_ca_ca_h */