/* Cesar project {{{ * * Copyright (C) 2009 Spidcom * * <<>> * * }}} */ /** * \file ce/rx/bitloading/src/common.c * \brief Common transition functions * \ingroup ce_rx */ #include "common/std.h" #include "ce/rx/bitloading/ber_margin_update.h" #include "ce/rx/bitloading/inc/initial.h" #include "ce/rx/bitloading/inc/common.h" #include "ce/rx/bitloading/inc/ber.h" #include "ce/rx/bitloading/inc/intervals.h" #include "ce/rx/inc/measure.h" #include "ce/rx/cp/inc/cp.h" #include "ce/rx/inc/trace.h" #include "ce/rx/ce_rx_param.h" #include "ce/debug/gpio/gpio.h" #include "mac/common/timings.h" #include uint ce_rx_bl_min_time_between_ce_restart_ms[CE_RX_BL_DATE_CRITERIA_NB] = { CE_RX_BL_MIN_TIME_BETWEEN_CE_RESTART_PBER_MS, CE_RX_BL_MIN_TIME_BETWEEN_CE_RESTART_BER_MS, CE_RX_BL_MIN_TIME_BETWEEN_CE_RESTART_BER_MARGIN_UPDATE }; void ce_rx_bl_start_bl (ce_rx_t *ce_rx, sta_t *sta, int fsm_id) { /* Check parameters. */ dbg_assert (ce_rx); dbg_assert (sta); dbg_assert (ce_rx->mac_config); /* Not using ts directly. */ /* Not using ce_rx directly. */ ce_rx_bitloading_t *bt; /* Initial CE is used when this is the first time we use a tone map with * the station. */ bool initial_ce; CE_RX_TRACE (BL_INITIAL, sta->tei, fsm_id); ce_debug_gpio_event (CE_DEBUG_GPIO_EVENT_CE_RX_BL_WORKING, true); tonemask_info_t *ts = &ce_rx->mac_config->tonemask_info; /* This is the default tone map. */ if (fsm_id == CE_RX_MEASURE_NO_INTERVAL) { bt = &sta->ce_rx_bt; initial_ce = true; } /* Tone map for an interval. */ else { dbg_assert (sta->intervals); bt = sta->intervals->intervals[fsm_id]; /* We don't have an initial CE here because with intervals, we already * have a default tone map. */ initial_ce = false; } /* Compute new tone map. */ tonemap_t *new_tm = ce_rx_bl_initial (ts, &ce_rx->tonemask, bt); /* Dump tone map in trace. */ if (CONFIG_TRACE) { dbg_assert (ts); #define OFFSET 3 /* The last field of mod_count is used to store the fsm id in the * trace */ int mod_count[OFFSET + CE_MOD_COUNT + 1]; mod_count [OFFSET + CE_MOD_COUNT] = fsm_id; uint m; uint sum = 0; /* Initialize. */ mod_count[0] = phy_date (); mod_count[1] = sta->tei; for (m = OFFSET; m < COUNT (mod_count) - 1; m++) mod_count[m] = 0; /* Count. */ if (new_tm) { TONEMAP_READ_BEGIN (new_tm, ts->tonemask, m) { mod_count[m + OFFSET]++; sum += m; } TONEMAP_READ_END; } /* Trace result. */ mod_count[2] = sum; CE_RX_TRACE_N (TONEMAP, mod_count, COUNT (mod_count)); #undef OFFSET } u8 new_tmi, old_tmi; u64 ber; /* Compare with ROBO. */ if (new_tm != NULL && ce_rx_bl_tonemap_better_than_robo (new_tm, ts)) { /* Set it. */ new_tmi = tonemaps_set_first_free_tmi (sta->rx_tonemaps, new_tm); /* This assert is required because this is the first time we ever * set a tone map in the life of this STA. So we MUST have an * empty tone map index available! */ dbg_assert (new_tmi != 0); ber = new_tm->ber_target_reached; } else { ce_debug_gpio_event (CE_DEBUG_GPIO_EVENT_CE_RX_BL_ROBO_BETTER, true); /* TMI ROBO. */ new_tmi = PHY_MOD_ROBO; /* Remove computed tone map. */ if (new_tm != NULL) tonemap_free (new_tm); ber = ce_rx_bl_ber_pt_robo (ts->carrier_nb); /* Trace it. */ CE_RX_TRACE (WORSE_THAN_ROBO, fsm_id, sta->tei); } /* Update BER sliding means. */ ce_rx_bl_ber_sliding_mean_update (bt, ber); if (fsm_id == CE_RX_MEASURE_NO_INTERVAL) sta->rx_tonemaps->default_tmi = new_tmi; else { old_tmi = sta->intervals->tmi[fsm_id]; sta->intervals->tmi[fsm_id] = new_tmi; /* Update default global tonemap. */ ce_rx_bl_intervals_update_default_tm (ce_rx, sta); /* Update intervals in rx_tonemaps. */ ce_rx_bl_intervals_update_tmi (sta, ce_rx->aclf->beacon_period_theo_tck); /* Mark old TM as to be release (unless it is used as global default * tonemap). */ if (!(ce_rx_bl_intervals_get_tmi_used_list (sta, true) & (1 << old_tmi)) && TONEMAP_INDEX_IS_NEGOTIATED (old_tmi)) tonemap_disable (sta->rx_tonemaps, old_tmi); } /* Send new tone map. */ ce_rx_cp_send_mme_new_tone_map (ce_rx, sta, TONEMAP_INDEX_IS_NEGOTIATED (new_tmi) ? new_tmi : 0, 0, initial_ce); /* Store next time the we can restart. */ uint i; for (i = 0; i < CE_RX_BL_DATE_CRITERIA_NB; i++) bt->next_date_min_for_restart_rtc_date[i] = cyg_current_time () + MAC_MS_TO_TCK (ce_rx_bl_min_time_between_ce_restart_ms[i]) / ce_rx->tck_per_rtc; /* Reset BER margin PB counter. */ ce_rx_bl_bmu_reset_pb_counter (&sta->ce_rx_bt.bmu); ce_debug_gpio_event (CE_DEBUG_GPIO_EVENT_CE_RX_BL_WORKING, false); ce_debug_gpio_event (CE_DEBUG_GPIO_EVENT_CE_RX_BL_ROBO_BETTER, false); } bool ce_rx_bl_tonemap_better_than_robo (tonemap_t *tm, tonemask_info_t *ti) { /* Check parameters. */ dbg_assert (tm); dbg_assert (ti); if (tm->bits_per_symbol > ti->tonemap_robo[PHY_MOD_ROBO].bits_per_symbol) return true; else return false; }