/* Cesar project {{{ * * Copyright (C) 2010 Spidcom * * <<>> * * }}} */ /** * \file bsu/test/utest/src/schedules.c * \brief BSU schedule tests. * \ingroup bsu */ #include "common/std.h" #include "lib/test.h" #include "bsu/bsu.h" #include "mac/common/timings.h" #include "bsu/test/utest/tests.h" #include "bsu/inc/bsu.h" #include "bsu/inc/context.h" #include "bsu/inc/interface.h" #include void bsu_schedules_merge (bsu_t *ctx, bsu_beacon_t *beacon, ca_schedule_t *schedules, uint nb); void bsu_ca_schedules__timer_event (bsu_t *ctx, bsu_avln_t *avln); void bsu_timer_event_process (void *ud); void test_case_ca_schedules (test_t test) { bsu_test_t t; bsu_avln_t avln; bsu_test_init (&t); test_case_begin (test, "CA Schedules"); test_begin (test, "Merge function") { t.bsu->is_sta = BSU_UPDATE_STA_TYPE_STA; uint i, j; ca_schedule_t scheds_cmp [3]; scheds_cmp[0].allocations[0].end_offset_tck = MAC_ATU_TO_TCK (500); scheds_cmp[0].allocations[0].glid = MAC_LID_SPC_BEACON_LISTEN; scheds_cmp[0].allocations[1].end_offset_tck = MAC_ATU_TO_TCK (700); scheds_cmp[0].allocations[1].glid = MAC_GLID_MIN; scheds_cmp[0].allocations[2].end_offset_tck = MAC_ATU_TO_TCK (1000); scheds_cmp[0].allocations[2].glid = MAC_GLID_MIN; scheds_cmp[0].allocations[3].end_offset_tck = MAC_ATU_TO_TCK (1600); scheds_cmp[0].allocations[3].glid = MAC_LID_SPC_HOLE; scheds_cmp[0].allocations[4].end_offset_tck = MAC_ATU_TO_TCK (2500); scheds_cmp[0].allocations[4].glid = MAC_GLID_MIN; scheds_cmp[0].allocations[5].end_offset_tck = MAC_ATU_TO_TCK (3907); scheds_cmp[0].allocations[5].glid = MAC_GLID_MIN; /* next */ scheds_cmp[1].allocations[0].end_offset_tck = MAC_ATU_TO_TCK (500); scheds_cmp[1].allocations[0].glid = MAC_LID_SPC_BEACON_LISTEN; scheds_cmp[1].allocations[1].end_offset_tck = MAC_ATU_TO_TCK (700); scheds_cmp[1].allocations[1].glid = MAC_GLID_MIN; scheds_cmp[1].allocations[2].end_offset_tck = MAC_ATU_TO_TCK (1000); scheds_cmp[1].allocations[2].glid = MAC_GLID_MIN; scheds_cmp[1].allocations[3].end_offset_tck = MAC_ATU_TO_TCK (1600); scheds_cmp[1].allocations[3].glid = MAC_LID_SPC_HOLE; scheds_cmp[1].allocations[4].end_offset_tck = MAC_ATU_TO_TCK (2500); scheds_cmp[1].allocations[4].glid = MAC_GLID_MIN; scheds_cmp[1].allocations[5].end_offset_tck = MAC_ATU_TO_TCK (3907); scheds_cmp[1].allocations[5].glid = MAC_GLID_MIN; /* next */ scheds_cmp[2].allocations[0].end_offset_tck = MAC_ATU_TO_TCK (50); scheds_cmp[2].allocations[0].glid = MAC_LID_SPC_BEACON_LISTEN; scheds_cmp[2].allocations[1].end_offset_tck = MAC_ATU_TO_TCK (500); scheds_cmp[2].allocations[1].glid = MAC_GLID_MIN; scheds_cmp[2].allocations[2].end_offset_tck = MAC_ATU_TO_TCK (700); scheds_cmp[2].allocations[2].glid = MAC_GLID_MIN; scheds_cmp[2].allocations[3].end_offset_tck = MAC_ATU_TO_TCK (1600); scheds_cmp[2].allocations[3].glid = MAC_GLID_MIN; scheds_cmp[2].allocations[4].end_offset_tck = MAC_ATU_TO_TCK (2500); scheds_cmp[2].allocations[4].glid = MAC_GLID_MIN; scheds_cmp[2].allocations[5].end_offset_tck = MAC_ATU_TO_TCK (3907); scheds_cmp[2].allocations[5].glid = MAC_GLID_MIN; ca_schedule_t scheds; bsu_test_avln_create (&t, &avln); for (i = 0; i < COUNT(scheds_cmp); i++) { bsu_schedules_merge (t.bsu, &avln.beacon, &scheds, i); for (j = 0; j < scheds.allocations_nb; j++) { test_fail_unless (scheds.allocations[j].end_offset_tck == scheds_cmp[i].allocations[j].end_offset_tck); test_fail_unless (scheds.allocations[j].glid == scheds_cmp[i].allocations[j].glid); } } } test_end; test_begin (test, "Ca schedules") { uint i, ca_sched_index, ca_first_sched_index; u32 bpsd[BSU_ACLF_BPSD_NB-1]; ca_sched_index = t.bsu->ca_index; ca_first_sched_index = t.bsu->ca_index_last_first; bsu_test_avln_create (&t, &avln); bsu_ca_schedules__timer_event (t.bsu, t.bsu->sta_avln); bsu_aclf_beacon_period_start_date (t.bsu->aclf, bpsd, COUNT (bpsd)); test_fail_unless (bpsd[0] == t.ca.beacon_periods[0].start_date); test_fail_unless (ca_first_sched_index == t.ca.beacon_periods[0].schedule_index); for (i = 1; i < t.ca.nb_beacon_periods; i++) { test_fail_unless (bpsd[i] == t.ca.beacon_periods[i].start_date); test_fail_unless ((i - 1 + ca_sched_index) % CA_SCHEDULE_NB == t.ca.beacon_periods[i].schedule_index); } } test_end; bsu_test_uninit (&t); } void test_case_bsu_schedules_countdowns_init (bsu_t *bsu, ca_schedule_t *cas) { bsu->sta_avln->beacon.bmis.change_snid.present = true; bsu->sta_avln->beacon.bmis.change_snid.snidccd = 3; bsu->sta_avln->beacon.bmis.change_snid.new_snid = 3; bsu->sta_avln->beacon.bmis.eks.present = true; bsu->sta_avln->beacon.bmis.eks.kccd = 3; bsu->sta_avln->beacon.bmis.eks.kbc = BSU_BEACON_EKS_KBC_NEK; bsu->sta_avln->beacon.bmis.eks.new_eks = 4; bsu->sta_avln->beacon.bmis.change_hm.present = true; bsu->sta_avln->beacon.bmis.change_hm.hmccd = 3; bsu->sta_avln->beacon.bmis.change_hm.newhm = 1; bsu->nek_switch = 0; cas[0].snid = bsu->sta_avln->snid; cas[0].coexistence_mode = bsu->sta_avln->beacon.vf.hm; cas[0].nek_switch = bsu->nek_switch; cas[1].snid = bsu->sta_avln->snid; cas[1].coexistence_mode = bsu->sta_avln->beacon.vf.hm; cas[1].nek_switch = bsu->nek_switch; cas[2].snid = bsu->sta_avln->beacon.bmis.change_snid.new_snid; cas[2].coexistence_mode = bsu->sta_avln->beacon.bmis.change_hm.newhm; cas[2].nek_switch = !bsu->nek_switch; } void test_case_bsu_schedules_countdowns (test_t t) { test_suite_begin (t, "Countdowns"); test_begin (t, "SNID/EKS/HM change") { uint i, j, ca_index, ca_index_last_first; bsu_beacon_t beacon; ca_schedule_t *casched; bsu_test_t ctx; pbproc_tx_beacon_params_t bparams; pbproc_rx_beacon_params_t bparamsrx; bsu_test_init (&ctx); bsu_activate (true); bsu_test_create_beacon (&ctx, &beacon); pb_beacon_t *pbbeacon = bsu_beacon_write ( &beacon, BSU_BEACON_TYPE_CENTRAL, &ctx.mac_config, &bparams); ctx.mac_config.tei = 0xA; bparamsrx.snid = 0; pbbeacon->phy_pb.pb_rx.pb_measurement.crc_error = false; bsu_beacon_recv (ctx.bsu, pbbeacon, &bparamsrx); blk_release (ctx.ul.beacon); bsu_test_upper_layer_beacon_received_init (&ctx); /* Continue the test. */ bsu_track_avln (beacon.vf.nid, 0x0, ctx.mac_config.tei); ctx.bsu->track_new = false; ctx.bsu->is_sta = BSU_UPDATE_STA_TYPE_STA; for (i = 0; i < BSU_ACLF_BPSD_NB; i++) ctx.bsu->aclf->bpsd[i] = i * BSU_ACLF_BP_50HZ_TCK; ca_schedule_t cas[3]; test_case_bsu_schedules_countdowns_init (ctx.bsu, cas); beacon.bmis.change_hm = ctx.bsu->sta_avln->beacon.bmis.change_hm; beacon.bmis.change_hm.hmccd--; beacon.bmis.change_snid = ctx.bsu->sta_avln->beacon.bmis.change_snid; beacon.bmis.change_snid.snidccd--; beacon.bmis.eks = ctx.bsu->sta_avln->beacon.bmis.eks; beacon.bmis.eks.kccd--; for (i = 0; i < COUNT (cas); i++) { /* Prepare expected results. */ for (j = 0; j < CA_SCHEDULE_NB; j++) { if (j != ctx.bsu->ca_index_last_first) memset (ca_alloc_get_schedule (INVALID_PTR, j), 0xff, sizeof (ca_schedule_t)); } /* station does not receive the last beacon. */ ctx.bsu->aclf->bpsd[0] = ctx.bsu->sta_avln->beacon.beacon_period_start_date = phy_date () - BSU_ACLF_BP_50HZ_TCK; if (i != 1) { beacon.bmis.bpsto.bpsto = 0; pb_beacon_t *b = bsu_beacon_write ( &beacon, BSU_BEACON_TYPE_CENTRAL, &ctx.mac_config, &bparams); ((pb_t *) b)->phy_pb.pb_rx.pb_measurement.crc_error = false; bparamsrx.preamble_date = bparamsrx.preamble_sysdate = 0; bparamsrx.bts = 0; /* On beacon reception only schedules are read and CA is * programmed with the current data. */ bsu_beacon_recv (ctx.bsu, b, &bparamsrx); blk_release (ctx.ul.beacon); bsu_test_upper_layer_beacon_received_init (&ctx); } /* On timer event the snid change, NEK and hybrid mode are changed * in the lower layers. */ ca_index = ctx.bsu->ca_index; ca_index_last_first = ctx.bsu->ca_index_last_first; bsu_timer_event_process (ctx.bsu); for (j = 0; j < COUNT (cas); j++) { if (j == 0) casched = ca_alloc_get_schedule ( INVALID_PTR, ca_index_last_first); else casched = ca_alloc_get_schedule ( INVALID_PTR, (ca_index + j - 1) % CA_SCHEDULE_NB); test_fail_unless (casched->snid == cas[j].snid); test_fail_unless (casched->nek_switch == cas[j].nek_switch); test_fail_unless (casched->coexistence_mode == cas[j].coexistence_mode); } cas[0] = cas[1]; cas[1] = cas[2]; beacon.bmis.change_snid.snidccd --; beacon.bmis.change_snid.present = beacon.bmis.change_snid.snidccd != 0; if (beacon.bmis.change_snid.present == false) bparamsrx.snid = beacon.bmis.change_snid.new_snid; beacon.bmis.eks.kccd--; beacon.bmis.eks.present = beacon.bmis.eks.kccd != 0; beacon.bmis.change_hm.hmccd--; beacon.bmis.change_hm.present = beacon.bmis.change_hm.hmccd != 0; if (beacon.bmis.change_hm.present == false) beacon.vf.hm = beacon.bmis.change_hm.newhm; } bsu_test_uninit (&ctx); } test_end; } void test_case_ca_schedules_intellon (test_t test) { test_case_begin (test, "Intellon central beacons"); test_begin ( test, "Persistent schedule valid for the current beacon period") { bsu_test_t t; bsu_test_init (&t); bsu_beacon_t beacon; pb_beacon_t *pbbeacon; bsu_test_create_beacon (&t, &beacon); beacon.bmis.nps.ns = 0; beacon.bmis.ps.nb = 1; beacon.bmis.ps.ps[0].ns = 1; beacon.bmis.ps.ps[0].pscd = 0; beacon.bmis.ps.ps[0].cscd = 0; beacon.bmis.ps.ps[0].sais[0].stpf = true; beacon.bmis.ps.ps[0].sais[0].start_time_atu = 52; beacon.bmis.ps.ps[0].sais[0].end_time_atu = 3907; beacon.bmis.ps.ps[0].sais[0].glid = MAC_LID_SHARED_CSMA & 0x7f; uint i; for (i = 0; i < COUNT (t.bsu->aclf->bpsd); i++) t.bsu->aclf->bpsd[i] = i * BSU_ACLF_BP_50HZ_TCK - 10; t.bsu->aclf->beacon_period = BSU_ACLF_BP_50HZ_TCK; *((uint*) &t.bsu->aclf->bp) = BSU_ACLF_BP_50HZ_TCK; pbproc_tx_beacon_params_t btx; pbproc_rx_beacon_params_t brx; memset (&brx, 0, sizeof (pbproc_rx_beacon_params_t)); pbbeacon = bsu_beacon_write ( &beacon, BSU_BEACON_TYPE_CENTRAL, &t.mac_config, &btx); pbbeacon->phy_pb.pb_rx.pb_measurement.crc_error = false; /* The first time bsu receives a beacon of an AVLN. */ brx.bts = BSU_ACLF_BP_50HZ_TCK / 2; bsu_beacon_process (t.bsu, pbbeacon, &brx); /* Control plane request to track this AVLN. */ bsu_track_avln (beacon.vf.nid, brx.snid, 0); t.bsu->track_new = false; t.bsu->is_sta = BSU_UPDATE_STA_TYPE_STA; /* BSU receives the next beacon. */ bsu_beacon_process (t.bsu, pbbeacon, &brx); /* Schedules which should be present. */ test_fail_unless (t.bsu->sta_avln->beacon.bmis.ps.nb == 1); test_fail_unless (t.bsu->sta_avln->beacon.bmis.ps.ps[0].pscd == 0); test_fail_unless (t.bsu->sta_avln->beacon.bmis.ps.ps[0].cscd == 7); test_fail_unless ( t.bsu->sta_avln->beacon.bmis.ps.ps[0].sais[0].glid == (MAC_LID_SHARED_CSMA & 0x7f)); test_fail_unless ( t.bsu->sta_avln->beacon.bmis.ps.ps[0].sais[0].end_time_atu == 3907); test_fail_unless ( t.bsu->sta_avln->beacon.bmis.ps.ps[0].sais[0].stpf == false); u32 bpsd[4]; bsu_aclf_beacon_period_start_date (t.bsu->aclf, bpsd, COUNT (bpsd)); for (i = 1; i < COUNT (bpsd); i++) test_fail_unless (brx.bts + i * BSU_ACLF_BP_50HZ_TCK == bpsd[i] + t.bsu->sta_avln->sync.ntb_offset_tck); blk_release_desc ((blk_t*) pbbeacon); bsu_test_uninit (&t); } test_end; } void test_case_ca_schedules_special_allocations__test ( test_t test, char *text, bsu_update_sta_type_t type) { bsu_test_t t; bsu_avln_t avln; bsu_test_init (&t); test_begin (test, text) { uint i; ca_schedule_t sched_cmp; sched_cmp.allocations[0].end_offset_tck = MAC_ATU_TO_TCK (500); if (type == BSU_UPDATE_STA_TYPE_STA) sched_cmp.allocations[0].glid = MAC_LID_SPC_BEACON_LISTEN; else sched_cmp.allocations[0].glid = MAC_LID_SPC_CENTRAL; sched_cmp.allocations[1].end_offset_tck = MAC_ATU_TO_TCK (3907); sched_cmp.allocations[1].glid = MAC_LID_SHARED_CSMA; t.bsu->is_sta = type; memset (&avln, 0, sizeof (bsu_avln_t)); avln.beacon.bmis.nps.ns = 1; avln.beacon.bmis.nps.sais[0].stpf = true; avln.beacon.bmis.nps.sais[0].start_time_atu = 500; avln.beacon.bmis.nps.sais[0].end_time_atu = 3907; avln.beacon.bmis.nps.sais[0].glid = MAC_LID_SHARED_CSMA & 0x7f; ca_schedule_t sched; bsu_schedules_merge (t.bsu, &avln.beacon, &sched, 0); for (i = 0; i < sched.allocations_nb; i++) { test_fail_unless (sched.allocations[i].end_offset_tck == sched_cmp.allocations[i].end_offset_tck); test_fail_unless (sched.allocations[i].glid == sched_cmp.allocations[i].glid); } } test_end; bsu_test_uninit (&t); } void test_case_ca_schedules_special_allocations (test_t t) { test_case_ca_schedules_special_allocations__test ( t, "Region beacon acts as STA", BSU_UPDATE_STA_TYPE_STA); test_case_ca_schedules_special_allocations__test ( t, "Region beacon acts as CCO", BSU_UPDATE_STA_TYPE_CCO); } bsu_avln_t * test_case_track_new_beacon (test_t t, bsu_test_t *ctx, bsu_beacon_t *beacon) { pbproc_rx_beacon_params_t params_rx; pbproc_tx_beacon_params_t params_tx; pb_beacon_t *pbbeacon; memset (¶ms_rx, 0, sizeof (pbproc_rx_beacon_params_t)); memset (¶ms_tx, 0, sizeof (pbproc_tx_beacon_params_t)); bsu_test_create_beacon (ctx, beacon); beacon->vf.nm = 0; beacon->bmis.bpsto.present = false; ctx->mac_config.tei = 1; pbbeacon = bsu_beacon_write ( beacon, BSU_BEACON_TYPE_CENTRAL, &ctx->mac_config, ¶ms_tx); ctx->mac_config.tei = 0; params_rx.bts = ctx->bsu->aclf->bpsd[0] + BSU_ACLF_BP_50HZ_TCK / 2; params_rx.snid = 1; bsu_avln_t *avln = bsu_beacon_process (ctx->bsu, pbbeacon, ¶ms_rx); blk_release_desc (&pbbeacon->blk); /* Modify the ntb_offset_tck to have a real case. */ avln->sync.ntb_offset_tck = 0; avln->beacon.beacon_period_start_date = params_rx.bts; return avln; } void test_case_track_new (test_t t) { bsu_test_t ctx; bsu_beacon_t beacon; uint i; test_case_begin (t, "Tracking a new AVLN"); test_begin (t, "Track new before timer") { bsu_test_init (&ctx); *((uint*) &ctx.bsu->aclf->bp) = BSU_ACLF_BP_50HZ_TCK; for (i = 0; i < COUNT (ctx.bsu->aclf->bpsd); i++) ctx.bsu->aclf->bpsd[i] = i * ctx.bsu->aclf->bp; ctx.bsu->activate = true; ctx.bsu->is_sta = BSU_UPDATE_STA_TYPE_STA; bsu_avln_t *avln = test_case_track_new_beacon (t, &ctx, &beacon); bsu_track_avln (beacon.vf.nid, 0x1, 0x1); test_fail_unless (ctx.bsu->track_new); bsu_timer_event_process (ctx.bsu); test_fail_unless (ctx.bsu->track_new == false); for (i = 0; i < BSU_BEACON_SCHEDULES_MAX - 1; i++) { test_fail_unless ( lesseq_mod2p32 ( ctx.ca.beacon_periods[i].start_date + ctx.bsu->aclf->bp, ctx.ca.beacon_periods[i + 1].start_date)); } /* Check beacon has been modified. */ for (i = 0; i < beacon.bmis.ps.nb; i++) { if (beacon.bmis.ps.ps[i].pscd) test_fail_unless (beacon.bmis.ps.ps[i].pscd - 1 == avln->beacon.bmis.ps.ps[i].pscd); else test_fail_unless (beacon.bmis.ps.ps[i].cscd - 1 == avln->beacon.bmis.ps.ps[i].cscd); } bsu_test_uninit (&ctx); } test_end; test_begin (t, "Track new after timer") { bsu_test_init (&ctx); *((uint*) &ctx.bsu->aclf->bp) = BSU_ACLF_BP_50HZ_TCK; for (i = 0; i < COUNT (ctx.bsu->aclf->bpsd); i++) ctx.bsu->aclf->bpsd[i] = i * ctx.bsu->aclf->bp; ctx.bsu->activate = true; ctx.bsu->is_sta = BSU_UPDATE_STA_TYPE_STA; bsu_avln_t *avln = test_case_track_new_beacon (t, &ctx, &beacon); bsu_timer_event_process (ctx.bsu); bsu_track_avln (beacon.vf.nid, 0x1, 0x1); test_fail_unless (ctx.bsu->track_new); avln = test_case_track_new_beacon (t, &ctx, &beacon); bsu_timer_event_process (ctx.bsu); test_fail_unless (ctx.bsu->track_new == false); for (i = 0; i < BSU_BEACON_SCHEDULES_MAX - 1; i++) { test_fail_unless ( lesseq_mod2p32 ( ctx.ca.beacon_periods[i].start_date + ctx.bsu->aclf->bp, ctx.ca.beacon_periods[i + 1].start_date)); } /* Check beacon has been modified. */ for (i = 0; i < beacon.bmis.ps.nb; i++) { if (beacon.bmis.ps.ps[i].pscd) test_fail_unless (beacon.bmis.ps.ps[i].pscd - 1 == avln->beacon.bmis.ps.ps[i].pscd); else test_fail_unless (beacon.bmis.ps.ps[i].cscd - 1 == avln->beacon.bmis.ps.ps[i].cscd); } bsu_test_uninit (&ctx); } test_end; test_begin (t, "Track new after timer second beacon not received.") { bsu_test_init (&ctx); *((uint*) &ctx.bsu->aclf->bp) = BSU_ACLF_BP_50HZ_TCK; for (i = 0; i < COUNT (ctx.bsu->aclf->bpsd); i++) ctx.bsu->aclf->bpsd[i] = i * ctx.bsu->aclf->bp; ctx.bsu->activate = true; ctx.bsu->is_sta = BSU_UPDATE_STA_TYPE_STA; bsu_avln_t *avln = test_case_track_new_beacon (t, &ctx, &beacon); bsu_timer_event_process (ctx.bsu); bsu_track_avln (beacon.vf.nid, 0x1, 0x1); test_fail_unless (ctx.bsu->track_new); bsu_timer_event_process (ctx.bsu); test_fail_unless (ctx.bsu->track_new == false); for (i = 0; i < BSU_BEACON_SCHEDULES_MAX - 1; i++) { test_fail_unless ( lesseq_mod2p32 ( ctx.ca.beacon_periods[i].start_date + ctx.bsu->aclf->bp, ctx.ca.beacon_periods[i + 1].start_date)); } /* Check beacon has been modified. */ beacon.bmis.ps.nb = 1; beacon.bmis.ps.ps[0] = beacon.bmis.ps.ps[1]; if (beacon.bmis.ps.ps[0].pscd) test_fail_unless (beacon.bmis.ps.ps[0].pscd - 2 == avln->beacon.bmis.ps.ps[0].pscd); else test_fail_unless (beacon.bmis.ps.ps[0].cscd - 2 == avln->beacon.bmis.ps.ps[0].cscd); bsu_test_uninit (&ctx); } test_end; } void test_suite_bsu_schedule (test_t t) { test_suite_begin (t, "BSU schedules"); test_case_ca_schedules (t); test_case_bsu_schedules_countdowns (t); test_case_ca_schedules_intellon (t); test_case_ca_schedules_special_allocations (t); test_case_track_new (t); }