summaryrefslogtreecommitdiff
path: root/mac/ca/src/access.c
diff options
context:
space:
mode:
Diffstat (limited to 'mac/ca/src/access.c')
-rw-r--r--mac/ca/src/access.c218
1 files changed, 218 insertions, 0 deletions
diff --git a/mac/ca/src/access.c b/mac/ca/src/access.c
new file mode 100644
index 0000000000..1cd69508dc
--- /dev/null
+++ b/mac/ca/src/access.c
@@ -0,0 +1,218 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file mac/ca/src/access.c
+ * \brief ACCESS event and VCS related functions.
+ * \ingroup mac_ca
+ */
+#include "common/std.h"
+
+#include "mac/common/timings.h"
+#include "mac/ca/ca.h"
+
+#include "hal/phy/phy.h"
+
+#include "mac/ca/inc/context.h"
+#include "mac/ca/inc/alloc.h"
+
+/**
+ * Choose a MFS TX for the given GLID.
+ * \param ctx ca context
+ * \param glid global link identifier
+ * \return MFS or NULL if none match
+ */
+static mfs_tx_t *
+ca_access_choose_mfs_tx (ca_t *ctx, uint glid);
+
+void
+ca_access_vcs_restart (ca_t *ctx, u32 start_date, uint length_tck,
+ uint anticipation_tck, bool eifs)
+{
+ uint bp_i, bp_end_i, alloc_i;
+ const ca_beacon_period_t *bp;
+ const ca_schedule_t *sched;
+ u32 vcs_end_date;
+ uint glid;
+ bool idle, cfp, hybrid;
+ uint minimum_length;
+ bool new_backoff_drawn;
+ mfs_tx_t *mfs;
+ dbg_assert (ctx);
+ dbg_assert (length_tck > 0);
+ /* Find the beacon period of the start date, will search for TX
+ * opportunities in two beacon periods. */
+ vcs_end_date = start_date + length_tck;
+ bp_i = ca_alloc_find_beacon_period (ctx, start_date);
+ if (bp_i != ctx->beacon_periods_tail)
+ {
+ /* Beacon period found. */
+ bp = &ctx->beacon_periods[bp_i];
+ sched = &ctx->schedules[bp->schedule_index];
+ /* Find the allocation of the start date. */
+ alloc_i = ca_alloc_find (sched, start_date - bp->start_date);
+ idle = eifs;
+ }
+ else
+ {
+ /* Beacon period not found, use first one. */
+ bp_i = ctx->beacon_periods_head;
+ dbg_assert (bp_i != ctx->beacon_periods_tail);
+ bp = &ctx->beacon_periods[bp_i];
+ sched = &ctx->schedules[bp->schedule_index];
+ alloc_i = 0;
+ vcs_end_date = bp->start_date;
+ idle = false;
+ }
+ /* Find a suitable allocation in this beacon period or the next one. */
+ bp_end_i = CA_ALLOC_NEXT_BEACON_PERIOD (bp_i);
+ if (bp_end_i != ctx->beacon_periods_tail)
+ bp_end_i = CA_ALLOC_NEXT_BEACON_PERIOD (bp_i);
+ new_backoff_drawn = false;
+ do
+ {
+ /* Test if this allocation can be used. */
+ if (alloc_i < sched->allocations_nb
+ && sched->allocations[alloc_i].glid != MAC_LID_SPC_HOLE
+ && less_mod2p32 (vcs_end_date, bp->start_date
+ + sched->allocations[alloc_i].end_offset_tck))
+ {
+ glid = sched->allocations[alloc_i].glid;
+ mfs = ca_access_choose_mfs_tx (ctx, glid);
+ if (mfs)
+ {
+ /* TODO: test if it have pb to send. */
+ cfp = !CA_ALLOC_IS_CSMA (glid);
+ hybrid = CA_ALLOC_IS_HYBRID (ctx->config->coexistence_mode,
+ glid);
+ /* TODO: with ACK, depends of the RIFS. */
+ /* TODO: need special handling for beacons. */
+ minimum_length = MAC_PREAMBLE_TCK
+ + (hybrid ? MAC_FC_10_TCK : 0)
+ + MAC_FC_AV_TCK * ctx->config->fc_symbols_nb
+ + MAC_DX567_TCK + MAC_AIFS_TCK;
+ if (!(cfp || idle))
+ {
+ /* The backoff should be drawn now. */
+ if (new_backoff_drawn)
+ ca_backoff_cancel (ctx);
+ ca_backoff_new (ctx, mfs->cap);
+ new_backoff_drawn = true;
+ minimum_length += (2 + ctx->backoff.bc) * MAC_SLOT_TCK;
+ }
+ if (less_mod2p32 (vcs_end_date + minimum_length,
+ bp->start_date +
+ sched->allocations[alloc_i].end_offset_tck))
+ {
+ /* Fit. */
+ break;
+ }
+ }
+ }
+ /* Advance to the next allocation. */
+ if (alloc_i == sched->allocations_nb)
+ {
+ /* Next beacon period. */
+ bp_i = CA_ALLOC_NEXT_BEACON_PERIOD (bp_i);
+ if (bp_i == bp_end_i)
+ {
+ /* Give up. */
+ break;
+ }
+ bp = &ctx->beacon_periods[bp_i];
+ sched = &ctx->schedules[bp->schedule_index];
+ alloc_i = 0;
+ vcs_end_date = bp->start_date;
+ }
+ else
+ {
+ /* Next allocation. */
+ vcs_end_date = bp->start_date
+ + sched->allocations[alloc_i].end_offset_tck;
+ alloc_i++;
+ }
+ /* IDLE for EIFS only works for the first allocation. If we land in
+ * another allocation, the synchronisation is done. */
+ idle = false;
+ } while (1);
+ /* TODO: combine with an MME. */
+ /* Was a allocation found? */
+ if (bp_i != bp_end_i)
+ {
+ /* Setup ACCESS for this allocation. */
+ if (!(cfp || idle))
+ {
+ phy_access_backoff_start (ctx->phy, vcs_end_date, mfs->cap);
+ phy_access_timer_program (ctx->phy, vcs_end_date
+ + (ctx->backoff.bc + 2) * MAC_SLOT_TCK
+ - anticipation_tck);
+ }
+ else
+ {
+ phy_access_timer_program (ctx->phy, vcs_end_date
+ - anticipation_tck);
+ }
+ /* Record parameters if VCS need to be reprogrammed. */
+ ctx->vcs_start_date = start_date;
+ ctx->vcs_length_tck = length_tck;
+ ctx->vcs_eifs = eifs;
+ ctx->anticipation_tck = anticipation_tck;
+ }
+ else
+ {
+ ctx->vcs_length_tck = 0;
+ }
+}
+
+void
+ca_access_program (ca_t *ctx, u32 date, uint anticipation_tck)
+{
+ dbg_assert (ctx);
+ phy_access_timer_program (ctx->phy, date - anticipation_tck);
+}
+
+void
+ca_access_grant (ca_t *ctx, mfs_tx_t *mfs, uint duration_tck)
+{
+ dbg_assert (ctx);
+ if (!mfs)
+ {
+ /* Choose an MFS. */
+ ctx->access_param.mfs =
+ PARENT_OF (mfs_tx_t, link, heap_get_root (&ctx->mfs_heap));
+ }
+ else
+ {
+ /* Use the given one. */
+ ctx->access_param.mfs = mfs;
+ }
+ ctx->access_param.duration_tck = duration_tck;
+ ctx->access_param.content = false;
+}
+
+const ca_access_param_t *
+ca_access_get_param (ca_t *ctx)
+{
+ dbg_assert (ctx);
+ return &ctx->access_param;
+}
+
+static mfs_tx_t *
+ca_access_choose_mfs_tx (ca_t *ctx, uint glid)
+{
+ dbg_assert (ctx);
+ dbg_assert (glid >= MAC_GLID_MIN);
+ /* If GLID, this is a CFP allocation, else choose the MFS with the greater
+ * priority. */
+ if (glid <= MAC_GLID_MAX)
+ return mac_store_mfs_get_tx (ctx->store, false, false, glid, 0);
+ else if (CA_ALLOC_IS_CSMA (glid))
+ return PARENT_OF (mfs_tx_t, link, heap_get_root (&ctx->mfs_heap));
+ else /* \todo support beacon TX. */
+ return NULL;
+}
+