/* Cesar project {{{ * * Copyright (C) 2010 Spidcom * * <<>> * * }}} */ /** * \file ce/rx/bitloading/test/src/test_fsm.c * \brief Test bit loading FSM. * \ingroup test */ #include "common/std.h" #include "ce/rx/inc/rx.h" #include "ce/rx/bitloading/fsm/event.h" #include "ce/rx/inc/measure.h" #include "ce/common/mod.h" #include "mac/common/sta.h" #include "ce_rx_bl_fsm_defs.h" #include "lib/test.h" #include "lib/scenario/scenario.h" #include "lib/rnd.h" #include /* Dirty hack. */ uint ce_rx_bl_pb_false_factor_; uint ce_rx_bl_pb_total_factor_; uint ce_rx_bl_min_pb_per_frame_; uint ce_rx_bl_min_frame_with_high_pb_err_rate_; uint ce_rx_bl_ber_lower_bound_ = 38; static uint const tmi_av = 24; static void test_ce_rx_bl_measure_empty (ce_rx_measure_mbox_t *m) { m->chan_data = NULL; m->chan_data_count = 0; m->total_pb_count = m->false_pb_count = m->ber_sum = 0; m->rx_params.tmi_av = tmi_av; m->rx_params.sound = false; m->rx_params.sound_complete = false; } /** * Reset bit loading after tracking */ static void test_ce_rx_bl_reset (ce_rx_bitloading_t *bl) { bl->noise_nrj_blk_count = 2; blk_t *last = NULL; bl->noise_nrj = blk_alloc_desc_range (bl->noise_nrj_blk_count, &last); bl->ber_sliding_mean[CE_RX_BL_BER_SLIDING_MEAN_FAST] = bl->ber_sliding_mean[CE_RX_BL_BER_SLIDING_MEAN_SLOW] = 0x4242; } static void test_ce_rx_bl_fsm_base (test_t t) { test_suite_begin (t, "CE:RX:BL:FSM"); mac_config_t config; config.tonemask_info.carrier_nb = PHY_CARRIER_NB; ce_rx_t ce = { .mac_config = &config, }; scenario_globals_t globals = { .ce = &ce, }; sta_t sta; tonemaps_t rx_tms, tx_tms; uint i; for (i = 0; i < TONEMAP_INDEX_NB; i++) { rx_tms.tm[i] = NULL; tx_tms.tm[i] = NULL; } sta.rx_tonemaps = &rx_tms; sta.tx_tonemaps = &tx_tms; tonemap_t tm; rx_tms.tm[tmi_av] = &tm; rx_tms.default_tmi = tmi_av; tm.bits_per_symbol = 1; tm.ber_target_reached = 1; ce_rx_bitloading_init (&sta.ce_rx_bt); for (i = 0; i < COUNT (sta.ce_rx_bt.next_date_min_for_restart_rtc_date); i++) sta.ce_rx_bt.next_date_min_for_restart_rtc_date[i] = 0; ce_rx_measure_mbox_t measure; test_case_begin (t, "sound not received yet"); test_begin (t, "IDLE, not sound, do nothing") { test_ce_rx_bl_measure_empty (&measure); scenario_entry_t fsm_base[] = { SCENARIO_ACTION (IDLE__data, .sta = &sta, .measure = measure, .branch = ce_rx_bl_fsm_next (IDLE, data)), /* Nothing should happen. */ SCENARIO_END, }; scenario_run (t, fsm_base, &globals); } test_end; test_case_begin (t, "many sounds, one sound complete, bit loading " "initial"); test_begin (t, "IDLE, many sound, one sound complete") { test_ce_rx_bl_measure_empty (&measure); measure.rx_params.sound = true; ce_rx_measure_mbox_t measure_sc; test_ce_rx_bl_measure_empty (&measure_sc); measure_sc.rx_params.sound = true; measure_sc.rx_params.sound_complete = true; scenario_entry_t fsm_base[] = { SCENARIO_ACTION (IDLE__sound, .sta = &sta, .measure = measure, .branch = ce_rx_bl_fsm_next (IDLE, sound)), /* Init NSR. */ SCENARIO_EVENT (ce_rx_bl_nsr_sum_init), SCENARIO_ACTION (INITIAL__sound, .sta = &sta, .measure = measure, .branch = ce_rx_bl_fsm_next (INITIAL, sound)), /* Increase NSR. */ SCENARIO_EVENT (ce_rx_bl_nsr_sum_add), SCENARIO_ACTION (INITIAL__sound, .sta = &sta, .measure = measure, .branch = ce_rx_bl_fsm_next (INITIAL, sound)), /* Increase NSR. */ SCENARIO_EVENT (ce_rx_bl_nsr_sum_add), SCENARIO_ACTION (INITIAL__sound_completed, .sta = &sta, .measure = measure_sc, .branch = ce_rx_bl_fsm_next_branch (INITIAL, sound_completed, no_mode_interval)), /* Increase NSR. */ SCENARIO_EVENT (ce_rx_bl_nsr_sum_add), /* Compute Mean. */ SCENARIO_EVENT (ce_rx_bl_nsr_compute_mean), /* Start BL. */ SCENARIO_EVENT (ce_rx_bl_start_bl), SCENARIO_END, }; scenario_run (t, fsm_base, &globals); } test_end; test_case_begin (t, "one sound complete, bit loading initial"); test_begin (t, "IDLE, one sound complete") { test_ce_rx_bl_measure_empty (&measure); measure.rx_params.sound = true; measure.rx_params.sound_complete = true; scenario_entry_t fsm_base[] = { SCENARIO_ACTION (IDLE__sound_completed, .sta = &sta, .measure = measure, .branch = ce_rx_bl_fsm_next_branch (IDLE, sound_completed, no_mode_interval)), /* Init NSR. */ SCENARIO_EVENT (ce_rx_bl_nsr_sum_init), /* Compute NSR mean (required because of NSR rescaling). */ SCENARIO_EVENT (ce_rx_bl_nsr_compute_mean), /* Start BL. */ SCENARIO_EVENT (ce_rx_bl_start_bl), SCENARIO_END, }; scenario_run (t, fsm_base, &globals); } test_end; test_case_begin (t, "many sound complete, one bit loading"); test_begin (t, "TRACKING, many sound complete") { test_ce_rx_bl_measure_empty (&measure); ce_rx_bitloading_init (&sta.ce_rx_bt); test_ce_rx_bl_reset (&sta.ce_rx_bt); measure.rx_params.sound = true; measure.rx_params.sound_complete = true; scenario_entry_t fsm_base[] = { SCENARIO_ACTION (TRACKING__sound_completed, .sta = &sta, .measure = measure, .branch = ce_rx_bl_fsm_next (TRACKING, sound_completed)), /* Nothing should happen. */ SCENARIO_END, }; scenario_run (t, fsm_base, &globals); /* Clean. */ ce_rx_bitloading_uninit (&sta.ce_rx_bt); } test_end; test_case_begin (t, "sound not complete, restart initial"); test_begin (t, "TRACKING, one sound not complete at least") { test_ce_rx_bl_measure_empty (&measure); ce_rx_bitloading_init (&sta.ce_rx_bt); test_ce_rx_bl_reset (&sta.ce_rx_bt); measure.rx_params.sound = true; measure.rx_params.sound_complete = false; scenario_entry_t fsm_base[] = { SCENARIO_ACTION (TRACKING__sound, .sta = &sta, .measure = measure, .branch = ce_rx_bl_fsm_next (TRACKING, sound)), /* Reset CE in RX. */ SCENARIO_EVENT (tonemaps_reset, .tms = sta.rx_tonemaps), /* Initialize with the last one. */ SCENARIO_EVENT (ce_rx_bl_nsr_sum_init), SCENARIO_END, }; scenario_run (t, fsm_base, &globals); /* Clean. */ ce_rx_bitloading_uninit (&sta.ce_rx_bt); } test_end; test_case_begin (t, "not sound, handle PB Error Rate"); ce_rx_bl_pb_false_factor_ = 2; ce_rx_bl_pb_total_factor_ = 3; ce_rx_bl_min_pb_per_frame_ = 2; ce_rx_bl_min_frame_with_high_pb_err_rate_ = 4; scenario_entry_t scenario_end = SCENARIO_END; const uint table_size = ce_rx_bl_min_frame_with_high_pb_err_rate_ * 4242; const uint iteration = ce_rx_bl_min_frame_with_high_pb_err_rate_ * 24; scenario_entry_t scenario_test[table_size]; lib_rnd_t rnd; lib_rnd_init (&rnd, 0x4242); test_begin (t, "TRACKING, low PB error rate, nothing happens") { test_ce_rx_bl_measure_empty (&measure); ce_rx_bitloading_init (&sta.ce_rx_bt); test_ce_rx_bl_reset (&sta.ce_rx_bt); uint i, pos = 0; for (i = 0; i < iteration; i++) { measure.total_pb_count = 1 + lib_rnd_uniform (&rnd, ((u8) -1)); measure.false_pb_count = lib_rnd_uniform (&rnd, measure.total_pb_count / ce_rx_bl_pb_total_factor_); scenario_test[pos++] = (scenario_entry_t) SCENARIO_ACTION (TRACKING__data, .sta = &sta, .measure = measure, .branch = ce_rx_bl_fsm_next_branch (TRACKING, data, pb_err_rate_low)); scenario_test[pos++] = (scenario_entry_t) SCENARIO_EVENT (ce_rx_bl_ber_sliding_mean_update); } scenario_test[pos++] = scenario_end; scenario_run (t, scenario_test, &globals); /* Clean. */ ce_rx_bitloading_uninit (&sta.ce_rx_bt); } test_end; test_begin (t, "TRACKING, low PB error rate, high PB error rate but not " "enough, nothing happens") { ce_rx_bitloading_init (&sta.ce_rx_bt); test_ce_rx_bl_reset (&sta.ce_rx_bt); test_ce_rx_bl_measure_empty (&measure); uint i, pos = 0; for (i = 0; i < iteration; i++) { measure.total_pb_count = ce_rx_bl_min_pb_per_frame_ + lib_rnd_uniform (&rnd, ((u8) (-1) - ce_rx_bl_min_pb_per_frame_)); dbg_assert (measure.total_pb_count); if (i % (ce_rx_bl_min_frame_with_high_pb_err_rate_ - 1) == 0) measure.false_pb_count = 0; else measure.false_pb_count = measure.total_pb_count; scenario_test[pos++] = (scenario_entry_t) SCENARIO_ACTION (TRACKING__data, .sta = &sta, .measure = measure, .branch = ce_rx_bl_fsm_next_branch (TRACKING, data, pb_err_rate_low)); if (measure.false_pb_count == 0) scenario_test[pos++] = (scenario_entry_t) SCENARIO_EVENT (ce_rx_bl_ber_sliding_mean_update); } scenario_test[pos++] = scenario_end; scenario_run (t, scenario_test, &globals); /* Clean. */ ce_rx_bitloading_uninit (&sta.ce_rx_bt); } test_end; test_begin (t, "TRACKING, high PB error rate, not enough PB, nothing " "happens") { ce_rx_bitloading_init (&sta.ce_rx_bt); test_ce_rx_bl_reset (&sta.ce_rx_bt); test_ce_rx_bl_measure_empty (&measure); uint i, pos = 0; for (i = 0; i < iteration; i++) { measure.total_pb_count = 1; measure.false_pb_count = lib_rnd_uniform (&rnd, (u8) -1); scenario_test[pos++] = (scenario_entry_t) SCENARIO_ACTION (TRACKING__data, .sta = &sta, .measure = measure, .branch = ce_rx_bl_fsm_next_branch (TRACKING, data, pb_err_rate_low)); if (measure.total_pb_count != measure.false_pb_count) scenario_test[pos++] = (scenario_entry_t) SCENARIO_EVENT (ce_rx_bl_ber_sliding_mean_update); } scenario_test[pos++] = scenario_end; scenario_run (t, scenario_test, &globals); /* Clean. */ ce_rx_bitloading_uninit (&sta.ce_rx_bt); } test_end; test_begin (t, "TRACKING, high PB error rate on ROBO, nothing " "happens") { ce_rx_bitloading_init (&sta.ce_rx_bt); test_ce_rx_bl_reset (&sta.ce_rx_bt); test_ce_rx_bl_measure_empty (&measure); u8 robo[PHY_MOD_ROBO_NB] = { PHY_MOD_ROBO, PHY_MOD_HS_ROBO, PHY_MOD_MINI_ROBO }; uint i, pos = 0; for (i = 0; i < iteration; i++) { measure.total_pb_count = 1; /* Set to ROBO. */ measure.rx_params.tmi_av = robo[i % PHY_MOD_ROBO_NB]; measure.false_pb_count = lib_rnd_uniform (&rnd, (u8) -1); scenario_test[pos++] = (scenario_entry_t) SCENARIO_ACTION (TRACKING__data, .sta = &sta, .measure = measure, .branch = ce_rx_bl_fsm_next_branch (TRACKING, data, pb_err_rate_low)); } scenario_test[pos++] = scenario_end; scenario_run (t, scenario_test, &globals); /* Clean. */ ce_rx_bitloading_uninit (&sta.ce_rx_bt); } test_end; test_begin (t, "TRACKING, high PB error rate, enough PB, restart CE") { ce_rx_bitloading_init (&sta.ce_rx_bt); test_ce_rx_bl_reset (&sta.ce_rx_bt); test_ce_rx_bl_measure_empty (&measure); measure.total_pb_count = ce_rx_bl_min_pb_per_frame_ + lib_rnd_uniform (&rnd, ((u8) (-1) - ce_rx_bl_min_pb_per_frame_)); measure.false_pb_count = measure.total_pb_count - 1; uint i; const uint limit = ce_rx_bl_min_frame_with_high_pb_err_rate_ - 1; uint pos; for (i = 0, pos = 0; i < limit; i++) { scenario_test[pos++] = (scenario_entry_t) SCENARIO_ACTION (TRACKING__data, .sta = &sta, .measure = measure, .branch = ce_rx_bl_fsm_next_branch (TRACKING, data, pb_err_rate_low)); scenario_test[pos++] = (scenario_entry_t) SCENARIO_EVENT (ce_rx_bl_ber_sliding_mean_update); } scenario_entry_t sub_sc_ce_restart[] = { SCENARIO_ACTION (TRACKING__data, .sta = &sta, .measure = measure, .branch = ce_rx_bl_fsm_next_branch (TRACKING, data, pb_err_rate_high)), SCENARIO_EVENT (ce_rx_bl_ber_sliding_mean_update), /* Reset CE in RX. */ SCENARIO_EVENT (tonemaps_reset, .tms = sta.rx_tonemaps), /* Dirty hack, reset CE in TX. */ SCENARIO_EVENT (tonemaps_reset, .tms = sta.tx_tonemaps), SCENARIO_END, }; for (i = 0; i < COUNT (sub_sc_ce_restart); i++) scenario_test[i + pos] = sub_sc_ce_restart[i]; scenario_run (t, scenario_test, &globals); /* Clean. */ ce_rx_bitloading_uninit (&sta.ce_rx_bt); } test_end; test_begin (t, "TRACKING, high PB error rate, enough PB, but too soon, " "not restarting CE") { ce_rx_bitloading_init (&sta.ce_rx_bt); sta.ce_rx_bt.next_date_min_for_restart_rtc_date[0] = 42; test_ce_rx_bl_reset (&sta.ce_rx_bt); test_ce_rx_bl_measure_empty (&measure); measure.total_pb_count = ce_rx_bl_min_pb_per_frame_ + lib_rnd_uniform (&rnd, ((u8) (-1) - ce_rx_bl_min_pb_per_frame_)); measure.false_pb_count = measure.total_pb_count - 1; uint i; const uint limit = ce_rx_bl_min_frame_with_high_pb_err_rate_ * 2; uint pos; for (i = 0, pos = 0; i < limit; i++) { scenario_test[pos++] = (scenario_entry_t) SCENARIO_ACTION (TRACKING__data, .sta = &sta, .measure = measure, .branch = ce_rx_bl_fsm_next_branch (TRACKING, data, pb_err_rate_low)); scenario_test[pos++] = (scenario_entry_t) SCENARIO_EVENT (ce_rx_bl_ber_sliding_mean_update); } scenario_run (t, scenario_test, &globals); /* Clean. */ ce_rx_bitloading_uninit (&sta.ce_rx_bt); sta.ce_rx_bt.next_date_min_for_restart_rtc_date[0] = 0; } test_end; test_begin (t, "TRACKING, BER sliding means too low, restart CE") { ce_rx_bitloading_init (&sta.ce_rx_bt); test_ce_rx_bl_reset (&sta.ce_rx_bt); test_ce_rx_bl_measure_empty (&measure); measure.false_pb_count = 0; measure.total_pb_count = 42; tm.ber_target_reached = 0x4242; sta.ce_rx_bt.ber_sliding_mean[CE_RX_BL_BER_SLIDING_MEAN_FAST] = sta.ce_rx_bt.ber_sliding_mean[CE_RX_BL_BER_SLIDING_MEAN_SLOW] = 0x1; uint pos = 0; scenario_test[pos++] = (scenario_entry_t) SCENARIO_ACTION (TRACKING__data, .sta = &sta, .measure = measure, .branch = ce_rx_bl_fsm_next_branch (TRACKING, data, ber_too_low)); scenario_test[pos++] = (scenario_entry_t) SCENARIO_EVENT (ce_rx_bl_ber_sliding_mean_update); /* Reset CE in RX. */ scenario_test[pos++] = (scenario_entry_t) SCENARIO_EVENT (tonemaps_reset, .tms = sta.rx_tonemaps); /* Dirty hack, reset CE in TX. */ scenario_test[pos++] = (scenario_entry_t) SCENARIO_EVENT (tonemaps_reset, .tms = sta.tx_tonemaps); scenario_test[pos++] = (scenario_entry_t) SCENARIO_END; scenario_run (t, scenario_test, &globals); /* Clean. */ ce_rx_bitloading_uninit (&sta.ce_rx_bt); } test_end; test_begin (t, "TRACKING, BER sliding means too low but too soon, " "not restarting CE") { ce_rx_bitloading_init (&sta.ce_rx_bt); sta.ce_rx_bt.next_date_min_for_restart_rtc_date[1] = 42; test_ce_rx_bl_reset (&sta.ce_rx_bt); test_ce_rx_bl_measure_empty (&measure); measure.false_pb_count = 0; measure.total_pb_count = 42; tm.ber_target_reached = 0x4242; sta.ce_rx_bt.ber_sliding_mean[CE_RX_BL_BER_SLIDING_MEAN_FAST] = sta.ce_rx_bt.ber_sliding_mean[CE_RX_BL_BER_SLIDING_MEAN_SLOW] = 0x1; uint pos = 0; scenario_test[pos++] = (scenario_entry_t) SCENARIO_ACTION (TRACKING__data, .sta = &sta, .measure = measure, .branch = ce_rx_bl_fsm_next_branch (TRACKING, data, pb_err_rate_low)); scenario_test[pos++] = (scenario_entry_t) SCENARIO_EVENT (ce_rx_bl_ber_sliding_mean_update); scenario_test[pos++] = (scenario_entry_t) SCENARIO_END; scenario_run (t, scenario_test, &globals); /* Clean. */ ce_rx_bitloading_uninit (&sta.ce_rx_bt); sta.ce_rx_bt.next_date_min_for_restart_rtc_date[1] = 0; } test_end; test_begin (t, "TRACKING, BER sliding means too low, restart CE, on ROBO") { ce_rx_bitloading_init (&sta.ce_rx_bt); test_ce_rx_bl_reset (&sta.ce_rx_bt); test_ce_rx_bl_measure_empty (&measure); measure.false_pb_count = 0; measure.total_pb_count = 42; tm.ber_target_reached = 0x4242; rx_tms.default_tmi = measure.rx_params.tmi_av = PHY_MOD_ROBO; sta.ce_rx_bt.ber_sliding_mean[CE_RX_BL_BER_SLIDING_MEAN_FAST] = sta.ce_rx_bt.ber_sliding_mean[CE_RX_BL_BER_SLIDING_MEAN_SLOW] = 0x1; uint pos = 0; scenario_test[pos++] = (scenario_entry_t) SCENARIO_ACTION (TRACKING__data, .sta = &sta, .measure = measure, .branch = ce_rx_bl_fsm_next_branch (TRACKING, data, ber_too_low)); scenario_test[pos++] = (scenario_entry_t) SCENARIO_EVENT (ce_rx_bl_ber_sliding_mean_update); /* Reset CE in RX. */ scenario_test[pos++] = (scenario_entry_t) SCENARIO_EVENT (tonemaps_reset, .tms = sta.rx_tonemaps); /* Dirty hack, reset CE in TX. */ scenario_test[pos++] = (scenario_entry_t) SCENARIO_EVENT (tonemaps_reset, .tms = sta.tx_tonemaps); scenario_test[pos++] = (scenario_entry_t) SCENARIO_END; scenario_run (t, scenario_test, &globals); /* Clean. */ ce_rx_bitloading_uninit (&sta.ce_rx_bt); rx_tms.default_tmi = tmi_av; } test_end; test_begin (t, "TRACKING, one one BER sliding means too low, " "do nothing") { ce_rx_bitloading_init (&sta.ce_rx_bt); test_ce_rx_bl_reset (&sta.ce_rx_bt); test_ce_rx_bl_measure_empty (&measure); measure.false_pb_count = 0; measure.total_pb_count = 42; tm.ber_target_reached = 0x4242; sta.ce_rx_bt.ber_sliding_mean[CE_RX_BL_BER_SLIDING_MEAN_FAST] = 0x1; sta.ce_rx_bt.ber_sliding_mean[CE_RX_BL_BER_SLIDING_MEAN_SLOW] = 0x4242; uint pos = 0; scenario_test[pos++] = (scenario_entry_t) SCENARIO_ACTION (TRACKING__data, .sta = &sta, .measure = measure, .branch = ce_rx_bl_fsm_next_branch (TRACKING, data, pb_err_rate_low)); scenario_test[pos++] = (scenario_entry_t) SCENARIO_EVENT (ce_rx_bl_ber_sliding_mean_update); scenario_test[pos++] = (scenario_entry_t) SCENARIO_END; scenario_run (t, scenario_test, &globals); /* Clean. */ ce_rx_bitloading_uninit (&sta.ce_rx_bt); } test_end; test_begin (t, "TRACKING, BER sliding means too low but tone map at max, " "do nothing") { ce_rx_bitloading_init (&sta.ce_rx_bt); test_ce_rx_bl_reset (&sta.ce_rx_bt); test_ce_rx_bl_measure_empty (&measure); measure.false_pb_count = 0; measure.total_pb_count = 42; tm.ber_target_reached = 0x4242; tm.bits_per_symbol = PHY_CARRIER_NB * CE_BIT_PER_MOD[CE_MOD_COUNT - 1]; sta.ce_rx_bt.ber_sliding_mean[CE_RX_BL_BER_SLIDING_MEAN_FAST] = sta.ce_rx_bt.ber_sliding_mean[CE_RX_BL_BER_SLIDING_MEAN_SLOW] = 0x1; uint pos = 0; scenario_test[pos++] = (scenario_entry_t) SCENARIO_ACTION (TRACKING__data, .sta = &sta, .measure = measure, .branch = ce_rx_bl_fsm_next_branch (TRACKING, data, pb_err_rate_low)); scenario_test[pos++] = (scenario_entry_t) SCENARIO_EVENT (ce_rx_bl_ber_sliding_mean_update); scenario_test[pos++] = (scenario_entry_t) SCENARIO_END; scenario_run (t, scenario_test, &globals); /* Clean. */ ce_rx_bitloading_uninit (&sta.ce_rx_bt); } test_end; } int main (int argc, char **argv) { test_t t; test_init (t, argc, argv); test_ce_rx_bl_fsm_base (t); test_result (t); return test_nb_failed (t) == 0 ? 0 : 1; }