summaryrefslogtreecommitdiff
path: root/cesar/mac/pbproc/test
diff options
context:
space:
mode:
Diffstat (limited to 'cesar/mac/pbproc/test')
-rw-r--r--cesar/mac/pbproc/test/fc/Makefile32
-rw-r--r--cesar/mac/pbproc/test/fc/src/beacon.txt12
-rwxr-xr-xcesar/mac/pbproc/test/fc/src/generate-check.pl54
-rw-r--r--cesar/mac/pbproc/test/fc/src/generic.txt5
-rw-r--r--cesar/mac/pbproc/test/fc/src/rsof.txt23
-rw-r--r--cesar/mac/pbproc/test/fc/src/rts_cts.txt17
-rw-r--r--cesar/mac/pbproc/test/fc/src/sack.txt18
-rw-r--r--cesar/mac/pbproc/test/fc/src/sof.txt32
-rw-r--r--cesar/mac/pbproc/test/fc/src/sound.txt19
-rw-r--r--cesar/mac/pbproc/test/fc/src/test_fc.c136
-rw-r--r--cesar/mac/pbproc/test/fsm/Makefile8
-rw-r--r--cesar/mac/pbproc/test/fsm/src/test_fsm.c209
-rw-r--r--cesar/mac/pbproc/test/maximus/Config2
-rw-r--r--cesar/mac/pbproc/test/maximus/Makefile10
-rw-r--r--cesar/mac/pbproc/test/maximus/ecos.ecc.sh5
-rw-r--r--cesar/mac/pbproc/test/maximus/inc/add_beacon_period.h23
-rw-r--r--cesar/mac/pbproc/test/maximus/inc/add_seg.h23
-rw-r--r--cesar/mac/pbproc/test/maximus/inc/context.h81
-rw-r--r--cesar/mac/pbproc/test/maximus/inc/get_seg.h31
-rw-r--r--cesar/mac/pbproc/test/maximus/inc/msg.h43
-rw-r--r--cesar/mac/pbproc/test/maximus/inc/prepare_beacon.h23
-rw-r--r--cesar/mac/pbproc/test/maximus/inc/set_tonemap.h23
-rw-r--r--cesar/mac/pbproc/test/maximus/inc/test_pbproc.h55
-rw-r--r--cesar/mac/pbproc/test/maximus/py/host_test_pbproc.py85
-rw-r--r--cesar/mac/pbproc/test/maximus/py/test_coll.py94
-rw-r--r--cesar/mac/pbproc/test/maximus/py/test_pbproc.py63
-rw-r--r--cesar/mac/pbproc/test/maximus/src/add_beacon_period.c101
-rw-r--r--cesar/mac/pbproc/test/maximus/src/add_seg.c111
-rw-r--r--cesar/mac/pbproc/test/maximus/src/get_seg.c104
-rw-r--r--cesar/mac/pbproc/test/maximus/src/prepare_beacon.c98
-rw-r--r--cesar/mac/pbproc/test/maximus/src/set_tonemap.c105
-rw-r--r--cesar/mac/pbproc/test/maximus/src/test_pbproc.c303
-rw-r--r--cesar/mac/pbproc/test/mfs/Makefile9
-rw-r--r--cesar/mac/pbproc/test/mfs/src/test_mfs.c292
-rw-r--r--cesar/mac/pbproc/test/pbproc/Config1
-rw-r--r--cesar/mac/pbproc/test/pbproc/Makefile10
-rw-r--r--cesar/mac/pbproc/test/pbproc/inc/scenario.h152
-rw-r--r--cesar/mac/pbproc/test/pbproc/inc/scenario_defs.h243
-rw-r--r--cesar/mac/pbproc/test/pbproc/inc/test_pbproc.h47
-rw-r--r--cesar/mac/pbproc/test/pbproc/inc/utils.h38
-rw-r--r--cesar/mac/pbproc/test/pbproc/override/hal/phy/inc/context.h51
-rw-r--r--cesar/mac/pbproc/test/pbproc/override/mac/ca/inc/context.h26
-rw-r--r--cesar/mac/pbproc/test/pbproc/src/ca.c129
-rw-r--r--cesar/mac/pbproc/test/pbproc/src/phy.c229
-rw-r--r--cesar/mac/pbproc/test/pbproc/src/prep_mpdu.c575
-rw-r--r--cesar/mac/pbproc/test/pbproc/src/rx_data.c624
-rw-r--r--cesar/mac/pbproc/test/pbproc/src/scenario.c50
-rw-r--r--cesar/mac/pbproc/test/pbproc/src/scenario_defs.c109
-rw-r--r--cesar/mac/pbproc/test/pbproc/src/test_pbproc.c193
-rw-r--r--cesar/mac/pbproc/test/pbproc/src/tx_data.c270
-rw-r--r--cesar/mac/pbproc/test/pbproc/src/utils.c148
-rw-r--r--cesar/mac/pbproc/test/sacki/Makefile10
-rw-r--r--cesar/mac/pbproc/test/sacki/src/test_sacki.c411
53 files changed, 5565 insertions, 0 deletions
diff --git a/cesar/mac/pbproc/test/fc/Makefile b/cesar/mac/pbproc/test/fc/Makefile
new file mode 100644
index 0000000000..9e62562fad
--- /dev/null
+++ b/cesar/mac/pbproc/test/fc/Makefile
@@ -0,0 +1,32 @@
+BASE = ../../../..
+
+TARGET=sparc
+
+HOST_PROGRAMS = test_fc
+test_fc_SOURCES = test_fc.c
+test_fc_MODULES = lib mac/pbproc
+
+TARGET_PROGRAMS = test_fc_target
+test_fc_target_SOURCES = test_fc.c
+test_fc_target_MODULES = lib mac/pbproc
+
+mac_pbproc_MODULE_SOURCES = fc.c
+
+generic_h = obj/inc/generic.h
+beacon_h = obj/inc/beacon.h
+sof_h = obj/inc/sof.h
+sack_h = obj/inc/sack.h
+rts_cts_h = obj/inc/rts_cts.h
+sound_h = obj/inc/sound.h
+rsof_h = obj/inc/rsof.h
+
+gen_headers = $(generic_h) $(beacon_h) $(sof_h) $(sack_h) $(rts_cts_h) \
+ $(sound_h) $(rsof_h)
+CLEAN_FILES = $(gen_headers)
+
+include $(BASE)/common/make/top.mk
+
+$(call src2obj,src/test_fc.c,host): $(gen_headers)
+$(call src2obj,src/test_fc.c,target): $(gen_headers)
+obj/inc/%.h: src/%.txt src/generate-check.pl $(OBJ_INC_DIR_STAMP)
+ perl src/generate-check.pl $* $< > $@
diff --git a/cesar/mac/pbproc/test/fc/src/beacon.txt b/cesar/mac/pbproc/test/fc/src/beacon.txt
new file mode 100644
index 0000000000..b7aa9a6c3f
--- /dev/null
+++ b/cesar/mac/pbproc/test/fc/src/beacon.txt
@@ -0,0 +1,12 @@
+DT_AV 3
+ACCESS 1
+SNID 4
+BTS_lsb 24 bts_lsb24
+BTS_msb 8 bts_msb8
+BTO(0) 16
+BTO(1)_lsb 8 bto1_lsb8
+BTO(1)_msb 8 bto1_msb8
+BTO(2) 16
+BTO(3)_lsb 8 bto3_lsb8
+BTO(3)_msb 8 bto3_msb8
+FCCS_AV 24
diff --git a/cesar/mac/pbproc/test/fc/src/generate-check.pl b/cesar/mac/pbproc/test/fc/src/generate-check.pl
new file mode 100755
index 0000000000..a3cea5b521
--- /dev/null
+++ b/cesar/mac/pbproc/test/fc/src/generate-check.pl
@@ -0,0 +1,54 @@
+#!/usr/bin/perl
+#
+# Generate a FC structure ckecking program.
+#
+use strict;
+use warnings;
+
+my $fc = shift @ARGV;
+
+print <<EOF;
+void
+check_$fc (test_t t, const pbproc_fc_t *fc)
+{
+ test_within (t);
+ u32 var;
+EOF
+
+my $offset = 0;
+
+while (<>)
+{
+ chomp;
+ /^([A-Za-z_0-9()]*)\t(\d+)(?:\t([][a-z_0-9]+))?$/ or die;
+ my $name = $1;
+ my $size = $2;
+ my $field = defined $3 ? $3 : $name;
+ $field = lc $field;
+ $field =~ y/()//d;
+ if ($name eq '')
+ {
+ print " /* Skip $size bits. */\n";
+ }
+ else
+ {
+ print " /* Read $name. */\n";
+ if ($size == 32)
+ {
+ print " var = fc->words[" . int ($offset / 32) . "] >> "
+ . $offset % 32 . ";\n";
+ }
+ else
+ {
+ print " var = (fc->words[" . int ($offset / 32) . "] >> "
+ . $offset % 32 . ") & ((1 << $size) - 1);\n";
+ }
+ print " test_fail_unless (var == fc->$fc.$field);\n";
+ }
+ $offset += $size;
+}
+$offset == 128 or die "$ARGV";
+
+print <<EOF;
+}
+EOF
diff --git a/cesar/mac/pbproc/test/fc/src/generic.txt b/cesar/mac/pbproc/test/fc/src/generic.txt
new file mode 100644
index 0000000000..c70cd69fcc
--- /dev/null
+++ b/cesar/mac/pbproc/test/fc/src/generic.txt
@@ -0,0 +1,5 @@
+DT_AV 3
+ACCESS 1
+SNID 4
+ 96
+FCCS_AV 24
diff --git a/cesar/mac/pbproc/test/fc/src/rsof.txt b/cesar/mac/pbproc/test/fc/src/rsof.txt
new file mode 100644
index 0000000000..03691af88d
--- /dev/null
+++ b/cesar/mac/pbproc/test/fc/src/rsof.txt
@@ -0,0 +1,23 @@
+DT_AV 3
+ACCESS 1
+SNID 4
+DTEI 8
+CFS 1
+BDF 1
+SVN 1
+RRTF 1
+MFSRspData 2 mfs_rsp_data
+MFSRspMgmt 2 mfs_rsp_mgmt
+SACKT(3) 2
+SACKT(2) 2
+SACKT(1) 2
+SACKT(0) 2
+SACKI(0) 32 sacki_lsb
+SACKI(1) 16 sacki_msb
+RSOF_FL_AV 10
+TMI_AV 5
+PBSz 1
+NumSym 2 num_sym
+MFSCmdMgmt 3 mfs_cmd_mgmt
+MFSCmdData 3 mfs_cmd_data
+FCCS_AV 24
diff --git a/cesar/mac/pbproc/test/fc/src/rts_cts.txt b/cesar/mac/pbproc/test/fc/src/rts_cts.txt
new file mode 100644
index 0000000000..6d46a2d6bc
--- /dev/null
+++ b/cesar/mac/pbproc/test/fc/src/rts_cts.txt
@@ -0,0 +1,17 @@
+DT_AV 3
+ACCESS 1
+SNID 4
+STEI 8
+DTEI 8
+LID 8
+CFS 1
+BDF 1
+HP10DF 1
+HP11DF 1
+RTSF 1
+IGF 1
+MNBF 1
+MCF 1
+DUR 14
+ 50
+FCCS_AV 24
diff --git a/cesar/mac/pbproc/test/fc/src/sack.txt b/cesar/mac/pbproc/test/fc/src/sack.txt
new file mode 100644
index 0000000000..c5c9da58c7
--- /dev/null
+++ b/cesar/mac/pbproc/test/fc/src/sack.txt
@@ -0,0 +1,18 @@
+DT_AV 3
+ACCESS 1
+SNID 4
+DTEI 8
+CFS 1
+BDF 1
+SVN 1
+RRTF 1
+MFSRspData 2 mfs_rsp_data
+MFSRspMgmt 2 mfs_rsp_mgmt
+SACKT(3) 2
+SACKT(2) 2
+SACKT(1) 2
+SACKT(0) 2
+SACKI(0) 32 sacki[0]
+SACKI(1) 32 sacki[1]
+SACKI(2) 8 sacki_last
+FCCS_AV 24
diff --git a/cesar/mac/pbproc/test/fc/src/sof.txt b/cesar/mac/pbproc/test/fc/src/sof.txt
new file mode 100644
index 0000000000..2b3a208c21
--- /dev/null
+++ b/cesar/mac/pbproc/test/fc/src/sof.txt
@@ -0,0 +1,32 @@
+DT_AV 3
+ACCESS 1
+SNID 4
+STEI 8
+DTEI 8
+LID 8
+CFS 1
+BDF 1
+HP10DF 1
+HP11DF 1
+EKS 4
+PPB 8
+BLE 8
+PBSz 1
+NumSym 2 num_sym
+TMI_AV 5
+FL_AV 12
+MPDUCnt 2 mpdu_cnt
+BurstCnt 2 burst_cnt
+BBF 1
+MRTFL 4
+DCPPCF 1
+MCF 1
+MNBF 1
+RSR 1
+CLST 1
+MFSCmdMgmt 3 mfs_cmd_mgmt
+MFSCmdData 3 mfs_cmd_data
+MFSRspMgmt 2 mfs_rsp_mgmt
+MFSRspData 2 mfs_rsp_data
+BM_SACKI 4
+FCCS_AV 24
diff --git a/cesar/mac/pbproc/test/fc/src/sound.txt b/cesar/mac/pbproc/test/fc/src/sound.txt
new file mode 100644
index 0000000000..8e3a081d65
--- /dev/null
+++ b/cesar/mac/pbproc/test/fc/src/sound.txt
@@ -0,0 +1,19 @@
+DT_AV 3
+ACCESS 1
+SNID 4
+STEI 8
+DTEI 8
+LID 8
+CFS 1
+PBSz 1
+BDF 1
+SAF 1
+SCF 1
+REQ_TM 3
+FL_AV 12
+MPDUCnt 2 mpdu_cnt
+ 2
+PPB 8
+SRC 8
+ 32
+FCCS_AV 24
diff --git a/cesar/mac/pbproc/test/fc/src/test_fc.c b/cesar/mac/pbproc/test/fc/src/test_fc.c
new file mode 100644
index 0000000000..69fdaa7413
--- /dev/null
+++ b/cesar/mac/pbproc/test/fc/src/test_fc.c
@@ -0,0 +1,136 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file src/test_fc.c
+ * \brief Test frame control structures.
+ * \ingroup test
+ */
+#include "common/std.h"
+
+#include "lib/rnd.h"
+#include "lib/test.h"
+
+#include "mac/pbproc/inc/fc.h"
+
+#define NB_ITER 10000
+
+typedef void
+(*check_f_t) (test_t t, const pbproc_fc_t *fc);
+
+#include "obj/inc/generic.h"
+#include "obj/inc/beacon.h"
+#include "obj/inc/sof.h"
+#include "obj/inc/sack.h"
+#include "obj/inc/rts_cts.h"
+#include "obj/inc/sound.h"
+#include "obj/inc/rsof.h"
+
+static struct
+{
+ const char *name;
+ check_f_t f;
+} checks[] = {
+ { "generic", check_generic },
+ { "beacon", check_beacon },
+ { "sof", check_sof },
+ { "sack", check_sack },
+ { "rts_cts", check_rts_cts },
+ { "sound", check_sound },
+ { "rsof", check_rsof },
+ { NULL, NULL }
+};
+
+void
+fc_test_suite (test_t t)
+{
+ uint i, j, k;
+ pbproc_fc_t fc;
+ lib_rnd_t rnd[1];
+ test_suite_begin (t, "fc");
+ /* Init. */
+ lib_rnd_init (rnd, 1234);
+ /* Test cases loop. */
+ for (i = 0; checks[i].name; i++)
+ {
+ test_case_begin (t, checks[i].name);
+ test_begin (t, "word to fields")
+ {
+ for (j = 0; j < NB_ITER; j++)
+ {
+ for (k = 0; k < COUNT (fc.words); k++)
+ fc.words[k] = lib_rnd32 (rnd);
+ checks[i].f (t, &fc);
+ }
+ } test_end;
+ }
+}
+
+static uint
+fc_ppb_test_decode (u8 ppb)
+{
+ uint mant = ppb >> 4;
+ uint exp = ppb & 0xf;
+ if (exp < 1)
+ return mant;
+ else if (exp == 1)
+ return (mant + 16) << (exp - 1);
+ else
+ return ((mant + 16) << (exp - 1)) + (1 << (exp - 2));
+}
+
+static void
+fc_ppb_test_value (test_t t, uint v)
+{
+ test_within (t);
+ u8 ppb = pbproc_fc_pbb (v);
+ uint ppb_dec_l, ppb_dec_p;
+ if (ppb == 0)
+ ppb_dec_l = 0;
+ else
+ {
+ u8 ppb_l = ppb >> 4 | ppb << 4;
+ ppb_l--;
+ ppb_l = ppb_l >> 4 | ppb_l << 4;
+ ppb_dec_l = fc_ppb_test_decode (ppb_l);
+ }
+ if (ppb == 255)
+ ppb_dec_p = 0xffffffffu;
+ else
+ {
+ u8 ppb_p = ppb >> 4 | ppb << 4;
+ ppb_p++;
+ ppb_p = ppb_p >> 4 | ppb_p << 4;
+ ppb_dec_p = fc_ppb_test_decode (ppb_p);
+ }
+ test_fail_unless (ppb_dec_l <= v && v < ppb_dec_p,
+ "bad PPB: integer = %u, coded = 0x%02x", v, ppb);
+}
+
+void
+fc_ppb_test_suite (test_t t)
+{
+ test_suite_begin (t, "fc ppb");
+ test_case_begin (t, "basic");
+ test_begin (t, "enumerate")
+ {
+ uint i;
+ for (i = 0; i < 2 << 19; i++)
+ fc_ppb_test_value (t, i);
+ } test_end;
+}
+
+int
+main (int argc, char **argv)
+{
+ test_t t;
+ test_init (t, argc, argv);
+ fc_test_suite (t);
+ fc_ppb_test_suite (t);
+ test_result (t);
+ return test_nb_failed (t) == 0 ? 0 : 1;
+}
diff --git a/cesar/mac/pbproc/test/fsm/Makefile b/cesar/mac/pbproc/test/fsm/Makefile
new file mode 100644
index 0000000000..ee1f48266a
--- /dev/null
+++ b/cesar/mac/pbproc/test/fsm/Makefile
@@ -0,0 +1,8 @@
+BASE = ../../../..
+
+HOST_PROGRAMS = test_fsm
+test_fsm_SOURCES = test_fsm.c
+test_fsm_MODULES = lib mac/pbproc
+mac_pbproc_MODULE_SOURCES = fsm.c
+
+include $(BASE)/common/make/top.mk
diff --git a/cesar/mac/pbproc/test/fsm/src/test_fsm.c b/cesar/mac/pbproc/test/fsm/src/test_fsm.c
new file mode 100644
index 0000000000..fc4efd4c98
--- /dev/null
+++ b/cesar/mac/pbproc/test/fsm/src/test_fsm.c
@@ -0,0 +1,209 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file src/test_fsm.c
+ * \brief Test FSM engine.
+ * \ingroup test
+ */
+#include "common/std.h"
+
+#include "lib/test.h"
+#include "lib/rnd.h"
+
+#include "mac/pbproc/inc/context.h"
+
+#define NB_ITER 10000
+#define NB_EVENT 3
+
+/** Test transition description. */
+struct fsm_basic_trans_desc_t
+{
+ /** Is an unexpected transition. */
+ bool unexpected;
+ /** Will ask a DSR. */
+ bool defer;
+ /** Next state. */
+ pbproc_fsm_state_t next_state;
+};
+typedef struct fsm_basic_trans_desc_t fsm_basic_trans_desc_t;
+
+/** Test description structure. */
+struct fsm_basic_desc_t
+{
+ /** Current state. */
+ pbproc_fsm_state_t state;
+ /** Expect callback (0-2 for event, -1 for DSR). */
+ int expected;
+ /** Set by the callback if ok. */
+ bool ok;
+ /** Transition table. */
+ fsm_basic_trans_desc_t trans[PBPROC_FSM_STATE_NB][NB_EVENT];
+};
+typedef struct fsm_basic_desc_t fsm_basic_desc_t;
+
+/** FSM DSR event callback. */
+void
+fsm_deferred_cb (pbproc_t *ctx)
+{
+ fsm_basic_desc_t *d;
+ dbg_assert (ctx);
+ d = ctx->user_data;
+ dbg_assert (d);
+ dbg_assert (d->state < PBPROC_FSM_STATE_NB);
+ if (d->expected == -1)
+ {
+ d->ok = true;
+ }
+}
+
+/** FSM any event callback. */
+void
+fsm_event_cb (pbproc_t *ctx, int event)
+{
+ fsm_basic_desc_t *d;
+ dbg_assert (ctx);
+ dbg_assert (event >= 0 && event < NB_EVENT);
+ d = ctx->user_data;
+ dbg_assert (d);
+ dbg_assert (d->state < PBPROC_FSM_STATE_NB);
+ fsm_basic_trans_desc_t *t = &d->trans[d->state][event];
+ if (d->expected == event && !t->unexpected)
+ {
+ d->ok = true;
+ if (t->defer)
+ pbproc_fsm_schedule_deferred (ctx, fsm_deferred_cb);
+ pbproc_fsm_change_state (ctx, t->next_state);
+ }
+}
+
+/** FSM RX FC event callback. */
+void
+fsm_rx_fc_cb (pbproc_t *ctx, u32 rx_date, const pbproc_fc_t *fc_av)
+{
+ fsm_event_cb (ctx, 0);
+}
+
+/** FSM ACCESS event callback. */
+void
+fsm_access_cb (pbproc_t *ctx)
+{
+ fsm_event_cb (ctx, 1);
+}
+
+/** FSM ACCESS CONFIRM event callback. */
+void
+fsm_access_conf_cb (pbproc_t *ctx)
+{
+ fsm_event_cb (ctx, 2);
+}
+
+void
+fsm_basic_test_case (test_t t)
+{
+ pbproc_t pbproc;
+ fsm_basic_desc_t d;
+ pbproc_fsm_state_t s;
+ uint i;
+ lib_rnd_t rnd[1];
+ test_case_begin (t, "basic");
+ lib_rnd_init (rnd, 1234);
+ /* Initialise FSM part. */
+ pbproc_fsm_init (&pbproc);
+ /* Randomize automaton. */
+ d.state = PBPROC_FSM_STATE_IDLE;
+ d.expected = 0;
+ d.ok = false;
+ for (s = 0; s < PBPROC_FSM_STATE_NB; s++)
+ {
+ bool one_expected = false;
+ for (i = 0; i < NB_EVENT; i++)
+ {
+ d.trans[s][i].unexpected = (one_expected || i != NB_EVENT - 1)
+ && lib_rnd_flip_coin (rnd, LIB_RND_RATIO (0.3));
+ if (!d.trans[s][i].unexpected)
+ {
+ d.trans[s][i].defer =
+ lib_rnd_flip_coin (rnd, LIB_RND_RATIO (0.5));
+ d.trans[s][i].next_state =
+ lib_rnd_uniform (rnd, PBPROC_FSM_STATE_NB);
+ one_expected = true;
+ switch (i)
+ {
+ case 0:
+ pbproc.fsm.states[s].rx_fc_cb = fsm_rx_fc_cb;
+ break;
+ case 1:
+ pbproc.fsm.states[s].access_cb = fsm_access_cb;
+ break;
+ case 2:
+ pbproc.fsm.states[s].access_conf_cb = fsm_access_conf_cb;
+ break;
+ }
+ }
+ }
+ }
+ pbproc.user_data = &d;
+ /* Run automaton. */
+ test_begin (t, "random transitions")
+ {
+ int event;
+ bool defer;
+ for (i = 0; i < NB_ITER; i++)
+ {
+ do {
+ event = lib_rnd_uniform (rnd, NB_EVENT);
+ } while (d.trans[d.state][event].unexpected);
+ d.expected = event;
+ switch (event)
+ {
+ case 0:
+ defer = pbproc_fsm_handle_rx_fc_event (&pbproc, 0, NULL);
+ break;
+ case 1:
+ defer = pbproc_fsm_handle_access_event (&pbproc);
+ break;
+ case 2:
+ defer = pbproc_fsm_handle_access_conf_event (&pbproc);
+ break;
+ }
+ test_fail_unless (d.ok, "callback not called");
+ d.ok = false;
+ test_fail_unless (pbproc.fsm.current_state ==
+ d.trans[d.state][event].next_state);
+ if (defer)
+ {
+ d.expected = -1;
+ pbproc_fsm_handle_deferred (&pbproc);
+ test_fail_unless (d.ok, "callback not called");
+ d.ok = false;
+ }
+ else
+ {
+ test_fail_unless (!pbproc.fsm.deferred_cb);
+ }
+ d.state = pbproc.fsm.current_state;
+ }
+ } test_end;
+}
+
+void
+fsm_test_suite (test_t t)
+{
+ test_suite_begin (t, "fsm");
+ fsm_basic_test_case (t);
+}
+
+int
+main (int argc, char **argv)
+{
+ test_t t;
+ test_init (t, argc, argv);
+ fsm_test_suite (t);
+ test_result (t);
+ return test_nb_failed (t) == 0 ? 0 : 1;
+}
diff --git a/cesar/mac/pbproc/test/maximus/Config b/cesar/mac/pbproc/test/maximus/Config
new file mode 100644
index 0000000000..56fc7a5571
--- /dev/null
+++ b/cesar/mac/pbproc/test/maximus/Config
@@ -0,0 +1,2 @@
+CONFIG_TRACE = y
+CONFIG_HOST_ASSERT = n \ No newline at end of file
diff --git a/cesar/mac/pbproc/test/maximus/Makefile b/cesar/mac/pbproc/test/maximus/Makefile
new file mode 100644
index 0000000000..2abbf462c8
--- /dev/null
+++ b/cesar/mac/pbproc/test/maximus/Makefile
@@ -0,0 +1,10 @@
+BASE = ../../../..
+
+ECOS = y
+
+TARGET_PROGRAMS = test_pbproc
+test_pbproc_SOURCES = test_pbproc.c get_seg.c add_seg.c prepare_beacon.c \
+ add_beacon_period.c set_tonemap.c
+test_pbproc_MODULES = hal/phy/maximus host lib mac/pbproc mac/ca mac/common
+
+include $(BASE)/common/make/top.mk
diff --git a/cesar/mac/pbproc/test/maximus/ecos.ecc.sh b/cesar/mac/pbproc/test/maximus/ecos.ecc.sh
new file mode 100644
index 0000000000..e0278271fe
--- /dev/null
+++ b/cesar/mac/pbproc/test/maximus/ecos.ecc.sh
@@ -0,0 +1,5 @@
+config=${1:-ecos-gen.ecc}
+ecosconfig --config=$config new maximus default
+cat >> $config <<'EOF'
+EOF
+ecosconfig --config=$config check
diff --git a/cesar/mac/pbproc/test/maximus/inc/add_beacon_period.h b/cesar/mac/pbproc/test/maximus/inc/add_beacon_period.h
new file mode 100644
index 0000000000..9df5a45281
--- /dev/null
+++ b/cesar/mac/pbproc/test/maximus/inc/add_beacon_period.h
@@ -0,0 +1,23 @@
+#ifndef inc_add_beacon_period_h
+#define inc_add_beacon_period_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file inc/add_beacon_period.h
+ * \brief Add beacon period fcall.
+ * \ingroup test
+ */
+
+BEGIN_DECLS
+
+void
+test_pbproc_add_beacon_period_init (test_pbproc_t *ctx);
+
+END_DECLS
+
+#endif /* inc_add_beacon_period_h */
diff --git a/cesar/mac/pbproc/test/maximus/inc/add_seg.h b/cesar/mac/pbproc/test/maximus/inc/add_seg.h
new file mode 100644
index 0000000000..37705e1a90
--- /dev/null
+++ b/cesar/mac/pbproc/test/maximus/inc/add_seg.h
@@ -0,0 +1,23 @@
+#ifndef inc_add_seg_h
+#define inc_add_seg_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file inc/add_seg.h
+ * \brief Add segments fcall.
+ * \ingroup test
+ */
+
+BEGIN_DECLS
+
+void
+test_pbproc_add_seg_init (test_pbproc_t *ctx);
+
+END_DECLS
+
+#endif /* inc_add_seg_h */
diff --git a/cesar/mac/pbproc/test/maximus/inc/context.h b/cesar/mac/pbproc/test/maximus/inc/context.h
new file mode 100644
index 0000000000..1a1fb93c6f
--- /dev/null
+++ b/cesar/mac/pbproc/test/maximus/inc/context.h
@@ -0,0 +1,81 @@
+#ifndef inc_context_h
+#define inc_context_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file inc/context.h
+ * \brief PBProc test context.
+ * \ingroup test
+ */
+
+#include <cyg/hal/hal_arch.h>
+#include <cyg/kernel/kapi.h>
+
+#include "lib/rnd.h"
+#include "host/fcall.h"
+
+#include "mac/pbproc/pbproc.h"
+
+#include "inc/msg.h"
+
+/** Number of beacon periods to keep. */
+#define TEST_PBPROC_NB_BEACON_PERIOD 3
+
+typedef void
+(*test_pbproc_msg_handler_cb_t) (test_pbproc_t *ctx, test_pbproc_msg_t *msg);
+
+/** Test PBProc context. */
+struct test_pbproc_t
+{
+ /** Random context. */
+ lib_rnd_t rnd[1];
+ /** Mac configuration. */
+ mac_config_t config;
+ /** Mac MFS and STA store. */
+ mac_store_t *store;
+ /** PBProc context. */
+ pbproc_t *pbproc;
+ /** Channel Access context. */
+ ca_t *ca;
+
+ /** Beacon periods. */
+ ca_beacon_period_t beacon_periods[TEST_PBPROC_NB_BEACON_PERIOD];
+ /** Number of beacon periods. */
+ uint beacon_periods_nb;
+
+ /** Event semaphore. */
+ cyg_sem_t event_sem;
+ /** Mailbox handle. */
+ cyg_handle_t mbox;
+ /** Mailbox storage. */
+ cyg_mbox mbox_storage;
+ /** Static message. */
+ test_pbproc_msg_t static_msg;
+ /** Messages handlers. */
+ test_pbproc_msg_handler_cb_t msg_handlers[TEST_PBPROC_MSG_ID_NONE];
+
+ /** PBProc RX callback. */
+ pbproc_rx_cb_t rx_cb;
+ /** Number of received PB. */
+ uint rx_pb_nb;
+
+ /** Function call context for return. */
+ fcall_ctx_t *fcall;
+ /** Function call identifier for return. */
+ unsigned short fcall_msg_id;
+
+ /** Kernel thread handle. */
+ cyg_handle_t thread;
+ /** Kernel thread storage. */
+ cyg_thread thread_storage;
+ /* Thread stack. */
+ u8 thread_stack[CYGNUM_HAL_STACK_SIZE_TYPICAL];
+};
+/* Forward declared in inc/test_pbproc.h. */
+
+#endif /* inc_context_h */
diff --git a/cesar/mac/pbproc/test/maximus/inc/get_seg.h b/cesar/mac/pbproc/test/maximus/inc/get_seg.h
new file mode 100644
index 0000000000..c6dccc8697
--- /dev/null
+++ b/cesar/mac/pbproc/test/maximus/inc/get_seg.h
@@ -0,0 +1,31 @@
+#ifndef inc_get_seg_h
+#define inc_get_seg_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file inc/get_seg.h
+ * \brief Get segments fcall.
+ * \ingroup test
+ */
+
+/** Get segments message. */
+struct test_pbproc_msg_get_seg_t
+{
+ /** Number of expected segments. */
+ uint seg_nb;
+};
+typedef struct test_pbproc_msg_get_seg_t test_pbproc_msg_get_seg_t;
+
+BEGIN_DECLS
+
+void
+test_pbproc_get_seg_init (test_pbproc_t *ctx);
+
+END_DECLS
+
+#endif /* inc_get_seg_h */
diff --git a/cesar/mac/pbproc/test/maximus/inc/msg.h b/cesar/mac/pbproc/test/maximus/inc/msg.h
new file mode 100644
index 0000000000..bd7ed8958a
--- /dev/null
+++ b/cesar/mac/pbproc/test/maximus/inc/msg.h
@@ -0,0 +1,43 @@
+#ifndef inc_msg_h
+#define inc_msg_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file inc/msg.h
+ * \brief PBProc test messages.
+ * \ingroup test
+ */
+
+#include "inc/test_pbproc.h"
+#include "inc/add_seg.h"
+#include "inc/prepare_beacon.h"
+#include "inc/get_seg.h"
+#include "inc/add_beacon_period.h"
+#include "inc/set_tonemap.h"
+
+/** Test PBProc messages identifiers. */
+enum test_pbproc_msg_id_t
+{
+ TEST_PBPROC_MSG_ID_GET_SEG,
+ TEST_PBPROC_MSG_ID_NONE,
+};
+typedef enum test_pbproc_msg_id_t test_pbproc_msg_id_t;
+
+/** Message union. */
+struct test_pbproc_msg_t
+{
+ /** Message identifier. */
+ test_pbproc_msg_id_t id;
+ /** Message itself. */
+ union {
+ struct test_pbproc_msg_get_seg_t get_seg;
+ } msg;
+};
+typedef struct test_pbproc_msg_t test_pbproc_msg_t;
+
+#endif /* inc_msg_h */
diff --git a/cesar/mac/pbproc/test/maximus/inc/prepare_beacon.h b/cesar/mac/pbproc/test/maximus/inc/prepare_beacon.h
new file mode 100644
index 0000000000..d2446b1ddc
--- /dev/null
+++ b/cesar/mac/pbproc/test/maximus/inc/prepare_beacon.h
@@ -0,0 +1,23 @@
+#ifndef inc_prepare_beacon_h
+#define inc_prepare_beacon_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file inc/prepare_beacon.h
+ * \brief Prepare beacon fcall.
+ * \ingroup test
+ */
+
+BEGIN_DECLS
+
+void
+test_pbproc_prepare_beacon_init (test_pbproc_t *ctx);
+
+END_DECLS
+
+#endif /* inc_prepare_beacon_h */
diff --git a/cesar/mac/pbproc/test/maximus/inc/set_tonemap.h b/cesar/mac/pbproc/test/maximus/inc/set_tonemap.h
new file mode 100644
index 0000000000..36fadbef99
--- /dev/null
+++ b/cesar/mac/pbproc/test/maximus/inc/set_tonemap.h
@@ -0,0 +1,23 @@
+#ifndef inc_set_tonemap_h
+#define inc_set_tonemap_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2008 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file inc/set_tonemap.h
+ * \brief Set tonemap fcall.
+ * \ingroup test
+ */
+
+BEGIN_DECLS
+
+void
+test_pbproc_set_tonemap_init (test_pbproc_t *ctx);
+
+END_DECLS
+
+#endif /* inc_set_tonemap_h */
diff --git a/cesar/mac/pbproc/test/maximus/inc/test_pbproc.h b/cesar/mac/pbproc/test/maximus/inc/test_pbproc.h
new file mode 100644
index 0000000000..6cb16c87d0
--- /dev/null
+++ b/cesar/mac/pbproc/test/maximus/inc/test_pbproc.h
@@ -0,0 +1,55 @@
+#ifndef inc_test_pbproc_h
+#define inc_test_pbproc_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file inc/test_pbproc.h
+ * \brief PBProc test on Maximus.
+ * \ingroup test
+ */
+#include "mac/pbproc/pbproc.h"
+
+/* Forward declaration. */
+typedef struct test_pbproc_t test_pbproc_t;
+
+/**
+ * Helper for parameter binding.
+ * \param name parameter string
+ * \param var parameter storage
+ * \return true if binding successful
+ */
+#define test_pbproc_fcall_bind(name, var) \
+ (fcall_param_bind (*param, *msg, (name), sizeof (var), &(var)) \
+ == sizeof (var))
+
+#define test_pbproc_fcall_bind_long(name, var) \
+ (fcall_param_bind_long (*param, *msg, (name), &(var)) == sizeof (var))
+
+/**
+ * Helper for parameter adding.
+ * \param name parameter string
+ * \param var parameter storage
+ */
+#define test_pbproc_fcall_add(name, var) \
+ dbg_check (fcall_param_add (&param, &msg, (name), sizeof (var), &(var)) \
+ != -1)
+
+#define test_pbproc_fcall_add_long(name, var) \
+ dbg_check (fcall_param_add_long (&param, &msg, (name), &(var)) != -1)
+
+BEGIN_DECLS
+
+void
+test_pbproc_default_rx_cb (void *user, mfs_t *mfs, mfs_t *mfs_mme,
+ const pbproc_rx_params_t *rx_params,
+ pb_t *pb_first, pb_t *pb_last, uint pb_nb,
+ pb_t *chandata_first, uint chandata_nb);
+
+END_DECLS
+
+#endif /* inc_test_pbproc_h */
diff --git a/cesar/mac/pbproc/test/maximus/py/host_test_pbproc.py b/cesar/mac/pbproc/test/maximus/py/host_test_pbproc.py
new file mode 100644
index 0000000000..2d55c183ee
--- /dev/null
+++ b/cesar/mac/pbproc/test/maximus/py/host_test_pbproc.py
@@ -0,0 +1,85 @@
+#!/usr/bin/python
+import sys;
+sys.path.append ('../../../../maximus/python')
+sys.path.append ('../../../../maximus/python/obj')
+
+trace = { }
+for i in ('phy', 'ca', 'pbproc'):
+ o = '--%s-trace' % i
+ if o in sys.argv:
+ trace[i] = True
+ sys.argv.remove (o)
+
+bp_tck = 25000000 / 50
+before_bp_tck = bp_tck * 3 / 4
+
+from interface import *
+from test_pbproc import *
+
+maximus = Maximus ()
+maximus.init (sys.argv + ['-e', 'obj/test_pbproc.elf'])
+
+sta1 = maximus.create_sta ()
+sta1.set_name ('sta1')
+sta2 = maximus.create_sta ()
+sta2.set_name ('sta2')
+
+t1 = TestPBProc (maximus, sta1)
+t2 = TestPBProc (maximus, sta2)
+
+sta1.debug ()
+sta2.debug ()
+
+t1.set_config (tei = 1, snid = 1)
+t2.set_config (tei = 2, snid = 1)
+
+beacon_period = dict (glid = 0xff, coex = 2)
+
+t1.add_beacon_period (start_date = 0, **beacon_period)
+t1.add_beacon_period (start_date = bp_tck, **beacon_period)
+t1.add_beacon_period (start_date = 2 * bp_tck, **beacon_period)
+t2.add_beacon_period (start_date = 0, **beacon_period)
+t2.add_beacon_period (start_date = bp_tck, **beacon_period)
+t2.add_beacon_period (start_date = 2 * bp_tck, **beacon_period)
+
+t1.seg = t2.seg = 0
+t1.add_seg (mme = False, lid = 0, tei = 2, seg_nb = 16, gen = 0); t1.seg += 16
+t1.add_seg (mme = True, lid = 0, tei = 2, seg_nb = 4, gen = 0); t1.seg += 4
+t1.add_seg (mme = False, lid = 1, tei = 2, seg_nb = 4, gen = 0); t1.seg += 4
+t2.add_seg (mme = False, lid = 0, tei = 1, seg_nb = 16, gen = 0); t2.seg += 16
+
+t1.rx_seg_refill (seg_nb = 25)
+t2.rx_seg_refill (seg_nb = 25)
+t1.activate ()
+t2.activate ()
+
+stop = 0
+
+def get_seg_cb (r, seg_nb):
+ assert (r.seg_nb == seg_nb)
+ global stop
+ stop += 1
+t1.get_seg_async (lambda r: get_seg_cb (r, t2.seg), seg_nb = t2.seg)
+t2.get_seg_async (lambda r: get_seg_cb (r, t1.seg), seg_nb = t1.seg)
+
+bp = 0
+while stop != 2:
+ bp += 1
+ maximus.wait (before_bp_tck)
+ t1.prepare_beacon (lid = 0xfd)
+ maximus.wait (bp_tck - before_bp_tck)
+ if bp == 1:
+ t2.set_tonemap (RX, tei = 1, tmi = 5, bits = 10)
+ t1.set_tonemap (TX, tei = 2, tmi = 5, bits = 10)
+ t1.set_tonemap (RX, tei = 2, tmi = 6, bits = 6)
+ t2.set_tonemap (TX, tei = 1, tmi = 6, bits = 6)
+ t1.add_beacon_period (start_date = (bp + 2) * bp_tck, **beacon_period)
+ t2.add_beacon_period (start_date = (bp + 2) * bp_tck, **beacon_period)
+
+t1.activate (False)
+t2.activate (False)
+
+print 'trace sta1:'; sys.stdout.flush ()
+t1.trace_dump (**trace)
+print '\ntrace sta2:'; sys.stdout.flush ()
+t2.trace_dump (**trace)
diff --git a/cesar/mac/pbproc/test/maximus/py/test_coll.py b/cesar/mac/pbproc/test/maximus/py/test_coll.py
new file mode 100644
index 0000000000..df3033aa7c
--- /dev/null
+++ b/cesar/mac/pbproc/test/maximus/py/test_coll.py
@@ -0,0 +1,94 @@
+#!/usr/bin/python
+import sys;
+sys.path.append ('../../../../maximus/python')
+sys.path.append ('../../../../maximus/python/obj')
+
+trace = { }
+for i in ('phy', 'ca', 'pbproc'):
+ o = '--%s-trace' % i
+ if o in sys.argv:
+ trace[i] = True
+ sys.argv.remove (o)
+
+bp_tck = 10 * 25000000 / 50
+
+from interface import *
+from test_pbproc import *
+
+maximus = Maximus ()
+maximus.init (sys.argv + ['-e', 'obj/test_pbproc.elf'])
+
+sta1 = maximus.create_sta ()
+sta1.set_name ('sta1')
+sta2 = maximus.create_sta ()
+sta2.set_name ('sta2')
+
+t1 = TestPBProc (maximus, sta1)
+t2 = TestPBProc (maximus, sta2)
+
+sta1.debug ()
+sta2.debug ()
+
+t1.set_config (tei = 1, snid = 1)
+t2.set_config (tei = 2, snid = 1)
+
+beacon_period = dict (glid = 0xff, coex = 2, beacon_period_tck = bp_tck)
+
+t1.add_beacon_period (start_date = 0, **beacon_period)
+t1.add_beacon_period (start_date = bp_tck, **beacon_period)
+t1.add_beacon_period (start_date = 2 * bp_tck, **beacon_period)
+t2.add_beacon_period (start_date = 0, **beacon_period)
+t2.add_beacon_period (start_date = bp_tck, **beacon_period)
+t2.add_beacon_period (start_date = 2 * bp_tck, **beacon_period)
+
+t1.seg = t2.seg = 0
+t1.tei = 1
+t2.tei = 2
+
+def feed (ttx, trx):
+ ttx.add_seg (mme = False, lid = 0, tei = trx.tei, seg_nb = 20, gen = 0); ttx.seg += 20
+ ttx.add_seg (mme = False, lid = 1, tei = trx.tei, seg_nb = 5, gen = 0); ttx.seg += 5
+
+feed (t1, t2)
+feed (t2, t1)
+
+t1.rx_seg_refill (seg_nb = 50)
+t2.rx_seg_refill (seg_nb = 50)
+t1.activate ()
+t2.activate ()
+
+stop = 0
+
+def get_seg_cb (r, ttx, trx):
+ assert (r.seg_nb == ttx.seg)
+ ttx.seg = 0
+ global stop
+ stop += 1
+ feed (ttx, trx)
+ trx.get_seg_async (lambda r: get_seg_cb (r, ttx, trx), seg_nb = ttx.seg)
+
+t1.get_seg_async (lambda r: get_seg_cb (r, t2, t1), seg_nb = t2.seg)
+t2.get_seg_async (lambda r: get_seg_cb (r, t1, t2), seg_nb = t1.seg)
+
+bp = 0
+while stop < 4:
+ bp += 1
+ maximus.wait (bp_tck)
+ if bp == 1:
+ t2.set_tonemap (RX, tei = 1, tmi = 5, bits = 10)
+ t1.set_tonemap (TX, tei = 2, tmi = 5, bits = 10)
+ t1.set_tonemap (RX, tei = 2, tmi = 6, bits = 6)
+ t2.set_tonemap (TX, tei = 1, tmi = 6, bits = 6)
+ t1.add_beacon_period (start_date = (bp + 2) * bp_tck, **beacon_period)
+ t2.add_beacon_period (start_date = (bp + 2) * bp_tck, **beacon_period)
+
+t1.activate (False)
+t2.activate (False)
+
+print 'trace sta1:'; sys.stdout.flush ()
+t1.trace_dump (**trace)
+print '\ntrace sta2:'; sys.stdout.flush ()
+t2.trace_dump (**trace)
+
+sta1.remove()
+sta2.remove()
diff --git a/cesar/mac/pbproc/test/maximus/py/test_pbproc.py b/cesar/mac/pbproc/test/maximus/py/test_pbproc.py
new file mode 100644
index 0000000000..3025494913
--- /dev/null
+++ b/cesar/mac/pbproc/test/maximus/py/test_pbproc.py
@@ -0,0 +1,63 @@
+RX = False
+TX = True
+
+class TestPBProc:
+ """PBProc test wrapper."""
+ def __init__ (self, maximus, sta):
+ self.maximus = maximus
+ self.sta = sta
+
+ def create_fcall (self, name, **args):
+ """Create a function call with given name and parameters."""
+ fc = self.maximus.create_fcall (name)
+ for (n, v) in args.iteritems ():
+ if type (v) is bool:
+ fc.add_param_bool (n, v)
+ elif type (v) is int:
+ fc.add_param_ulong (n, v)
+ else:
+ raise TypeError
+ return fc
+
+ def set_config (self, **args):
+ self.create_fcall ('set_config', **args).send (self.sta)
+
+ def add_seg (self, mme, lid, tei, seg_nb, gen):
+ self.create_fcall ('add_seg', mme = mme, lid = lid, tei = tei,
+ seg_nb = seg_nb, gen = gen).send (self.sta)
+
+ def prepare_beacon (self, **args):
+ self.create_fcall ('prepare_beacon', **args).send (self.sta)
+
+ def get_seg (self, **args):
+ m = self.create_fcall ('get_seg', **args)
+ m.send (self.sta)
+ class get_seg_rsp:
+ def __init__ (self, m):
+ self.seg_nb = m.bind_param_ulong ('seg_nb')
+ return get_seg_rsp (m)
+
+ def get_seg_async (self, cb, **args):
+ m = self.create_fcall ('get_seg', **args)
+ class get_seg_rsp:
+ def __init__ (self, m):
+ self.seg_nb = m.bind_param_ulong ('seg_nb')
+ def get_seg_cb (msg):
+ cb (get_seg_rsp (msg))
+ m.set_cb (get_seg_cb)
+ m.send_async (self.sta)
+
+ def rx_seg_refill (self, **args):
+ self.create_fcall ('rx_seg_refill', **args).send (self.sta)
+
+ def add_beacon_period (self, **args):
+ self.create_fcall ('add_beacon_period', **args).send (self.sta)
+
+ def set_tonemap (self, tx, **args):
+ self.create_fcall ('set_tonemap', tx = tx, **args).send (self.sta)
+
+ def activate (self, activate = True):
+ self.create_fcall ('activate', activate = activate).send (self.sta)
+
+ def trace_dump (self, **args):
+ self.create_fcall ('trace_dump', **args).send (self.sta)
diff --git a/cesar/mac/pbproc/test/maximus/src/add_beacon_period.c b/cesar/mac/pbproc/test/maximus/src/add_beacon_period.c
new file mode 100644
index 0000000000..21f1550925
--- /dev/null
+++ b/cesar/mac/pbproc/test/maximus/src/add_beacon_period.c
@@ -0,0 +1,101 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file src/add_beacon_period.c
+ * \brief Add beacon period fcall.
+ * \ingroup test
+ */
+#include "common/std.h"
+
+#include "host/fcall.h"
+#include "mac/common/mfs.h"
+#include "mac/common/store.h"
+#include "mac/common/timings.h"
+
+#include "inc/test_pbproc.h"
+#include "inc/add_beacon_period.h"
+#include "inc/context.h"
+
+static int
+test_pbproc_add_beacon_period_fcall (fcall_ctx_t *fcall,
+ fcall_param_t **param, sci_msg_t **msg,
+ void *data);
+
+void
+test_pbproc_add_beacon_period_init (test_pbproc_t *ctx)
+{
+ dbg_assert (ctx);
+ fcall_register (my_station.fcall, "add_beacon_period",
+ test_pbproc_add_beacon_period_fcall, ctx);
+}
+
+static void
+test_pbproc_add_beacon_period (test_pbproc_t *ctx, u32 start_date, uint glid,
+ mac_coexistence_mode_t coex,
+ uint beacon_period_tck)
+{
+ dbg_assert (ctx);
+ /* Get and fill schedule. */
+ uint schedule_index = ctx->beacon_periods_nb == 0 ? 0 :
+ ((ctx->beacon_periods[ctx->beacon_periods_nb - 1].schedule_index + 1)
+ % (TEST_PBPROC_NB_BEACON_PERIOD + 1));
+ ca_schedule_t *sched = ca_alloc_get_schedule (ctx->ca, schedule_index);
+ sched->coexistence_mode = coex;
+ sched->nek_switch = 0;
+ sched->allocations_nb = 1;
+ sched->allocations[0].end_offset_tck = beacon_period_tck
+ ? beacon_period_tck : MAC_MS_TO_TCK (1000) / 50;
+ sched->allocations[0].glid = glid;
+ /* Update the beacon period table. */
+ if (ctx->beacon_periods_nb == TEST_PBPROC_NB_BEACON_PERIOD)
+ {
+ uint i;
+ for (i = 0; i < TEST_PBPROC_NB_BEACON_PERIOD - 1; i++)
+ ctx->beacon_periods[i] = ctx->beacon_periods[i + 1];
+ ctx->beacon_periods_nb--;
+ }
+ ctx->beacon_periods[ctx->beacon_periods_nb].start_date = start_date;
+ ctx->beacon_periods[ctx->beacon_periods_nb].schedule_index =
+ schedule_index;
+ ctx->beacon_periods_nb++;
+ /* Use the new one. */
+ ca_alloc_update_beacon_periods (ctx->ca, ctx->beacon_periods,
+ ctx->beacon_periods_nb);
+}
+
+static int
+test_pbproc_add_beacon_period_fcall (fcall_ctx_t *fcall,
+ fcall_param_t **param, sci_msg_t **msg,
+ void *data)
+{
+ dbg_assert (fcall);
+ dbg_assert (param && *param);
+ dbg_assert (msg && *msg);
+ test_pbproc_t *ctx = (void *) data;
+ dbg_assert (ctx);
+ /* Read message. */
+ u32 start_date;
+ uint glid;
+ uint beacon_period_tck;
+ mac_coexistence_mode_t coex;
+ if (!test_pbproc_fcall_bind_long ("start_date", start_date))
+ return -1;
+ if (!test_pbproc_fcall_bind_long ("glid", glid))
+ return -1;
+ if (!test_pbproc_fcall_bind_long ("coex", coex))
+ coex = MAC_COEXISTENCE_AV_ONLY_MODE;
+ if (!test_pbproc_fcall_bind_long ("beacon_period_tck", beacon_period_tck))
+ beacon_period_tck = 0;
+ /* Add beacon period. */
+ test_pbproc_add_beacon_period (ctx, start_date, glid, coex,
+ beacon_period_tck);
+ /* Return. */
+ fcall_param_reset (*param);
+ return 0;
+}
+
diff --git a/cesar/mac/pbproc/test/maximus/src/add_seg.c b/cesar/mac/pbproc/test/maximus/src/add_seg.c
new file mode 100644
index 0000000000..3c7e746e92
--- /dev/null
+++ b/cesar/mac/pbproc/test/maximus/src/add_seg.c
@@ -0,0 +1,111 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file src/add_seg.c
+ * \brief Add segments fcall.
+ * \ingroup test
+ */
+#include "common/std.h"
+
+#include "host/fcall.h"
+#include "mac/common/mfs.h"
+#include "mac/common/store.h"
+
+#include "inc/test_pbproc.h"
+#include "inc/add_seg.h"
+#include "inc/context.h"
+
+static int
+test_pbproc_add_seg_fcall (fcall_ctx_t *fcall, fcall_param_t **param,
+ sci_msg_t **msg, void *data);
+
+void
+test_pbproc_add_seg_init (test_pbproc_t *ctx)
+{
+ dbg_assert (ctx);
+ fcall_register (my_station.fcall, "add_seg", test_pbproc_add_seg_fcall,
+ ctx);
+}
+
+static void
+test_pbproc_add_seg (test_pbproc_t *ctx, bool mme, uint lid, uint tei,
+ uint seg_nb, uint gen)
+{
+ mfs_tx_t *mfs;
+ bool added;
+ dbg_assert (ctx);
+ dbg_assert (seg_nb > 0);
+ /* Locate the MFS. */
+ mfs = mac_store_mfs_add_tx (ctx->store, tei == MAC_TEI_BCAST, mme,
+ mme ? MAC_LID_NONE : lid, tei, &added);
+ if (added)
+ ca_mfs_add (ctx->ca, mfs);
+ /* Generate segments. */
+ blk_t *blk_first, *blk_last;
+ blk_first = blk_alloc_desc_range (seg_nb, &blk_last);
+ pb_t *seg_first = PB_FROM_BLK (blk_first);
+ pb_t *seg_last = PB_FROM_BLK (blk_last);
+ pb_t *seg, *lseg;
+ uint i;
+ for (lseg = NULL, seg = seg_first, i = 0;
+ lseg != seg_last;
+ lseg = seg, seg = seg->next, i++)
+ {
+ /* Fill header. */
+ seg->header.ssn = mfs->next_ssn++;
+ seg->header.mfbo = 0;
+ seg->header.vpbf = true;
+ seg->header.mmqf = mme;
+ seg->header.mfbf = false;
+ seg->header.opsf = false;
+ seg->header.rsvd = 0;
+ /* Generate pattern. */
+ seg->data[0] = 0x42;
+ seg->data[1] = 0x5a;
+ seg->data[2] = gen;
+ seg->data[3] = i;
+ }
+ /* Insert them. */
+ pbproc_mfs_insert (mfs, seg_first, seg_last, seg_nb, mfs->cap);
+ pbproc_mfs_provide (mfs, seg_nb);
+ /* Update CA. */
+ ca_mfs_update (ctx->ca, mfs);
+ /* Release the MFS reference. */
+ blk_release (mfs);
+}
+
+static int
+test_pbproc_add_seg_fcall (fcall_ctx_t *fcall, fcall_param_t **param,
+ sci_msg_t **msg, void *data)
+{
+ dbg_assert (fcall);
+ dbg_assert (param && *param);
+ dbg_assert (msg && *msg);
+ test_pbproc_t *ctx = (void *) data;
+ dbg_assert (ctx);
+ /* Read message. */
+ uint seg_nb, tei, lid, gen;
+ bool mme;
+ if (!test_pbproc_fcall_bind ("mme", mme))
+ return -1;
+ if (!test_pbproc_fcall_bind_long ("lid", lid) || !MAC_LID_IS_XLID (lid))
+ return -1;
+ if (!test_pbproc_fcall_bind_long ("tei", tei)
+ || !(MAC_TEI_IS_STA (tei) || tei == MAC_TEI_BCAST))
+ return -1;
+ if (!test_pbproc_fcall_bind_long ("seg_nb", seg_nb))
+ return -1;
+ if (!test_pbproc_fcall_bind_long ("gen", gen))
+ return -1;
+ /* Add segments. */
+ test_pbproc_add_seg (ctx, mme, lid, tei, seg_nb, gen);
+ /* Return. */
+ fcall_param_reset (*param);
+ return 0;
+}
+
diff --git a/cesar/mac/pbproc/test/maximus/src/get_seg.c b/cesar/mac/pbproc/test/maximus/src/get_seg.c
new file mode 100644
index 0000000000..935a0435b7
--- /dev/null
+++ b/cesar/mac/pbproc/test/maximus/src/get_seg.c
@@ -0,0 +1,104 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file src/get_seg.c
+ * \brief Get segments fcall.
+ * \ingroup test
+ */
+#include "common/std.h"
+
+#include "host/fcall.h"
+#include "mac/common/mfs.h"
+#include "mac/common/store.h"
+
+#include "inc/test_pbproc.h"
+#include "inc/get_seg.h"
+#include "inc/context.h"
+
+static int
+test_pbproc_get_seg_fcall (fcall_ctx_t *fcall, fcall_param_t **param,
+ sci_msg_t **msg, void *data);
+
+static void
+test_pbproc_get_seg_handler (test_pbproc_t *ctx, test_pbproc_msg_t *msg);
+
+static void
+test_pbproc_get_seg_fcall_return (test_pbproc_t *ctx, uint seg_nb);
+
+void
+test_pbproc_get_seg_init (test_pbproc_t *ctx)
+{
+ dbg_assert (ctx);
+ fcall_register (my_station.fcall, "get_seg", test_pbproc_get_seg_fcall,
+ ctx);
+ ctx->msg_handlers[TEST_PBPROC_MSG_ID_GET_SEG] =
+ test_pbproc_get_seg_handler;
+}
+
+static void
+test_pbproc_get_seg_handler (test_pbproc_t *ctx, test_pbproc_msg_t *msg)
+{
+ dbg_assert (ctx);
+ dbg_assert (msg->id == TEST_PBPROC_MSG_ID_GET_SEG);
+ uint seg_nb = msg->msg.get_seg.seg_nb;
+ dbg_assert (seg_nb > 0);
+ /* Install callback. */
+ ctx->rx_cb = test_pbproc_default_rx_cb;
+ /* Wait until enough segments are received. */
+ uint base = ctx->rx_pb_nb;
+ while (ctx->rx_pb_nb < base + seg_nb)
+ dbg_check (cyg_semaphore_wait (&ctx->event_sem));
+ /* Uninstall callback. */
+ ctx->rx_cb = NULL;
+ /* Return. */
+ test_pbproc_get_seg_fcall_return (ctx, ctx->rx_pb_nb - base);
+}
+
+static int
+test_pbproc_get_seg_fcall (fcall_ctx_t *fcall, fcall_param_t **param,
+ sci_msg_t **msg, void *data)
+{
+ dbg_assert (fcall);
+ dbg_assert (param && *param);
+ dbg_assert (msg && *msg);
+ test_pbproc_t *ctx = (void *) data;
+ dbg_assert (ctx);
+ /* Only one message at a time. */
+ if (ctx->static_msg.id != TEST_PBPROC_MSG_ID_NONE)
+ return -1;
+ ctx->static_msg.id = TEST_PBPROC_MSG_ID_GET_SEG;
+ /* Read message. */
+ test_pbproc_msg_get_seg_t *m = &ctx->static_msg.msg.get_seg;
+ if (!test_pbproc_fcall_bind_long ("seg_nb", m->seg_nb))
+ return -1;
+ /* Message accepted, will return later. */
+ fcall_param_set_async (*param, 1);
+ dbg_assert (ctx->fcall == NULL);
+ ctx->fcall = fcall;
+ ctx->fcall_msg_id = fcall_param_get_msg_id (*param);
+ /* Post message. */
+ dbg_check (cyg_mbox_put (ctx->mbox, &ctx->static_msg));
+ return 0;
+}
+
+static void
+test_pbproc_get_seg_fcall_return (test_pbproc_t *ctx, uint seg_nb)
+{
+ fcall_param_t param;
+ sci_msg_t msg;
+ u8 buffer[64];
+ dbg_assert (ctx);
+ dbg_assert (ctx->fcall);
+ fcall_param_init (&param, "get_seg", ctx->fcall_msg_id);
+ sci_msg_init (&msg, buffer, sizeof (buffer));
+ fcall_param_reset (&param);
+ test_pbproc_fcall_add_long ("seg_nb", seg_nb);
+ dbg_check (fcall_return (ctx->fcall, &param, &msg) != -1);
+ ctx->fcall = NULL;
+}
+
diff --git a/cesar/mac/pbproc/test/maximus/src/prepare_beacon.c b/cesar/mac/pbproc/test/maximus/src/prepare_beacon.c
new file mode 100644
index 0000000000..c7abc2b4cf
--- /dev/null
+++ b/cesar/mac/pbproc/test/maximus/src/prepare_beacon.c
@@ -0,0 +1,98 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file src/prepare_beacon.c
+ * \brief Prepare beacon fcall.
+ * \ingroup test
+ */
+#include "common/std.h"
+
+#include "host/fcall.h"
+#include "mac/common/mfs.h"
+#include "mac/common/store.h"
+
+#include "inc/test_pbproc.h"
+#include "inc/prepare_beacon.h"
+#include "inc/context.h"
+
+static int
+test_pbproc_prepare_beacon_fcall (fcall_ctx_t *fcall, fcall_param_t **param,
+ sci_msg_t **msg, void *data);
+
+void
+test_pbproc_prepare_beacon_init (test_pbproc_t *ctx)
+{
+ dbg_assert (ctx);
+ fcall_register (my_station.fcall, "prepare_beacon",
+ test_pbproc_prepare_beacon_fcall, ctx);
+}
+
+static void
+test_pbproc_prepare_beacon (test_pbproc_t *ctx, uint lid, u32 gen)
+{
+ mfs_tx_t *mfs;
+ bool added;
+ dbg_assert (ctx);
+ /* Locate the MFS. */
+ mfs = mac_store_mfs_add_tx (ctx->store, MAC_TEI_BCAST, false, lid, 0xff,
+ &added);
+ if (added)
+ {
+ mfs->beacon = true;
+ mfs->cap = lid == MAC_LID_SPC_CENTRAL ? 3 : 2;
+ ca_mfs_add (ctx->ca, mfs);
+ }
+ /* Generate segments. */
+ blk_t *blk;
+ blk = blk_alloc_desc ();
+ pb_beacon_t *seg = PARENT_OF (pb_beacon_t, blk, blk);
+ /* Generate pattern. */
+ seg->first_data_word = 0x04052006;
+ seg->data[0] = 0x42;
+ seg->data[1] = 0xa5;
+ seg->data[2] = gen;
+ seg->data[3] = 0;
+ /* Prepare beacon. */
+ pbproc_tx_beacon_params_t params = {
+ { 0x0123, 0x1234, 0x2345, 0x3456 }, NULL
+ };
+ ca_mfs_hold (ctx->ca, mfs);
+ pbproc_mfs_beacon_prepare (ctx->pbproc, mfs, seg, &params);
+ /* Update CA (may be useful if the MFS is unheld before beacon payload is
+ * added.. */
+ ca_mfs_update (ctx->ca, mfs);
+ /* Release the MFS reference. */
+ blk_release (mfs);
+}
+
+static int
+test_pbproc_prepare_beacon_fcall (fcall_ctx_t *fcall, fcall_param_t **param,
+ sci_msg_t **msg, void *data)
+{
+ dbg_assert (fcall);
+ dbg_assert (param && *param);
+ dbg_assert (msg && *msg);
+ test_pbproc_t *ctx = (void *) data;
+ dbg_assert (ctx);
+ /* Read message. */
+ u32 gen;
+ uint lid;
+ if (!test_pbproc_fcall_bind_long ("lid", lid))
+ lid = MAC_LID_SPC_CENTRAL;
+ if (!(MAC_LID_IS_GLID (lid) || lid == MAC_LID_SPC_CENTRAL
+ || lid == MAC_LID_DISCOVER))
+ return -1;
+ if (!test_pbproc_fcall_bind_long ("gen", gen))
+ gen = 0;
+ /* Prepare beacon. */
+ test_pbproc_prepare_beacon (ctx, lid, gen);
+ /* Return. */
+ fcall_param_reset (*param);
+ return 0;
+}
+
diff --git a/cesar/mac/pbproc/test/maximus/src/set_tonemap.c b/cesar/mac/pbproc/test/maximus/src/set_tonemap.c
new file mode 100644
index 0000000000..7e7f0b60f8
--- /dev/null
+++ b/cesar/mac/pbproc/test/maximus/src/set_tonemap.c
@@ -0,0 +1,105 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2008 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file src/set_tonemap.c
+ * \brief Set tonemap fcall.
+ * \ingroup test
+ */
+#include "common/std.h"
+
+#include "host/fcall.h"
+#include "mac/common/store.h"
+
+#include "inc/test_pbproc.h"
+#include "inc/set_tonemap.h"
+#include "inc/context.h"
+
+#include <string.h>
+
+static int
+test_pbproc_set_tonemap_fcall (fcall_ctx_t *fcall,
+ fcall_param_t **param, sci_msg_t **msg,
+ void *data);
+
+void
+test_pbproc_set_tonemap_init (test_pbproc_t *ctx)
+{
+ dbg_assert (ctx);
+ fcall_register (my_station.fcall, "set_tonemap",
+ test_pbproc_set_tonemap_fcall, ctx);
+}
+
+static void
+test_pbproc_set_tonemap (test_pbproc_t *ctx, bool tx, uint tei, uint tmi,
+ uint bits)
+{
+ dbg_assert (ctx);
+ dbg_assert (MAC_TEI_IS_STA (tei));
+ dbg_assert (tmi < TONEMAP_INDEX_NB);
+ /* Create/get STA. */
+ mac_store_sta_add (ctx->store, tei);
+ sta_t *sta = mac_store_sta_get (ctx->store, tei);
+ dbg_assert (sta);
+ tonemaps_t *tms = tx ? sta->tx_tonemaps : sta->rx_tonemaps;
+ /* Release any older tonemap. */
+ if (tms->tm[tmi])
+ tonemap_release (tms, tmi);
+ /* Create the new tonemap. */
+ if (tmi >= PHY_MOD_ROBO_NB)
+ {
+ /* Create a tonemap. */
+ tonemap_t *tm = tonemap_alloc ();
+ tms->tm[tmi] = tm;
+ tm->strict = false;
+ tm->cpf = true;
+ tm->fecrate = PHY_FEC_RATE_16_21;
+ tm->gil = PHY_GIL_417;
+ tm->bits_per_symbol = bits * ctx->config.tonemask_info.carrier_nb;
+ tm->ble = tonemap_ble (tm->bits_per_symbol, tm->fecrate,
+ CONST_UF32 (0.0), tm->gil);
+ /* Fill tonemap. */
+ static const u8 tm_data[] = {
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0, 0x55, 0, 0x66, 0, 0x77
+ };
+ dbg_assert (bits < COUNT (tm_data) && tm_data[bits]);
+ memset (tm->tmdma_desc_head->data, tm_data[bits], BLK_SIZE);
+ memset (tm->tmdma_desc_head->next->data, tm_data[bits], BLK_SIZE / 2);
+ }
+ /* Done. */
+ tms->default_tmi = tmi;
+ blk_release (sta);
+}
+
+static int
+test_pbproc_set_tonemap_fcall (fcall_ctx_t *fcall,
+ fcall_param_t **param, sci_msg_t **msg,
+ void *data)
+{
+ dbg_assert (fcall);
+ dbg_assert (param && *param);
+ dbg_assert (msg && *msg);
+ test_pbproc_t *ctx = (void *) data;
+ dbg_assert (ctx);
+ /* Read message. */
+ bool tx;
+ uint tei, tmi, bits = 0;
+ if (!test_pbproc_fcall_bind ("tx", tx))
+ return -1;
+ if (!test_pbproc_fcall_bind_long ("tei", tei))
+ return -1;
+ if (!test_pbproc_fcall_bind_long ("tmi", tmi))
+ return -1;
+ if (!test_pbproc_fcall_bind_long ("bits", bits) && tmi >= PHY_MOD_ROBO_NB)
+ return -1;
+ /* Add beacon period. */
+ test_pbproc_set_tonemap (ctx, tx, tei, tmi, bits);
+ /* Return. */
+ fcall_param_reset (*param);
+ return 0;
+}
+
diff --git a/cesar/mac/pbproc/test/maximus/src/test_pbproc.c b/cesar/mac/pbproc/test/maximus/src/test_pbproc.c
new file mode 100644
index 0000000000..65c9198610
--- /dev/null
+++ b/cesar/mac/pbproc/test/maximus/src/test_pbproc.c
@@ -0,0 +1,303 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file src/test_pbproc.c
+ * \brief PBProc test on Maximus.
+ * \ingroup test
+ */
+#include "common/std.h"
+
+#include "lib/trace.h"
+
+#include "mac/common/mfs.h"
+
+#include "inc/test_pbproc.h"
+#include "inc/context.h"
+
+#include "hal/phy/maximus/inc/maximus_phy_ctx.h"
+#include "mac/ca/inc/context.h"
+#include "mac/pbproc/inc/context.h"
+
+#define TEST_PBPROC_PRIORITY 16
+
+/** Global test PBProc context. */
+static test_pbproc_t test_pbproc_global;
+
+static void
+test_pbproc_init (test_pbproc_t *ctx);
+
+static void
+test_pbproc_init_pbproc (test_pbproc_t *ctx);
+
+void
+test_pbproc_uninit_pbproc (test_pbproc_t *ctx);
+
+static void
+test_pbproc_thread (cyg_addrword_t data);
+
+void
+test_pbproc_rx_cb (void *user, mfs_t *mfs, mfs_t *mfs_mme,
+ const pbproc_rx_params_t *rx_params,
+ pb_t *pb_first, pb_t *pb_last,
+ uint pb_nb, pb_t *chandata_first, uint chandata_nb)
+{
+ dbg_assert_ptr (user);
+ test_pbproc_t *ctx = user;
+ dbg_assert_ptr (rx_params);
+ if (pb_nb)
+ {
+ dbg_assert_ptr (pb_first);
+ dbg_assert_ptr (pb_last);
+ }
+ else
+ dbg_assert (pb_first == NULL && pb_last == NULL);
+ uint pb_null = 0, pb_valid = 0;
+ pb_t *pb, *pbl;
+ for (pb = pb_first, pbl = NULL;
+ pbl != pb_last;
+ pbl = pb, pb = pb->next)
+ {
+ if (pb->header.vpbf)
+ pb_valid++;
+ else
+ pb_null++;
+ }
+ dbg_assert (pb_valid + pb_null == pb_nb);
+ ctx->rx_pb_nb += pb_valid;
+ if (ctx->rx_cb)
+ ctx->rx_cb (user, mfs, mfs_mme, rx_params, pb_first, pb_last, pb_nb,
+ chandata_first, chandata_nb);
+ else
+ dbg_assert (0);
+}
+
+void
+test_pbproc_default_rx_cb (void *user, mfs_t *mfs, mfs_t *mfs_mme,
+ const pbproc_rx_params_t *rx_params,
+ pb_t *pb_first, pb_t *pb_last, uint pb_nb,
+ pb_t *chandata_first, uint chandata_nb)
+{
+ dbg_assert_ptr (user);
+ dbg_assert_print (chandata_nb == 0, "Not handled yet");
+ test_pbproc_t *ctx = user;
+ pbproc_rx_segment_refill (ctx->pbproc, pb_first, pb_last, pb_nb);
+ /* This is forbidden if running under ISR. */
+ cyg_semaphore_post (&ctx->event_sem);
+}
+
+void
+test_pbproc_rx_beacon_cb (void *user, pb_beacon_t *pb,
+ pbproc_rx_beacon_params_t *params)
+{
+ dbg_assert_ptr (user);
+ dbg_assert_ptr (pb);
+ dbg_assert (params == (void *) (pb->data + MAC_PB136_BYTES));
+ blk_release_desc (&pb->blk);
+}
+
+static int
+test_pbproc_activate_fcall (fcall_ctx_t *fcall, fcall_param_t **param,
+ sci_msg_t **msg, void *data)
+{
+ dbg_assert (fcall);
+ dbg_assert (param && *param);
+ dbg_assert (msg && *msg);
+ test_pbproc_t *ctx = (void *) data;
+ dbg_assert (ctx);
+ /* Read message. */
+ bool activate;
+ if (!test_pbproc_fcall_bind ("activate", activate))
+ activate = true;
+ /* Activate. */
+ pbproc_activate (ctx->pbproc, activate);
+ /* Return. */
+ fcall_param_reset (*param);
+ return 0;
+}
+
+static int
+test_pbproc_set_config_fcall (fcall_ctx_t *fcall, fcall_param_t **param,
+ sci_msg_t **msg, void *data)
+{
+ dbg_assert (fcall);
+ dbg_assert (param && *param);
+ dbg_assert (msg && *msg);
+ test_pbproc_t *ctx = (void *) data;
+ dbg_assert (ctx);
+ /* Read message. */
+ uint tei, snid;
+ if (test_pbproc_fcall_bind_long ("tei", tei))
+ ctx->config.tei = tei;
+ if (test_pbproc_fcall_bind_long ("snid", snid))
+ ctx->config.snid = snid;
+ /* Initialise PBProc. */
+ if (!ctx->pbproc)
+ {
+ ctx->config.seed = ctx->config.snid << 8 | ctx->config.tei;
+ test_pbproc_init_pbproc (ctx);
+ }
+ /* Return. */
+ fcall_param_reset (*param);
+ return 0;
+}
+
+static int
+test_pbproc_rx_seg_refill_fcall (fcall_ctx_t *fcall, fcall_param_t **param,
+ sci_msg_t **msg, void *data)
+{
+ dbg_assert (fcall);
+ dbg_assert (param && *param);
+ dbg_assert (msg && *msg);
+ test_pbproc_t *ctx = (void *) data;
+ dbg_assert (ctx);
+ /* Read message. */
+ uint seg_nb;
+ if (!test_pbproc_fcall_bind_long ("seg_nb", seg_nb))
+ return -1;
+ /* Refill. */
+ blk_t *first, *last;
+ first = blk_alloc_desc_range (seg_nb, &last);
+ pbproc_rx_segment_refill (ctx->pbproc, PB_FROM_BLK (first),
+ PB_FROM_BLK (last), seg_nb);
+ /* Return. */
+ fcall_param_reset (*param);
+ return 0;
+}
+
+static int
+test_pbproc_trace_dump_fcall (fcall_ctx_t *fcall, fcall_param_t **param,
+ sci_msg_t **msg, void *data)
+{
+ dbg_assert (fcall);
+ dbg_assert (param && *param);
+ dbg_assert (msg && *msg);
+ test_pbproc_t *ctx = (void *) data;
+ dbg_assert (ctx);
+ /* Read message. */
+ bool phy, ca, pbproc;
+ if (!test_pbproc_fcall_bind ("phy", phy))
+ phy = false;
+ if (!test_pbproc_fcall_bind ("ca", ca))
+ ca = false;
+ if (!test_pbproc_fcall_bind ("pbproc", pbproc))
+ pbproc = false;
+ /* Dump traces. */
+ if (!phy && !ca && !pbproc)
+ pbproc = true;
+ if (phy)
+ trace_buffer_dbg_dump (&ctx->pbproc->phy->trace);
+ if (ca)
+ trace_buffer_dbg_dump (&ctx->pbproc->ca->trace);
+ if (pbproc)
+ trace_buffer_dbg_dump (&ctx->pbproc->trace);
+ /* Return. */
+ fcall_param_reset (*param);
+ return 0;
+}
+
+static void
+test_pbproc_init (test_pbproc_t *ctx)
+{
+ dbg_assert (ctx);
+ /* Rnd, config, PBProc (initialised later)... */
+ lib_rnd_init (ctx->rnd, 1234);
+ mac_config_init (&ctx->config);
+ ctx->config.tei = 1;
+ ctx->config.snid = 1;
+ ctx->store = NULL;
+ ctx->pbproc = NULL;
+ ctx->ca = NULL;
+ /* Beacon period. */
+ ctx->beacon_periods_nb = 0;
+ /* Semaphore, mbox... */
+ cyg_semaphore_init (&ctx->event_sem, 0);
+ cyg_mbox_create (&ctx->mbox, &ctx->mbox_storage);
+ ctx->static_msg.id = TEST_PBPROC_MSG_ID_NONE;
+ int i;
+ for (i = 0; i < TEST_PBPROC_MSG_ID_NONE; i++)
+ ctx->msg_handlers[i] = NULL;
+ /* Callbacks... */
+ ctx->rx_cb = NULL;
+ ctx->rx_pb_nb = 0;
+ /* Fcall... */
+ ctx->fcall = NULL;
+ ctx->fcall_msg_id = 0;
+ /* Init modules. */
+ test_pbproc_add_seg_init (ctx);
+ test_pbproc_prepare_beacon_init (ctx);
+ test_pbproc_get_seg_init (ctx);
+ test_pbproc_add_beacon_period_init (ctx);
+ test_pbproc_set_tonemap_init (ctx);
+ fcall_register (my_station.fcall, "activate", test_pbproc_activate_fcall,
+ ctx);
+ fcall_register (my_station.fcall, "set_config",
+ test_pbproc_set_config_fcall, ctx);
+ fcall_register (my_station.fcall, "rx_seg_refill",
+ test_pbproc_rx_seg_refill_fcall, ctx);
+ fcall_register (my_station.fcall, "trace_dump",
+ test_pbproc_trace_dump_fcall, ctx);
+ /* Go. */
+ cyg_thread_create (TEST_PBPROC_PRIORITY, &test_pbproc_thread,
+ (cyg_addrword_t) ctx, "test_pbproc", ctx->thread_stack,
+ COUNT (ctx->thread_stack), &ctx->thread,
+ &ctx->thread_storage);
+ cyg_thread_resume (ctx->thread);
+}
+
+static void
+test_pbproc_init_pbproc (test_pbproc_t *ctx)
+{
+ trace_init ();
+ ctx->store = mac_store_init ();
+ ctx->pbproc = pbproc_init (&ctx->config, ctx->store);
+ pbproc_init_cb (ctx->pbproc, ctx, test_pbproc_rx_cb,
+ test_pbproc_rx_beacon_cb);
+ ctx->ca = pbproc_get_ca (ctx->pbproc);
+}
+
+void
+test_pbproc_uninit_pbproc (test_pbproc_t *ctx)
+{
+ dbg_assert (ctx);
+ dbg_assert_ptr (ctx->ca);
+ ctx->ca = NULL;
+ dbg_assert_ptr (ctx->pbproc);
+ pbproc_uninit (ctx->pbproc);
+ ctx->pbproc = NULL;
+ dbg_assert_ptr (ctx->store);
+ mac_store_uninit (ctx->store);
+ ctx->store = NULL;
+ trace_uninit ();
+}
+
+static void
+test_pbproc_thread (cyg_addrword_t data)
+{
+ test_pbproc_t *ctx = (void *) data;
+ dbg_assert (ctx);
+ /* Handle messages. */
+ test_pbproc_msg_t *msg;
+ while ((msg = cyg_mbox_get (ctx->mbox)))
+ {
+ dbg_assert (msg->id < TEST_PBPROC_MSG_ID_NONE);
+ dbg_assert (ctx->msg_handlers[msg->id]);
+ ctx->msg_handlers[msg->id] (ctx, msg);
+ msg->id = TEST_PBPROC_MSG_ID_NONE;
+ }
+}
+
+/** Entry point. */
+void
+cyg_user_start (void)
+{
+ //my_station.pipe_log_fd = 1;
+ //my_station.log_level = STATION_LOG_DEBUG;
+ //my_station.log_mask = STATION_LOGTYPE_FCALL;
+ test_pbproc_init (&test_pbproc_global);
+}
+
diff --git a/cesar/mac/pbproc/test/mfs/Makefile b/cesar/mac/pbproc/test/mfs/Makefile
new file mode 100644
index 0000000000..bce539cb94
--- /dev/null
+++ b/cesar/mac/pbproc/test/mfs/Makefile
@@ -0,0 +1,9 @@
+BASE = ../../../..
+
+HOST_PROGRAMS = test_mfs
+test_mfs_SOURCES = test_mfs.c
+test_mfs_MODULES = lib mac/pbproc mac/common
+mac_pbproc_MODULE_SOURCES = mfs.c
+mac_common_MODULE_SOURCES = mfs.c
+
+include $(BASE)/common/make/top.mk
diff --git a/cesar/mac/pbproc/test/mfs/src/test_mfs.c b/cesar/mac/pbproc/test/mfs/src/test_mfs.c
new file mode 100644
index 0000000000..986e7a1b91
--- /dev/null
+++ b/cesar/mac/pbproc/test/mfs/src/test_mfs.c
@@ -0,0 +1,292 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file src/test_mfs.c
+ * \brief Test MFS related functions.
+ * \ingroup test
+ */
+#include "common/std.h"
+
+#include "lib/test.h"
+#include "lib/rnd.h"
+#include "lib/blk.h"
+
+#include "mac/common/mfs.h"
+#include "mac/pbproc/pbproc.h"
+
+#define NB_ITER 1000
+
+struct test_pbproc_t
+{
+ uint next_it;
+ int to_take;
+ pb_t *tx_head, *tx_tail;
+ pb_t *free_head, *free_tail;
+ uint tx_seg_nb;
+ lib_rnd_t rnd[1];
+};
+typedef struct test_pbproc_t test_pbproc_t;
+
+struct test_param_t
+{
+ uint next_it;
+ uint to_take_max;
+ u32 free_r;
+ uint sar_add_min;
+ uint sar_add_max;
+};
+typedef struct test_param_t test_param_t;
+
+void
+test_pbproc_init (test_pbproc_t *ctx)
+{
+ ctx->next_it = 1;
+ ctx->to_take = 0;
+ ctx->tx_head = ctx->tx_tail = NULL;
+ ctx->free_head = ctx->free_tail = NULL;
+ ctx->tx_seg_nb = 0;
+ lib_rnd_init (ctx->rnd, 4321);
+}
+
+void
+test_pbproc_check (test_t t, test_pbproc_t *ctx, mfs_tx_t *mfs)
+{
+ test_within (t);
+ uint ssn = 0;
+ pb_t *p;
+ p = ctx->free_head;
+ test_fail_unless (p);
+ while (1)
+ {
+ if (!mfs->beacon)
+ test_fail_unless (p->header.ssn == ssn++);
+ else
+ {
+ pbproc_tx_beacon_params_t *params =
+ (void *) (p->data + MAC_PB136_BYTES);
+ test_fail_unless (params->bto[0] >= ssn
+ && params->bto[1] == params->bto[0] + 1
+ && params->bto[2] == params->bto[0] + 2
+ && params->bto[3] == params->bto[0] + 3
+ && params->bpsto == NULL);
+ ssn = params->bto[0];
+ }
+ if (p == ctx->free_tail)
+ break;
+ p = p->next;
+ }
+ test_fail_unless (mfs->pending_seg_nb == 0);
+ if (!mfs->beacon)
+ test_fail_unless (ssn + ctx->tx_seg_nb + ctx->to_take + mfs->seg_nb
+ == mfs->next_ssn);
+ test_verbose_print ("freed: %d, total: %d", ssn, mfs->next_ssn);
+}
+
+void
+test_pbproc_uninit (test_pbproc_t *ctx)
+{
+ blk_release_desc_range (&ctx->tx_head->blk, &ctx->tx_tail->blk);
+ blk_release_desc_range (&ctx->free_head->blk, &ctx->free_tail->blk);
+}
+
+void
+test_pbproc_free (test_pbproc_t *ctx)
+{
+ if (!ctx->free_head)
+ ctx->free_head = ctx->tx_head;
+ else
+ ctx->free_tail->next = ctx->tx_head;
+ ctx->free_tail = ctx->tx_tail;
+ ctx->tx_head = ctx->tx_tail = NULL;
+ ctx->tx_seg_nb = 0;
+}
+
+void
+test_pbproc_put_back (test_pbproc_t *ctx, mfs_tx_t *mfs)
+{
+ ctx->tx_tail->next = mfs->head;
+ if (!mfs->head)
+ mfs->tail = ctx->tx_tail;
+ mfs->head = ctx->tx_head;
+ ctx->tx_head = ctx->tx_tail = NULL;
+ mfs->seg_nb += ctx->tx_seg_nb;
+ ctx->tx_seg_nb = 0;
+}
+
+void
+test_pbproc_take (test_pbproc_t *ctx, mfs_tx_t *mfs, uint tt)
+{
+ uint i;
+ for (i = 0; i < tt; i++)
+ {
+ if (!ctx->tx_head)
+ ctx->tx_head = mfs->head;
+ else
+ ctx->tx_tail->next = mfs->head;
+ ctx->tx_tail = mfs->head;
+ if (mfs->head == mfs->tail)
+ {
+ mfs->head = NULL;
+ dbg_invalid_ptr (mfs->tail);
+ }
+ else
+ mfs->head = mfs->head->next;
+ dbg_invalid_ptr (ctx->tx_tail->next); /* simulate next clobber. */
+ ctx->to_take--;
+ ctx->tx_seg_nb++;
+ }
+}
+
+void
+test_pbproc_it (test_t t, test_pbproc_t *ctx, mfs_tx_t *mfs,
+ test_param_t *param)
+{
+ test_within (t);
+ if (!ctx->next_it--)
+ {
+ if (!ctx->to_take && ctx->tx_seg_nb)
+ {
+ if (lib_rnd_flip_coin (ctx->rnd, param->free_r))
+ test_pbproc_free (ctx);
+ else
+ test_pbproc_put_back (ctx, mfs);
+ }
+ else
+ {
+ if (!ctx->to_take)
+ {
+ /* New transmission. */
+ ctx->to_take = lib_rnd_uniform (ctx->rnd, param->to_take_max)
+ + 1;
+ if (mfs->seg_nb == -1)
+ ctx->to_take = 0;
+ else if (ctx->to_take > mfs->seg_nb)
+ ctx->to_take = mfs->seg_nb;
+ test_verbose_print ("to take: %d", ctx->to_take);
+ mfs->seg_nb -= ctx->to_take;
+ }
+ if (ctx->to_take)
+ test_pbproc_take (ctx, mfs, lib_rnd_uniform (
+ ctx->rnd, ctx->to_take) + 1);
+ }
+ ctx->next_it = lib_rnd_uniform (ctx->rnd, param->next_it);
+ }
+}
+
+void
+mfs_basic_test_case (test_t t)
+{
+ uint i;
+ lib_rnd_t rnd[1];
+ test_case_begin (t, "basic");
+ lib_rnd_init (rnd, 1234);
+ /* Test. */
+#define IT() test_pbproc_it (t, &test_pbproc, mfs, &param)
+ test_begin (t, "synchronous")
+ {
+ test_param_t param;
+ param.next_it = 5;
+ param.to_take_max = 200;
+ param.free_r = LIB_RND_RATIO (0.7);
+ param.sar_add_min = 1;
+ param.sar_add_max = 30;
+ test_pbproc_t test_pbproc;
+ test_pbproc_init (&test_pbproc);
+ mfs_tx_t *mfs = blk_alloc ();
+ mfs_tx_init (mfs, false, false, 0, 1);
+ mfs->dynamic_cap = true;
+ for (i = 0; i < NB_ITER; i++)
+ {
+ uint add = lib_rnd_uniform (rnd, param.sar_add_max -
+ param.sar_add_min + 1)
+ + param.sar_add_min;
+ test_verbose_print ("add: %d", add);
+ pb_t *tail = pbproc_mfs_extract_tail (mfs);
+ IT ();
+ uint insert = tail ? add - 1 : add;
+ test_verbose_print ("insert: %d", insert);
+ if (insert)
+ {
+ pb_t *sar_head, *sar_tail, *p;
+ sar_head = (pb_t *) blk_alloc_desc_range (insert, (blk_t **)
+ &sar_tail);
+ p = sar_head;
+ do
+ {
+ pb_header_t h;
+ h.ssn = mfs->next_ssn++;
+ h.mfbo = 0;
+ h.vpbf = true;
+ h.mmqf = false;
+ h.mfbf = false;
+ h.opsf = false;
+ h.rsvd = 0;
+ p->header = h;
+ if (p == sar_tail)
+ break;
+ p = p->next;
+ } while (1);
+ pbproc_mfs_insert (mfs, sar_head, sar_tail, insert, 0);
+ IT ();
+ }
+ pbproc_mfs_provide (mfs, add);
+ IT ();
+ }
+ test_pbproc_check (t, &test_pbproc, mfs);
+ if (mfs->head)
+ blk_release_desc_range (&mfs->head->blk, &mfs->tail->blk);
+ blk_release (mfs);
+ test_pbproc_uninit (&test_pbproc);
+ } test_end;
+ test_begin (t, "beacon")
+ {
+ test_param_t param;
+ param.next_it = 2;
+ param.to_take_max = 1;
+ param.free_r = 0xffffffff;
+ test_pbproc_t test_pbproc;
+ test_pbproc_init (&test_pbproc);
+ mfs_tx_t *mfs = blk_alloc ();
+ mfs_tx_init (mfs, false, false, 0, 1);
+ mfs->beacon = true;
+ for (i = 0; i < NB_ITER; i++)
+ {
+ test_verbose_print ("prepare");
+ pb_beacon_t *beacon = (pb_beacon_t *) blk_alloc_desc ();
+ pbproc_tx_beacon_params_t params =
+ { { mfs->next_ssn, mfs->next_ssn + 1,
+ mfs->next_ssn + 2, mfs->next_ssn + 3 }, NULL };
+ beacon->first_data_word = 42;
+ mfs->next_ssn++;
+ pbproc_mfs_beacon_prepare (INVALID_PTR, mfs, beacon, &params);
+ IT ();
+ }
+ test_pbproc_check (t, &test_pbproc, mfs);
+ if (mfs->head)
+ blk_release_desc_range (&mfs->head->blk, &mfs->tail->blk);
+ blk_release (mfs);
+ test_pbproc_uninit (&test_pbproc);
+ } test_end;
+}
+
+void
+mfs_test_suite (test_t t)
+{
+ test_suite_begin (t, "mfs");
+ mfs_basic_test_case (t);
+}
+
+int
+main (int argc, char **argv)
+{
+ test_t t;
+ test_init (t, argc, argv);
+ mfs_test_suite (t);
+ test_result (t);
+ return test_nb_failed (t) == 0 ? 0 : 1;
+}
diff --git a/cesar/mac/pbproc/test/pbproc/Config b/cesar/mac/pbproc/test/pbproc/Config
new file mode 100644
index 0000000000..9ff10b2165
--- /dev/null
+++ b/cesar/mac/pbproc/test/pbproc/Config
@@ -0,0 +1 @@
+CONFIG_TRACE = y
diff --git a/cesar/mac/pbproc/test/pbproc/Makefile b/cesar/mac/pbproc/test/pbproc/Makefile
new file mode 100644
index 0000000000..7414413953
--- /dev/null
+++ b/cesar/mac/pbproc/test/pbproc/Makefile
@@ -0,0 +1,10 @@
+BASE = ../../../..
+
+INCLUDES = mac/pbproc/test/pbproc/override
+
+HOST_PROGRAMS = test_pbproc
+test_pbproc_SOURCES = test_pbproc.c prep_mpdu.c tx_data.c rx_data.c \
+ scenario.c scenario_defs.c ca.c phy.c utils.c
+test_pbproc_MODULES = lib mac/pbproc mac/common
+
+include $(BASE)/common/make/top.mk
diff --git a/cesar/mac/pbproc/test/pbproc/inc/scenario.h b/cesar/mac/pbproc/test/pbproc/inc/scenario.h
new file mode 100644
index 0000000000..bf2c236b04
--- /dev/null
+++ b/cesar/mac/pbproc/test/pbproc/inc/scenario.h
@@ -0,0 +1,152 @@
+#ifndef inc_scenario_h
+#define inc_scenario_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file inc/scenario.h
+ * \brief Scenario support.
+ * \ingroup test
+ *
+ * When doing complex test, I expect a suite of event with precise parameters.
+ * This scenario system will make this easy to check.
+ */
+#include "lib/test.h"
+
+/* Forward declaration. */
+typedef struct scenario_t scenario_t;
+typedef struct scenario_globals_t scenario_globals_t;
+typedef union scenario_params_t scenario_params_t;
+
+/** Callback for actions. */
+typedef void
+(*scenario_action_cb_t) (scenario_globals_t *globals, scenario_params_t *params);
+
+#include "inc/scenario_defs.h"
+
+/** Scenario event identifier. */
+enum scenario_event_id_t
+{
+ /** Event identifier for end of list. */
+ SCENARIO_NULL_ID,
+ /** Event identifier for no operation. */
+ SCENARIO_NOP_ID,
+ /** Event identifier for action. */
+ SCENARIO_ACTION_ID,
+#define SCENARIO_DEFS_EVENTS_ID(event) PASTE (SCENARIO_EVENT_, event)
+ PREPROC_FOR_EACH_COMMA (SCENARIO_DEFS_EVENTS_ID, SCENARIO_DEFS_EVENTS)
+#undef SCENARIO_DEFS_EVENTS_ID
+};
+typedef enum scenario_event_id_t scenario_event_id_t;
+
+/** Scenario parameters. */
+union scenario_params_t
+{
+#define SCENARIO_DEFS_PARAMS(event) \
+ scenario_event_ ## event ## _t event_ ## event;
+ PREPROC_FOR_EACH (SCENARIO_DEFS_PARAMS, SCENARIO_DEFS_EVENTS)
+#undef SCENARIO_DEFS_PARAMS
+#define SCENARIO_DEFS_PARAMS(action) \
+ scenario_action_ ## action ## _t action_ ## action;
+ PREPROC_FOR_EACH (SCENARIO_DEFS_PARAMS, SCENARIO_DEFS_ACTIONS)
+#undef SCENARIO_DEFS_PARAMS
+};
+
+/** Scenario entry. */
+struct scenario_entry_t
+{
+ /** Event identifier. */
+ scenario_event_id_t event_id;
+ /** Action callback if not an event. */
+ scenario_action_cb_t action_cb;
+ /** Entry parameters. */
+ scenario_params_t params;
+};
+typedef struct scenario_entry_t scenario_entry_t;
+
+/** Scenario globals. */
+struct scenario_globals_t
+{
+ SCENARIO_DEFS_GLOBALS
+};
+
+/** Scenario context. */
+struct scenario_t
+{
+ /** Currently running test. */
+ struct test_t *t;
+ /** Current entry. */
+ scenario_entry_t *current;
+ /** Scenario entries. */
+ scenario_entry_t *entries;
+ /** Scenario globals. */
+ scenario_globals_t *globals;
+};
+
+/** Currently running scenario. */
+extern scenario_t scenario;
+
+/** Use this at event entry. This macro is special and can not be included in
+ * a do { } while (0). */
+#define scenario_event(event, args...) \
+ scenario_event_ (event, ## args)
+
+#define scenario_event_(event, args...) \
+ PASTE_EXPAND (scenario_event_, PREPROC_NARG (events, ## args)) \
+ (event, ## args)
+
+#define scenario_event_1(event) \
+ dbg_assert (scenario.current); \
+ test_within (scenario.t); \
+ while (scenario.current->event_id == SCENARIO_NOP_ID) \
+ scenario.current++; \
+ test_fail_unless (scenario.current->event_id \
+ == SCENARIO_EVENT_ ## event); \
+ scenario.current++
+
+#define scenario_event_2(event, params_var) \
+ scenario_event_1 (event); \
+ scenario_event_ ## event ## _t *params_var = \
+ &scenario.current[-1].params.event_ ## event
+
+#define scenario_event_3(event, params_var, globals_var) \
+ scenario_event_2 (event, params_var); \
+ scenario_globals_t *globals_var = scenario.globals
+
+/** Use this to define an event in a scenario list of entries. */
+#define SCENARIO_EVENT(event, params_def...) \
+ { SCENARIO_EVENT_ ## event, NULL, \
+ { .event_ ## event = { params_def } } }
+
+/** Use this to define an action in a scenario list of entries. */
+#define SCENARIO_ACTION(action, params_def...) \
+ { SCENARIO_ACTION_ID, scenario_action_ ## action ## _cb, \
+ { .action_ ## action = { params_def } } }
+
+/** Use this for a no operation in a scenario list of entries. */
+#define SCENARIO_NOP \
+ { SCENARIO_NOP_ID, NULL, { } }
+
+/** Use this to mark end of scenario list of entries. */
+#define SCENARIO_END \
+ { SCENARIO_NULL_ID, NULL, { } }
+
+BEGIN_DECLS
+
+/**
+ * Run a scenario until completion.
+ * \param t test context
+ * \param entries list of entries for this scenario
+ * \param globals pointer to globals structure for this scenario
+ */
+void
+scenario_run (test_t t, scenario_entry_t *entries,
+ scenario_globals_t *globals);
+
+END_DECLS
+
+#endif /* inc_scenario_h */
diff --git a/cesar/mac/pbproc/test/pbproc/inc/scenario_defs.h b/cesar/mac/pbproc/test/pbproc/inc/scenario_defs.h
new file mode 100644
index 0000000000..a50010c4d3
--- /dev/null
+++ b/cesar/mac/pbproc/test/pbproc/inc/scenario_defs.h
@@ -0,0 +1,243 @@
+#ifndef inc_scenario_defs_h
+#define inc_scenario_defs_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file inc/scenario_defs.h
+ * \brief Scenario entries definition.
+ * \ingroup test
+ */
+
+#include "inc/test_pbproc.h"
+
+/* Scenario globals. */
+#define SCENARIO_DEFS_GLOBALS \
+ test_pbproc_t *tp;
+
+typedef struct
+{
+} scenario_empty_t;
+
+/* Scenario actions. */
+#define SCENARIO_DEFS_ACTIONS \
+ phy_rx_fc, \
+ phy_access, \
+ phy_access_conf, \
+ phy_pbdma, \
+ pbproc_activate
+
+typedef struct
+{
+ u32 rx_date;
+ u32 rx_sysdate;
+ u32 *fc_av;
+ bool prp_won;
+ uint slot_count;
+} scenario_action_phy_rx_fc_t;
+
+void
+scenario_action_phy_rx_fc_cb (scenario_globals_t *globals,
+ scenario_params_t *params);
+
+typedef struct
+{
+ ca_access_param_t *access_param;
+ bool prp_won;
+ uint slot_count;
+} scenario_action_phy_access_t;
+
+void
+scenario_action_phy_access_cb (scenario_globals_t *globals,
+ scenario_params_t *params);
+
+typedef scenario_empty_t scenario_action_phy_access_conf_t;
+
+void
+scenario_action_phy_access_conf_cb (scenario_globals_t *globals,
+ scenario_params_t *params);
+
+typedef struct
+{
+ bool pb_null;
+ bool pb_crc_error;
+ bool pb_it;
+ bool end_rx_pb;
+ bool end_tx_pb;
+ bool end_chandata;
+ uint null_pb_index;
+ u32 *crc_bitmap;
+ uint crc_bitmap_bits;
+} scenario_action_phy_pbdma_t;
+
+void
+scenario_action_phy_pbdma_cb (scenario_globals_t *globals,
+ scenario_params_t *params);
+
+typedef struct
+{
+ bool flag;
+} scenario_action_pbproc_activate_t;
+
+void
+scenario_action_pbproc_activate_cb (scenario_globals_t *globals,
+ scenario_params_t *params);
+
+/* Scenario events. */
+#define SCENARIO_DEFS_EVENTS \
+ phy_set_tonemap, \
+ phy_tx_fc10, \
+ phy_tx_param, \
+ phy_tx_frame, \
+ phy_rx_param, \
+ phy_rx_activate, \
+ phy_rx_prepare, \
+ phy_pbdma_start, \
+ phy_pbdma_update, \
+ ca_mfs_update, \
+ ca_access_activate, \
+ ca_access_deactivate, \
+ ca_access_hold, \
+ ca_access_vcs_restart, \
+ ca_access_program, \
+ ca_access_defer, \
+ ca_access_aifs, \
+ ca_backoff_deferred, \
+ ca_backoff_success, \
+ ca_backoff_cancel, \
+ pbproc_rx_cb, \
+ pbproc_rx_beacon_cb
+
+typedef struct
+{
+ uint tonemap_index;
+} scenario_event_phy_set_tonemap_t;
+
+typedef struct
+{
+ u32 fc_10;
+} scenario_event_phy_tx_fc10_t;
+
+typedef struct
+{
+ phy_fc_mode_t fc_mode;
+ bool short_ppdu;
+ phy_mod_t mod;
+ phy_fecrate_t fecrate;
+ phy_pb_size_t pb_size;
+ phy_gil_t gil;
+ uint tonemap_index;
+} scenario_event_phy_tx_param_t;
+
+typedef struct
+{
+ u32 date;
+ bool want_conf;
+ bool stop_tx_on_prp_lost;
+} scenario_event_phy_tx_frame_t;
+
+typedef struct
+{
+ phy_fc_mode_t fc_mode;
+} scenario_event_phy_rx_param_t;
+
+typedef struct
+{
+ bool now;
+ u32 date;
+ bool pre_detection;
+} scenario_event_phy_rx_activate_t;
+
+typedef struct
+{
+ bool short_ppdu;
+ phy_mod_t mod;
+ phy_fecrate_t fecrate;
+ phy_pb_size_t pb_size;
+ phy_gil_t gil;
+ uint tonemap_index;
+ uint symbol_nb;
+} scenario_event_phy_rx_prepare_t;
+
+typedef struct
+{
+ bool bypass_aes;
+ uint nb_total;
+ uint nb_ready;
+ uint nb_pb_it;
+} scenario_event_phy_pbdma_start_t;
+
+typedef struct
+{
+ uint nb_ready;
+ uint nb_pb_it;
+} scenario_event_phy_pbdma_update_t;
+
+typedef struct
+{
+ mfs_tx_t *mfs;
+} scenario_event_ca_mfs_update_t;
+
+typedef struct
+{
+ u32 date;
+ uint anticipation_tck;
+ mac_coexistence_mode_t coexistence_mode;
+ bool hybrid;
+ uint nek_switch;
+} scenario_event_ca_access_activate_t;
+
+typedef scenario_empty_t scenario_event_ca_access_deactivate_t;
+
+typedef scenario_empty_t scenario_event_ca_access_hold_t;
+
+typedef struct
+{
+ u32 start_date;
+ uint length_tck;
+ uint anticipation_tck;
+ bool eifs;
+} scenario_event_ca_access_vcs_restart_t;
+
+typedef struct
+{
+ u32 date;
+ uint anticipation_tck;
+} scenario_event_ca_access_program_t;
+
+typedef struct
+{
+ u32 date;
+ uint anticipation_tck;
+} scenario_event_ca_access_defer_t;
+
+typedef struct
+{
+ mac_coexistence_mode_t coexistence_mode;
+ bool hybrid;
+ uint nek_switch;
+} scenario_event_ca_access_aifs_t;
+
+typedef struct
+{
+ uint slot_count;
+} scenario_event_ca_backoff_deferred_t;
+
+typedef scenario_empty_t scenario_event_ca_backoff_success_t;
+
+typedef scenario_empty_t scenario_event_ca_backoff_cancel_t;
+
+typedef struct
+{
+ uint pb_nb;
+} scenario_event_pbproc_rx_cb_t;
+
+typedef struct
+{
+} scenario_event_pbproc_rx_beacon_cb_t;
+
+#endif /* inc_scenario_defs_h */
diff --git a/cesar/mac/pbproc/test/pbproc/inc/test_pbproc.h b/cesar/mac/pbproc/test/pbproc/inc/test_pbproc.h
new file mode 100644
index 0000000000..f8ef9b2ce0
--- /dev/null
+++ b/cesar/mac/pbproc/test/pbproc/inc/test_pbproc.h
@@ -0,0 +1,47 @@
+#ifndef inc_test_pbproc_h
+#define inc_test_pbproc_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file inc/test_pbproc.h
+ * \brief PBProc test.
+ * \ingroup test
+ */
+#include "lib/rnd.h"
+#include "mac/common/config.h"
+#include "mac/common/store.h"
+#include "mac/ca/ca.h"
+#include "mac/pbproc/pbproc.h"
+
+/** Test pbproc context. */
+struct test_pbproc_t
+{
+ /** Random context. */
+ lib_rnd_t rnd[1];
+ /** Mac configuration. */
+ mac_config_t config;
+ /** Mac MFS and STA store. */
+ mac_store_t *store;
+ /** PB Processing context. */
+ pbproc_t *pbproc;
+ /** Channel Access context. */
+ ca_t *ca;
+};
+typedef struct test_pbproc_t test_pbproc_t;
+
+BEGIN_DECLS
+
+void
+test_pbproc_init (test_pbproc_t *ctx);
+
+void
+test_pbproc_uninit (test_pbproc_t *ctx);
+
+END_DECLS
+
+#endif /* inc_test_pbproc_h */
diff --git a/cesar/mac/pbproc/test/pbproc/inc/utils.h b/cesar/mac/pbproc/test/pbproc/inc/utils.h
new file mode 100644
index 0000000000..5dbcf55160
--- /dev/null
+++ b/cesar/mac/pbproc/test/pbproc/inc/utils.h
@@ -0,0 +1,38 @@
+#ifndef inc_utils_h
+#define inc_utils_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file inc/utils.h
+ * \brief Utilities.
+ * \ingroup test
+ */
+#include "mac/common/mfs.h"
+#include "mac/common/tonemap.h"
+#include "inc/test_pbproc.h"
+
+BEGIN_DECLS
+
+mfs_tx_t *
+utils_mfs_tx_prepare (bool bcast, bool mme, uint lid, uint tei, uint seg_nb);
+
+void
+utils_mfs_tx_cleanup (mfs_tx_t *mfs);
+
+tonemap_t *
+utils_sta_prepare_default_tonemap (test_pbproc_t *tp, bool tx, uint tei,
+ uint tmi, uint tm_mod, uint tm_max_fl_tck,
+ uint *dx);
+
+void
+utils_prepare_encryption (test_pbproc_t *tp, bool encrypted, bool sta_auth,
+ uint tei, uint nek_switch);
+
+END_DECLS
+
+#endif /* inc_utils_h */
diff --git a/cesar/mac/pbproc/test/pbproc/override/hal/phy/inc/context.h b/cesar/mac/pbproc/test/pbproc/override/hal/phy/inc/context.h
new file mode 100644
index 0000000000..8ab0f4b183
--- /dev/null
+++ b/cesar/mac/pbproc/test/pbproc/override/hal/phy/inc/context.h
@@ -0,0 +1,51 @@
+#ifndef override_hal_phy_inc_context_h
+#define override_hal_phy_inc_context_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file override/hal/phy/inc/context.h
+ * \brief Override HAL Phy context.
+ * \ingroup test
+ */
+#include "hal/phy/phy.h"
+
+/** Phy context. */
+struct phy_t
+{
+ /** User data passed to any callback. */
+ void *user_data;
+ /** RX FC event callback. */
+ phy_rx_fc_cb_t rx_fc_cb;
+ /** ACCESS event callback. */
+ phy_access_cb_t access_cb;
+ /** ACCESS CONFIRM event callback. */
+ phy_access_conf_cb_t access_conf_cb;
+ /** PB DMA callback. */
+ phy_pbdma_cb_t pbdma_cb;
+ /** TX FALSE ALARM callback. */
+ phy_tx_false_alarm_cb_t tx_false_alarm_cb;
+ /** DSR callback. */
+ phy_deferred_cb_t deferred_cb;
+ /** Stubbed RX preamble SYS date. */
+ u32 rx_sysdate;
+ /** Stubbed PRP won. */
+ bool prp_won;
+ /** Stubbed slot count. */
+ uint slot_count;
+ /** Number of PB DMA PB. */
+ uint pbdma_nb_total;
+ /** First PB DMA PB. */
+ phy_pb_t *pbdma_first_pb;
+ /** Last FC sent. */
+ u32 tx_fc[4];
+ /** PBDMA CRC bitmap. */
+ u32 crc_bitmap[8];
+};
+/* Forward declaration in hal/phy/forward.h. */
+
+#endif /* override_hal_phy_inc_context_h */
diff --git a/cesar/mac/pbproc/test/pbproc/override/mac/ca/inc/context.h b/cesar/mac/pbproc/test/pbproc/override/mac/ca/inc/context.h
new file mode 100644
index 0000000000..9a817beae9
--- /dev/null
+++ b/cesar/mac/pbproc/test/pbproc/override/mac/ca/inc/context.h
@@ -0,0 +1,26 @@
+#ifndef override_mac_ca_inc_context_h
+#define override_mac_ca_inc_context_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file override/mac/ca/inc/context.h
+ * \brief Override CA context.
+ * \ingroup test
+ */
+
+/** Channel Access context. */
+struct ca_t
+{
+ /** Next ACCESS event parameters. */
+ ca_access_param_t access_param;
+ /** Current allocation parameters. */
+ ca_access_alloc_param_t current_allocation_param;
+};
+/* Forward declaration in mac/ca/ca.h. */
+
+#endif /* override_mac_ca_inc_context_h */
diff --git a/cesar/mac/pbproc/test/pbproc/src/ca.c b/cesar/mac/pbproc/test/pbproc/src/ca.c
new file mode 100644
index 0000000000..4e2f80f667
--- /dev/null
+++ b/cesar/mac/pbproc/test/pbproc/src/ca.c
@@ -0,0 +1,129 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file src/ca.c
+ * \brief Override CA functions.
+ * \ingroup test
+ */
+#include "common/std.h"
+#include "mac/ca/ca.h"
+
+#include "mac/ca/inc/context.h"
+
+#include "inc/scenario.h"
+
+ca_t *
+ca_init (phy_t *phy, mac_config_t *config, mac_store_t *store)
+{
+ static ca_t ca_ctx;
+ ca_t *ctx = &ca_ctx;
+ ctx->access_param.mfs = NULL;
+ return ctx;
+}
+
+void
+ca_uninit (ca_t *ctx)
+{
+}
+
+void
+ca_mfs_update (ca_t *ctx, mfs_tx_t *mfs)
+{
+ if (scenario.current)
+ {
+ scenario_event (ca_mfs_update, params);
+ test_fail_unless (mfs == params->mfs);
+ }
+}
+
+const ca_access_alloc_param_t *
+ca_access_activate (ca_t *ctx, u32 date, uint anticipation_tck)
+{
+ scenario_event (ca_access_activate, params);
+ test_fail_unless (date == params->date);
+ test_fail_unless (anticipation_tck == params->anticipation_tck);
+ ctx->current_allocation_param.coexistence_mode = params->coexistence_mode;
+ ctx->current_allocation_param.hybrid = params->hybrid;
+ ctx->current_allocation_param.nek_switch = params->nek_switch;
+ return &ctx->current_allocation_param;
+}
+
+void
+ca_access_deactivate (ca_t *ctx)
+{
+ scenario_event (ca_access_deactivate);
+}
+
+void
+ca_access_hold (ca_t *ctx)
+{
+ scenario_event (ca_access_hold);
+}
+
+void
+ca_access_vcs_restart (ca_t *ctx, u32 start_date, uint length_tck,
+ uint anticipation_tck, bool eifs)
+{
+ scenario_event (ca_access_vcs_restart, params);
+ test_fail_unless (start_date == params->start_date);
+ test_fail_unless (length_tck == params->length_tck);
+ test_fail_unless (anticipation_tck == params->anticipation_tck);
+ test_fail_unless (eifs == params->eifs);
+}
+
+void
+ca_access_program (ca_t *ctx, u32 date, uint anticipation_tck)
+{
+ scenario_event (ca_access_program, params);
+ test_fail_unless (date == params->date);
+ test_fail_unless (anticipation_tck == params->anticipation_tck);
+}
+
+void
+ca_access_defer (ca_t *ctx, u32 date, uint anticipation_tck)
+{
+ scenario_event (ca_access_defer, params);
+ test_fail_unless (date == params->date);
+ test_fail_unless (anticipation_tck == params->anticipation_tck);
+}
+
+const ca_access_alloc_param_t *
+ca_access_aifs (ca_t *ctx)
+{
+ scenario_event (ca_access_aifs, params);
+ ctx->current_allocation_param.coexistence_mode = params->coexistence_mode;
+ ctx->current_allocation_param.hybrid = params->hybrid;
+ ctx->current_allocation_param.nek_switch = params->nek_switch;
+ return &ctx->current_allocation_param;
+}
+
+const ca_access_param_t *
+ca_access_get_param (ca_t *ctx)
+{
+ return &ctx->access_param;
+}
+
+void
+ca_backoff_deferred (ca_t *ctx, int slot_counter)
+{
+ scenario_event (ca_backoff_deferred, params);
+ test_fail_unless (slot_counter == (int) params->slot_count);
+}
+
+void
+ca_backoff_success (ca_t *ctx)
+{
+ scenario_event (ca_backoff_success);
+}
+
+void
+ca_backoff_cancel (ca_t *ctx)
+{
+ scenario_event (ca_backoff_cancel);
+}
+
diff --git a/cesar/mac/pbproc/test/pbproc/src/phy.c b/cesar/mac/pbproc/test/pbproc/src/phy.c
new file mode 100644
index 0000000000..c8b94b1602
--- /dev/null
+++ b/cesar/mac/pbproc/test/pbproc/src/phy.c
@@ -0,0 +1,229 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file src/phy.c
+ * \brief Override HAL Phy functions.
+ * \ingroup test
+ */
+#include "common/std.h"
+
+#include "hal/phy/phy.h"
+#include "hal/phy/pbdma.h"
+
+#include "hal/phy/inc/context.h"
+
+#include "inc/scenario.h"
+
+phy_t *
+phy_init (void *user_data, phy_rx_fc_cb_t rx_fc_cb, phy_access_cb_t access_cb,
+ phy_access_conf_cb_t access_conf_cb, phy_pbdma_cb_t pbdma_cb,
+ phy_tx_false_alarm_cb_t tx_false_alarm_cb,
+ phy_deferred_cb_t deferred_cb)
+{
+ static phy_t phy_ctx;
+ phy_t *ctx = &phy_ctx;
+ ctx->user_data = user_data;
+ ctx->rx_fc_cb = rx_fc_cb;
+ ctx->access_cb = access_cb;
+ ctx->access_conf_cb = access_conf_cb;
+ ctx->pbdma_cb = pbdma_cb;
+ ctx->tx_false_alarm_cb = tx_false_alarm_cb;
+ ctx->deferred_cb = deferred_cb;
+ ctx->prp_won = false;
+ ctx->slot_count = 0;
+ ctx->pbdma_nb_total = 0;
+ ctx->pbdma_first_pb = NULL;
+ uint i;
+ for (i = 0; i < COUNT (ctx->tx_fc); i++)
+ ctx->tx_fc[i] = 0;
+ for (i = 0; i < COUNT (ctx->crc_bitmap); i++)
+ ctx->crc_bitmap[i] = 0;
+ return ctx;
+}
+
+void
+phy_uninit (phy_t *ctx)
+{
+}
+
+u32
+phy_date (phy_t *ctx)
+{
+ return 0;
+}
+
+void
+phy_set_tonemask (phy_t *ctx, u8 *tonemask, uint carrier_nb)
+{
+}
+
+void
+phy_set_tonemap (phy_t *ctx, uint tonemap_index, blk_t *tonemap)
+{
+ scenario_event (phy_set_tonemap, params);
+ test_fail_unless (tonemap_index == params->tonemap_index);
+ /* Test tonemap? */
+}
+
+void
+phy_tx_fc10 (phy_t *ctx, u32 fc_10)
+{
+ scenario_event (phy_tx_fc10, params);
+ test_fail_unless (fc_10 == params->fc_10);
+}
+
+void
+phy_tx_param (phy_t *ctx, phy_fc_mode_t fc_mode, bool short_ppdu,
+ phy_mod_t mod, phy_fecrate_t fecrate, phy_pb_size_t pb_size,
+ phy_gil_t gil, uint tonemap_index)
+{
+ scenario_event (phy_tx_param, params);
+ test_fail_unless (fc_mode == params->fc_mode);
+ test_fail_unless (short_ppdu == params->short_ppdu);
+ if (short_ppdu)
+ {
+ test_fail_unless (mod == PHY_MOD_NONE);
+ test_fail_unless (fecrate == PHY_FEC_RATE_NONE);
+ test_fail_unless (pb_size == PHY_PB_SIZE_NONE);
+ test_fail_unless (gil == PHY_GIL_NB);
+ test_fail_unless (tonemap_index == 0);
+ }
+ else
+ {
+ test_fail_unless (mod == params->mod);
+ test_fail_unless (fecrate == params->fecrate);
+ test_fail_unless (pb_size == params->pb_size);
+ test_fail_unless (gil == params->gil);
+ test_fail_unless (tonemap_index == params->tonemap_index);
+ }
+}
+
+void
+phy_tx_frame (phy_t *ctx, u32 date, bool want_conf, bool stop_tx_on_prp_lost,
+ const u32 fc_av[4])
+{
+ scenario_event (phy_tx_frame, params);
+ test_fail_unless (date == params->date);
+ test_fail_unless (want_conf == params->want_conf);
+ test_fail_unless (stop_tx_on_prp_lost == params->stop_tx_on_prp_lost);
+ ctx->tx_fc[0] = fc_av[0];
+ ctx->tx_fc[1] = fc_av[1];
+ ctx->tx_fc[2] = fc_av[2];
+ ctx->tx_fc[3] = fc_av[3];
+}
+
+void
+phy_rx_param (phy_t *ctx, phy_fc_mode_t fc_mode)
+{
+ scenario_event (phy_rx_param, params);
+ test_fail_unless (fc_mode == params->fc_mode);
+}
+
+void
+phy_rx_activate (phy_t *ctx, bool now, u32 date, bool pre_detection)
+{
+ scenario_event (phy_rx_activate, params);
+ test_fail_unless (now == params->now);
+ test_fail_unless (date == params->date);
+ test_fail_unless (pre_detection == params->pre_detection);
+}
+
+void
+phy_rx_prepare (phy_t *ctx, bool short_ppdu, phy_mod_t mod,
+ phy_fecrate_t fecrate, phy_pb_size_t pb_size, phy_gil_t gil,
+ uint tonemap_index, uint symbol_nb)
+{
+ scenario_event (phy_rx_prepare, params);
+ test_fail_unless (short_ppdu == params->short_ppdu);
+ if (short_ppdu)
+ {
+ test_fail_unless (mod == PHY_MOD_NONE);
+ test_fail_unless (fecrate == PHY_FEC_RATE_NONE);
+ test_fail_unless (pb_size == PHY_PB_SIZE_NONE);
+ test_fail_unless (gil == PHY_GIL_NB);
+ test_fail_unless (tonemap_index == 0);
+ test_fail_unless (symbol_nb == 0);
+ }
+ else
+ {
+ test_fail_unless (mod == params->mod);
+ test_fail_unless (fecrate == params->fecrate);
+ test_fail_unless (pb_size == params->pb_size);
+ test_fail_unless (gil == params->gil);
+ test_fail_unless (tonemap_index == params->tonemap_index);
+ test_fail_unless (symbol_nb == params->symbol_nb);
+ }
+}
+
+u32
+phy_rx_sysdate (phy_t *ctx)
+{
+ dbg_assert (ctx);
+ return ctx->rx_sysdate;
+}
+
+uint
+phy_access_backoff_slot_count (phy_t *ctx)
+{
+ dbg_assert (ctx);
+ return ctx->slot_count;
+}
+
+bool
+phy_access_backoff_prp_won (phy_t *ctx)
+{
+ dbg_assert (ctx);
+ return ctx->prp_won;
+}
+
+void
+phy_access_timer_cancel (phy_t *ctx)
+{
+}
+
+void
+phy_pbdma_start (phy_t *ctx, bool bypass_aes, const u32 iv[3],
+ const u32 nek[4], uint nb_total, uint nb_ready,
+ uint nb_pb_it, phy_pb_t *first_pb)
+{
+ scenario_event (phy_pbdma_start, params);
+ test_fail_unless (bypass_aes == params->bypass_aes);
+ test_fail_unless (nb_total == params->nb_total);
+ test_fail_unless (nb_ready == params->nb_ready);
+ test_fail_unless (nb_pb_it == params->nb_pb_it);
+ ctx->pbdma_nb_total = nb_total;
+ ctx->pbdma_first_pb = first_pb;
+}
+
+void
+phy_pbdma_update (phy_t *ctx, uint nb_ready, uint nb_pb_it)
+{
+ scenario_event (phy_pbdma_update, params);
+ test_fail_unless (nb_ready == params->nb_ready);
+ test_fail_unless (nb_pb_it == params->nb_pb_it);
+}
+
+phy_pb_t *
+phy_pbdma_get_tail (phy_t *ctx)
+{
+ dbg_assert (ctx);
+ uint i;
+ phy_pb_t *pb;
+ for (i = 1, pb = ctx->pbdma_first_pb;
+ i < ctx->pbdma_nb_total;
+ i++, pb = PARENT_OF (phy_pb_t, blk, pb->blk.next))
+ ;
+ return pb;
+}
+
+volatile const u32 *
+phy_pbdma_get_crc_bitmap (phy_t *ctx)
+{
+ return ctx->crc_bitmap;
+}
+
diff --git a/cesar/mac/pbproc/test/pbproc/src/prep_mpdu.c b/cesar/mac/pbproc/test/pbproc/src/prep_mpdu.c
new file mode 100644
index 0000000000..f281f66c58
--- /dev/null
+++ b/cesar/mac/pbproc/test/pbproc/src/prep_mpdu.c
@@ -0,0 +1,575 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file src/prep_mpdu.c
+ * \brief PBProc prep_mpdu test.
+ * \ingroup test
+ */
+#include "common/std.h"
+
+#include "lib/test.h"
+
+#include "inc/test_pbproc.h"
+#include "inc/utils.h"
+
+#include "mac/common/timings.h"
+#include "mac/pbproc/inc/context.h"
+
+void
+prep_mpdu_test (test_t t, test_pbproc_t *tp, u32 date, bool bcast,
+ uint mfs_seg_nb, uint duration_tck, uint symb_nb,
+ uint main_seg_nb_total, uint seg_nb_pending, u64 crc_error,
+ u64 encoded_sack, uint tmi, uint tm_mod, uint tm_max_fl_tck,
+ bool encrypted)
+{
+ const uint dtei = (bcast ? MAC_TEI_BCAST : 2), lid = 0;
+ pb_t *seg;
+ test_within (t);
+ /* Prepare tone map. */
+ tonemap_t *tm = &tp->config.tonemask_info.tonemap_robo[PHY_MOD_ROBO];
+ uint dx = MAC_DX417_TCK;
+ if (tmi != PHY_MOD_ROBO || (encrypted && !bcast))
+ tm = utils_sta_prepare_default_tonemap (tp, true, dtei, tmi, tm_mod,
+ tm_max_fl_tck, &dx);
+ uint rifs_tck = symb_nb == 0 || tmi < PHY_MOD_ROBO_NB
+ ? MAC_RIFS_DEFAULT_TCK : MAC_RIFS_SPC_ANY_TCK;
+ /* Create an MFS. */
+ mfs_tx_t *mfs = utils_mfs_tx_prepare (bcast, false, lid, dtei,
+ mfs_seg_nb);
+ pb_t *seg_first = mfs->head;
+ /* Encrypted? */
+ utils_prepare_encryption (tp, encrypted, !bcast, dtei, 0);
+ /* Setup an access. */
+ ca_access_param_t *access = &tp->pbproc->access;
+ access->mfs = mfs;
+ access->access_date = date;
+ const uint beacon_tck = MAC_MS_TO_TCK (1000) / 50;
+ access->beacon_period_start_date = date / beacon_tck * beacon_tck;
+ access->duration_tck = duration_tck;
+ bool cfp = tmi != PHY_MOD_ROBO && tm_max_fl_tck;
+ access->cfp = cfp;
+ access->hybrid = false;
+ /* Prepare MPDU. */
+ pbproc_prep_mpdu (tp->pbproc);
+ /* Check result. */
+ pbproc_prep_mpdu_t *prep = &tp->pbproc->prep_mpdu;
+ test_fail_unless (prep->dtei == dtei);
+ test_fail_unless (prep->lid == lid);
+ test_fail_unless (prep->wack == !bcast);
+ test_fail_unless (!prep->rts_cts);
+ test_fail_unless (!prep->burst);
+ test_fail_unless (prep->tx_date == date);
+ if (main_seg_nb_total == 0)
+ {
+ test_fail_unless (!prep->valid);
+ test_fail_unless (prep->main_mfs == NULL);
+ test_fail_unless (prep->combined_mfs == NULL);
+ test_fail_unless (prep->main_seg_nb == 0);
+ test_fail_unless (prep->main_seg_nb_reserved == 0);
+ test_fail_unless (prep->seg_nb_pending == 0);
+ test_fail_unless (prep->pb_nb_total == 0);
+ }
+ else
+ {
+ test_fail_unless (prep->valid);
+ test_fail_unless (prep->main_mfs == mfs);
+ test_fail_unless (prep->combined_mfs == NULL);
+ test_fail_unless (prep->fc_mode == PHY_FC_MODE_AV_1);
+ test_fail_unless (prep->mod == tmi);
+ test_fail_unless (prep->fecrate == tm->fecrate);
+ test_fail_unless (prep->pb_size == PHY_PB_SIZE_520);
+ test_fail_unless (prep->gil == tm->gil);
+ test_fail_unless (prep->tonemap == tm->tmdma_desc_head);
+ test_fail_unless (prep->main_head == seg_first);
+ test_fail_unless (prep->head == seg_first);
+ uint main_seg_nb = MIN (main_seg_nb_total, 4u);
+ uint main_seg_nb_reserved = main_seg_nb_total - main_seg_nb;
+ test_fail_unless (prep->main_seg_nb == main_seg_nb);
+ uint i;
+ for (seg = seg_first, i = 1; i < main_seg_nb; seg = seg->next, i++)
+ ;
+ test_fail_unless (prep->main_tail == seg);
+ test_fail_unless (prep->tail == seg);
+ test_fail_unless (prep->main_seg_nb_reserved == main_seg_nb_reserved);
+ test_fail_unless (prep->seg_nb_pending == seg_nb_pending);
+ test_fail_unless (prep->pb_nb_total == main_seg_nb_total +
+ seg_nb_pending);
+ test_fail_unless (prep->flp_tck == MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (symb_nb, dx)
+ + rifs_tck);
+ if (encrypted)
+ {
+ test_fail_if (prep->bypass_aes);
+ test_fail_unless (prep->nek == tp->config.nek[0].nek);
+ /* Compute IV. */
+ u32 iv[3];
+ u32 *fcw = prep->fc_av.words;
+ iv[0] = (fcw[0] >> 8) | (fcw[1] << 24);
+ iv[1] = (fcw[1] >> 8) | (fcw[2] << 24);
+ iv[2] = (fcw[2] >> 8) | (fcw[3] << 24);
+ test_fail_unless (prep->iv[0] == iv[0]
+ && prep->iv[1] == iv[1]
+ && prep->iv[2] == iv[2]);
+ }
+ else
+ test_fail_unless (prep->bypass_aes);
+ /* Check FC. */
+ pbproc_fc_sof_t fc = prep->fc_av.sof;
+ test_fail_unless (fc.dt_av = PBPROC_FC_DT_SOF
+ && !fc.access
+ && fc.snid == tp->config.snid
+ && fc.stei == tp->config.tei);
+ test_fail_unless (fc.dtei == dtei);
+ test_fail_unless (fc.lid == lid);
+ test_fail_unless (fc.cfs == cfp);
+ test_fail_unless (fc.bdf && !fc.hp10df && !fc.hp11df);
+ test_fail_unless (fc.eks == encrypted ? 3 : 0xf);
+ test_fail_unless (fc.ppb == pbproc_fc_pbb (mfs_seg_nb
+ - main_seg_nb_total));
+ test_fail_unless (fc.ble == tm->ble);
+ test_fail_unless (!fc.pbsz);
+ test_fail_unless (fc.num_sym == MIN (main_seg_nb_total, 3u));
+ test_fail_unless (fc.tmi_av == tmi);
+ test_fail_unless (fc.fl_av ==
+ ((MAC_PAYLOAD_TCK (symb_nb, dx)
+ + rifs_tck)
+ / MAC_TCK_PER_FL));
+ test_fail_unless (fc.mpdu_cnt == 0);
+ test_fail_unless (fc.burst_cnt == 0);
+ test_fail_unless (!fc.bbf);
+ test_fail_unless (fc.mrtfl == 0);
+ test_fail_unless (!fc.dcppcf);
+ test_fail_unless (fc.mcf == bcast);
+ test_fail_unless (!fc.mnbf);
+ test_fail_unless (!fc.rsr);
+ test_fail_unless (fc.clst == 0);
+ test_fail_unless (fc.mfs_cmd_mgmt == PBPROC_FC_MFS_CMD_NOP);
+ test_fail_unless (fc.mfs_cmd_data == PBPROC_FC_MFS_CMD_NOP);
+ test_fail_unless (fc.mfs_rsp_mgmt == PBPROC_FC_MFS_RSP_ACK);
+ test_fail_unless (fc.mfs_rsp_data == PBPROC_FC_MFS_RSP_ACK);
+ test_fail_unless (fc.bm_sacki == 0);
+ /* Chain remaining segments. */
+ pbproc_prep_mpdu_chain (tp->pbproc);
+ /* Check result. */
+ test_fail_unless (prep->valid);
+ test_fail_unless (prep->main_mfs == mfs);
+ test_fail_unless (prep->main_head == seg_first);
+ test_fail_unless (prep->head == seg_first);
+ test_fail_unless (prep->main_seg_nb == main_seg_nb_total);
+ test_fail_unless (prep->main_seg_nb_reserved == 0);
+ test_fail_unless (prep->seg_nb_pending == seg_nb_pending);
+ test_fail_unless (prep->pb_nb_total == main_seg_nb_total +
+ seg_nb_pending);
+ for (seg = seg_first, i = 1; i < main_seg_nb_total;
+ seg = seg->next, i++)
+ ;
+ test_fail_unless (prep->main_tail == seg);
+ test_fail_unless (prep->tail == seg);
+ /* Cancel or acknowledge preparation. */
+ uint acked = main_seg_nb_total
+ - MIN (main_seg_nb_total, BITS_ONES_COUNT (crc_error));
+ uint mfs_seg_nb_after = mfs_seg_nb - acked;
+ if (crc_error == (u64) -1ll)
+ pbproc_prep_mpdu_cancel (tp->pbproc);
+ else if (crc_error == 0)
+ pbproc_prep_mpdu_ack_all (tp->pbproc);
+ else
+ {
+ if (!encoded_sack)
+ {
+ u32 bmp[3];
+ bmp[0] = crc_error & 0xffffffff;
+ bmp[1] = (crc_error >> 32) & 0xffffffff;
+ bmp[2] = 0;
+ pbproc_prep_mpdu_ack_bitmap (tp->pbproc, bmp, 0,
+ MIN (main_seg_nb_total, 64u));
+ }
+ else
+ {
+ u32 si[3];
+ si[0] = encoded_sack & 0xffffffff;
+ si[1] = (encoded_sack >> 32) & 0xffffffff;
+ si[2] = 0;
+ pbproc_prep_mpdu_ack_encoded (tp->pbproc, si, 64);
+ }
+ }
+ /* Check result. */
+ test_fail_unless (mfs->seg_nb == (int) mfs_seg_nb_after);
+ seg = mfs->head;
+ for (i = 0; i < mfs_seg_nb; i++)
+ {
+ if (i >= main_seg_nb_total || (crc_error & (u64) (1ull << i)))
+ {
+ test_fail_unless (seg->header.ssn == i
+ && seg->header.mfbo == 0
+ && seg->header.vpbf == true
+ && seg->header.mmqf == false
+ && seg->header.mfbf == false
+ && seg->header.opsf == false
+ && seg->header.rsvd == 0);
+ seg = seg->next;
+ }
+ }
+ }
+ /* Cleanup. */
+ utils_mfs_tx_cleanup (mfs);
+ if (tmi != PHY_MOD_ROBO || (encrypted && !bcast))
+ dbg_check (mac_store_sta_remove (tp->store, dtei));
+ tp->config.authenticated = false;
+}
+
+void
+prep_mpdu_basic_test_case (test_t t)
+{
+ test_pbproc_t tp;
+ test_case_begin (t, "basic");
+ test_pbproc_init (&tp);
+ test_begin (t, "robo unicast data limit dur")
+ {
+ prep_mpdu_test (t, &tp, 0, false, 30,
+ MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (91, MAC_DX417_TCK)
+ + MAC_RIFS_DEFAULT_TCK + MAC_PREAMBLE_TCK
+ + MAC_FC_AV_TCK,
+ 91, 5, 0, (u64) -1ll, 0, PHY_MOD_ROBO, 0, 0, false);
+ } test_end;
+ test_begin (t, "robo unicast data limit seg")
+ {
+ prep_mpdu_test (t, &tp, 0, false, 3,
+ MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (91, MAC_DX417_TCK)
+ + MAC_RIFS_DEFAULT_TCK + MAC_PREAMBLE_TCK
+ + MAC_FC_AV_TCK,
+ 55, 3, 0, (u64) -1ll, 0, PHY_MOD_ROBO, 0, 0, false);
+ } test_end;
+ test_begin (t, "robo unicast data limit dur zero")
+ {
+ prep_mpdu_test (t, &tp, 0, false, 30,
+ MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (16, MAC_DX417_TCK)
+ + MAC_RIFS_DEFAULT_TCK + MAC_PREAMBLE_TCK
+ + MAC_FC_AV_TCK,
+ 0, 0, 0, (u64) -1ll, 0, PHY_MOD_ROBO, 0, 0, false);
+ } test_end;
+ test_begin (t, "robo multicast data limit dur")
+ {
+ prep_mpdu_test (t, &tp, 0, true, 30,
+ MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (91, MAC_DX417_TCK)
+ + MAC_RIFS_DEFAULT_TCK + MAC_PREAMBLE_TCK
+ + MAC_FC_AV_TCK,
+ 91, 5, 0, (u64) -1ll, 0, PHY_MOD_ROBO, 0, 0, false);
+ } test_end;
+ test_begin (t, "hs-robo unicast data limit seg")
+ {
+ prep_mpdu_test (t, &tp, 0, false, 3,
+ MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (91, MAC_DX417_TCK)
+ + MAC_RIFS_DEFAULT_TCK + MAC_PREAMBLE_TCK
+ + MAC_FC_AV_TCK,
+ 28, 3, 0, (u64) -1ll, 0, PHY_MOD_HS_ROBO, 0, 0, false);
+ } test_end;
+ test_begin (t, "acked all")
+ {
+ prep_mpdu_test (t, &tp, 0, false, 30,
+ MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (91, MAC_DX417_TCK)
+ + MAC_RIFS_DEFAULT_TCK + MAC_PREAMBLE_TCK
+ + MAC_FC_AV_TCK,
+ 91, 5, 0, 0, 0, PHY_MOD_ROBO, 0, 0, false);
+ } test_end;
+ test_begin (t, "acked bitmap")
+ {
+ prep_mpdu_test (t, &tp, 0, false, 30,
+ MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (91, MAC_DX417_TCK)
+ + MAC_RIFS_DEFAULT_TCK + MAC_PREAMBLE_TCK
+ + MAC_FC_AV_TCK,
+ 91, 5, 0, 0x15, 0, PHY_MOD_ROBO, 0, 0, false);
+ prep_mpdu_test (t, &tp, 0, false, 41,
+ MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (30, MAC_DX417_TCK)
+ + MAC_RIFS_SPC_ANY_TCK + MAC_PREAMBLE_TCK
+ + MAC_FC_AV_TCK,
+ 25, 41, 0, 0x150fa5c03aull, 0, PHY_MOD_TM, 10, 0, false);
+ } test_end;
+ test_begin (t, "acked encoded bitmap")
+ {
+ prep_mpdu_test (t, &tp, 0, false, 30,
+ MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (91, MAC_DX417_TCK)
+ + MAC_RIFS_DEFAULT_TCK + MAC_PREAMBLE_TCK
+ + MAC_FC_AV_TCK,
+ 91, 5, 0, 0x15, 0x6f, PHY_MOD_ROBO, 0, 0, false);
+ prep_mpdu_test (t, &tp, 0, false, 41,
+ MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (30, MAC_DX417_TCK)
+ + MAC_RIFS_SPC_ANY_TCK + MAC_PREAMBLE_TCK
+ + MAC_FC_AV_TCK,
+ 25, 41, 0, 0x150fa5c03aull, 0x066bffc9fd3f9ull,
+ PHY_MOD_TM, 10, 0, false);
+ prep_mpdu_test (t, &tp, 0, false, 32,
+ MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (30, MAC_DX417_TCK)
+ + MAC_RIFS_SPC_ANY_TCK + MAC_PREAMBLE_TCK
+ + MAC_FC_AV_TCK,
+ 20, 32, 0, 0xf9ffffffull, 0xbfffffffffffffffull,
+ PHY_MOD_TM, 10, 0, false);
+ } test_end;
+ test_begin (t, "tm unicast data limit dur")
+ {
+ prep_mpdu_test (t, &tp, 0, false, 30,
+ MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (10, MAC_DX417_TCK)
+ + MAC_RIFS_SPC_ANY_TCK + MAC_PREAMBLE_TCK
+ + MAC_FC_AV_TCK,
+ 10, 10, 0, (u64) -1ll, 0, PHY_MOD_TM, 6, 0, false);
+ prep_mpdu_test (t, &tp, 0, false, 30,
+ MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (10, MAC_DX417_TCK)
+ + MAC_RIFS_SPC_ANY_TCK + MAC_PREAMBLE_TCK
+ + MAC_FC_AV_TCK,
+ 10, 16, 0, (u64) -1ll, 0, PHY_MOD_TM, 10, 0, false);
+ } test_end;
+ test_begin (t, "tm unicast data limit seg with null")
+ {
+ prep_mpdu_test (t, &tp, 0, false, 13,
+ MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (9, MAC_DX417_TCK)
+ + MAC_RIFS_SPC_ANY_TCK + MAC_PREAMBLE_TCK
+ + MAC_FC_AV_TCK,
+ 9, 13, 1, (u64) -1ll, 0, PHY_MOD_TM, 10, 0, false);
+ } test_end;
+ test_begin (t, "tm unicast data limit dur bis")
+ {
+ prep_mpdu_test (t, &tp, 0, false, 13,
+ MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (8, MAC_DX417_TCK)
+ + MAC_RIFS_SPC_ANY_TCK + MAC_PREAMBLE_TCK
+ + MAC_FC_AV_TCK,
+ 8, 12, 0, (u64) -1ll, 0, PHY_MOD_TM, 10, 0, false);
+ } test_end;
+ test_begin (t, "tm unicast data limit dur tm")
+ {
+ prep_mpdu_test (t, &tp, 0, false, 60,
+ MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (91, MAC_DX417_TCK)
+ + MAC_RIFS_DEFAULT_TCK + MAC_PREAMBLE_TCK
+ + MAC_FC_AV_TCK,
+ 30, 49, 0, (u64) -1ll, 0, PHY_MOD_TM, 10,
+ MAC_PAYLOAD_TCK (30, MAC_DX417_TCK)
+ + MAC_RIFS_SPC_ANY_TCK, false);
+ } test_end;
+ test_begin (t, "tm unicast data limit dur zero")
+ {
+ prep_mpdu_test (t, &tp, 0, false, 5,
+ MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (0, MAC_DX417_TCK)
+ + MAC_RIFS_SPC_ANY_TCK + MAC_PREAMBLE_TCK
+ + MAC_FC_AV_TCK,
+ 0, 0, 0, (u64) -1ll, 0, PHY_MOD_TM, 10, 0, false);
+ } test_end;
+ test_begin (t, "tm unicast data limit dur one")
+ {
+ prep_mpdu_test (t, &tp, 0, false, 5,
+ MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (1, MAC_DX417_TCK)
+ + MAC_RIFS_SPC_ANY_TCK + MAC_PREAMBLE_TCK
+ + MAC_FC_AV_TCK,
+ 1, 1, 0, (u64) -1ll, 0, PHY_MOD_TM, 10, 0, false);
+ } test_end;
+ test_begin (t, "tm unicast data limit dur two")
+ {
+ prep_mpdu_test (t, &tp, 0, false, 5,
+ MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (2, MAC_DX417_TCK)
+ + MAC_RIFS_SPC_ANY_TCK + MAC_PREAMBLE_TCK
+ + MAC_FC_AV_TCK,
+ 2, 2, 0, (u64) -1ll, 0, PHY_MOD_TM, 10, 0, false);
+ } test_end;
+ test_begin (t, "robo unicast data limit dur encrypted")
+ {
+ prep_mpdu_test (t, &tp, 0, false, 30,
+ MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (91, MAC_DX417_TCK)
+ + MAC_RIFS_DEFAULT_TCK + MAC_PREAMBLE_TCK
+ + MAC_FC_AV_TCK,
+ 91, 5, 0, (u64) -1ll, 0, PHY_MOD_ROBO, 0, 0, true);
+ } test_end;
+ test_begin (t, "robo multicast data limit dur encrypted")
+ {
+ prep_mpdu_test (t, &tp, 0, true, 30,
+ MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (91, MAC_DX417_TCK)
+ + MAC_RIFS_DEFAULT_TCK + MAC_PREAMBLE_TCK
+ + MAC_FC_AV_TCK,
+ 91, 5, 0, (u64) -1ll, 0, PHY_MOD_ROBO, 0, 0, true);
+ } test_end;
+ test_pbproc_uninit (&tp);
+}
+
+void
+prep_beacon_test (test_t t, test_pbproc_t *tp, u32 date, bool prepared,
+ uint duration_tck, uint symb_nb)
+{
+ test_within (t);
+ dbg_assert (tp);
+ const uint beacon_tck = MAC_MS_TO_TCK (1000) / 50;
+ const u32 beacon_period_start_date = date / beacon_tck * beacon_tck;
+ /* Create a beacon MFS. */
+ mfs_tx_t *mfs = utils_mfs_tx_prepare (true, false, MAC_LID_SPC_CENTRAL,
+ MAC_TEI_BCAST, 0);
+ mfs->cfp = true;
+ mfs->beacon = true;
+ pb_t *seg = NULL;
+ pbproc_tx_beacon_params_t params =
+ { { 0x0123, 0x4242, 0xabab, 0x5555 }, NULL };
+ if (prepared)
+ {
+ pb_beacon_t *pb = PARENT_OF (pb_beacon_t, blk, blk_alloc_desc ());
+ seg = (pb_t *) pb;
+ params.bpsto = pb->data + 123;
+ pbproc_mfs_beacon_prepare (tp->pbproc, mfs, pb, &params);
+ }
+ /* Setup an access. */
+ ca_access_param_t *access = &tp->pbproc->access;
+ access->mfs = mfs;
+ access->access_date = date;
+ access->beacon_period_start_date = beacon_period_start_date;
+ access->duration_tck = duration_tck;
+ access->cfp = true;
+ access->hybrid = true;
+ /* Prepare beacon. */
+ pbproc_prep_beacon (tp->pbproc);
+ /* Check result. */
+ pbproc_prep_mpdu_t *prep = &tp->pbproc->prep_mpdu;
+ test_fail_unless (prep->dtei == MAC_TEI_BCAST);
+ test_fail_unless (prep->lid == MAC_LID_NONE);
+ test_fail_unless (!prep->wack);
+ test_fail_unless (!prep->rts_cts);
+ test_fail_unless (!prep->burst);
+ if (symb_nb)
+ {
+ test_fail_unless (prep->valid);
+ test_fail_unless (prep->main_mfs == mfs);
+ test_fail_unless (prep->combined_mfs == NULL);
+ test_fail_unless (prep->tx_date == date);
+ test_fail_unless (prep->fc_mode == PHY_FC_MODE_HYBRID_1);
+ test_fail_unless (prep->mod == PHY_MOD_MINI_ROBO);
+ test_fail_unless (prep->fecrate == PHY_FEC_RATE_1_2);
+ test_fail_unless (prep->pb_size == PHY_PB_SIZE_136);
+ test_fail_unless (prep->gil == PHY_GIL_567);
+ test_fail_unless (prep->tonemap == NULL);
+ test_fail_unless (prep->flp_tck == MAC_PREAMBLE_HYBRID_TCK
+ + MAC_FC_10_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (symb_nb, MAC_DX567_TCK)
+ + MAC_B2BIFS_TCK);
+ test_fail_unless (prep->main_head == seg);
+ test_fail_unless (prep->main_tail == seg);
+ test_fail_unless (prep->main_seg_nb == 1);
+ test_fail_unless (prep->main_seg_nb_reserved == 0);
+ test_fail_unless (prep->head == seg);
+ test_fail_unless (prep->tail == seg);
+ test_fail_unless (prep->pb_nb_total == 1);
+ test_fail_unless (prep->bypass_aes);
+ /* Check FC. */
+ pbproc_fc_beacon_t *fc = &prep->fc_av.beacon;
+ test_fail_unless (fc->dt_av == PBPROC_FC_DT_BEACON);
+ test_fail_unless (fc->access == false
+ && fc->snid == tp->config.snid);
+ uint bts = fc->bts_msb8 << 24 | fc->bts_lsb24;
+ uint bto[4] = {
+ fc->bto0,
+ fc->bto1_msb8 << 8 | fc->bto1_lsb8,
+ fc->bto2,
+ fc->bto3_msb8 << 8 | fc->bto3_lsb8
+ };
+ test_fail_unless (bts == date);
+ test_fail_unless (bto[0] == params.bto[0]);
+ test_fail_unless (bto[1] == params.bto[1]);
+ test_fail_unless (bto[2] == params.bto[2]);
+ test_fail_unless (bto[3] == params.bto[3]);
+ /* Check payload (BPSTO). */
+ uint bpsto = params.bpsto[0]
+ | params.bpsto[1] << 8
+ | params.bpsto[2] << 16;
+ test_fail_unless (bpsto == date - beacon_period_start_date);
+ /* Cancel preparation. */
+ pbproc_prep_mpdu_cancel (tp->pbproc);
+ /* Check result. */
+ test_fail_unless (mfs->seg_nb == 1);
+ test_fail_unless (mfs->head == seg);
+ test_fail_unless (mfs->tail == seg);
+ }
+ else
+ {
+ test_fail_unless (!prep->valid);
+ test_fail_unless (prep->main_mfs == NULL);
+ test_fail_unless (prep->combined_mfs == NULL);
+ test_fail_unless (prep->main_seg_nb == 0);
+ test_fail_unless (prep->main_seg_nb_reserved == 0);
+ test_fail_unless (prep->pb_nb_total == 0);
+ /* Check MFS. */
+ if (prepared)
+ {
+ test_fail_unless (mfs->seg_nb == 1);
+ test_fail_unless (mfs->head == seg);
+ test_fail_unless (mfs->tail == seg);
+ }
+ else
+ {
+ test_fail_unless (mfs->seg_nb == 0);
+ test_fail_unless (mfs->head == NULL);
+ }
+ }
+ /* Cleanup. */
+ utils_mfs_tx_cleanup (mfs);
+}
+
+void
+prep_mpdu_beacon_test_case (test_t t)
+{
+ test_pbproc_t tp;
+ test_case_begin (t, "beacon");
+ test_pbproc_init (&tp);
+ test_begin (t, "valid")
+ {
+ prep_beacon_test (t, &tp, 123456, true, MAC_PREAMBLE_HYBRID_TCK
+ + MAC_FC_10_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (6, MAC_DX567_TCK)
+ + MAC_B2BIFS_TCK, 6);
+ } test_end;
+ test_begin (t, "unvalid")
+ {
+ prep_beacon_test (t, &tp, 54321, true, MAC_PREAMBLE_HYBRID_TCK
+ + MAC_FC_10_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (6, MAC_DX567_TCK), 0);
+ } test_end;
+ test_begin (t, "no seg")
+ {
+ prep_beacon_test (t, &tp, 54321, false, MAC_PREAMBLE_HYBRID_TCK
+ + MAC_FC_10_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (6, MAC_DX567_TCK)
+ + MAC_B2BIFS_TCK, 0);
+ } test_end;
+ test_pbproc_uninit (&tp);
+}
+
+void
+prep_mpdu_test_suite (test_t t)
+{
+ test_suite_begin (t, "prepare mpdu");
+ prep_mpdu_basic_test_case (t);
+ prep_mpdu_beacon_test_case (t);
+ test_case_begin (t, "memory");
+ test_begin (t, "memory")
+ {
+ test_fail_unless (blk_check_memory ());
+ } test_end;
+}
+
diff --git a/cesar/mac/pbproc/test/pbproc/src/rx_data.c b/cesar/mac/pbproc/test/pbproc/src/rx_data.c
new file mode 100644
index 0000000000..7d6c3f1f6e
--- /dev/null
+++ b/cesar/mac/pbproc/test/pbproc/src/rx_data.c
@@ -0,0 +1,624 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file src/rx_data.c
+ * \brief RX Data automaton test.
+ * \ingroup test
+ */
+#include "common/std.h"
+
+#include "inc/scenario.h"
+#include "inc/utils.h"
+
+#include "inc/test_pbproc.h"
+
+#include "mac/common/timings.h"
+#include "mac/pbproc/inc/context.h"
+#include "hal/phy/inc/context.h"
+
+void
+rx_data_test (test_t t, test_pbproc_t *tp, u32 date, uint symb_nb, uint pb_nb,
+ uint pool_pb_nb, bool prp_won, uint tmi, uint tm_mod,
+ bool encrypted, bool sta_auth, uint nek_switch, u32 *crc_error)
+{
+ test_within (t);
+ const uint lid = 1;
+ const uint stei = 2;
+ /* Prepare tone map. */
+ tonemap_t *tm = &tp->config.tonemask_info.tonemap_robo[PHY_MOD_ROBO];
+ uint dx = MAC_DX417_TCK;
+ if (tmi != PHY_MOD_ROBO || (encrypted && sta_auth))
+ tm = utils_sta_prepare_default_tonemap (tp, false, stei, tmi, tm_mod,
+ 0, &dx);
+ uint rifs_tck = symb_nb == 0 || tmi < PHY_MOD_ROBO_NB
+ ? MAC_RIFS_DEFAULT_TCK : MAC_RIFS_SPC_ANY_TCK;
+ /* Encrypted? */
+ utils_prepare_encryption (tp, encrypted, sta_auth, stei, nek_switch);
+ /* Prepare fc. */
+ const uint fl_tck = MAC_PAYLOAD_TCK (symb_nb, dx)
+ + rifs_tck;
+ pbproc_fc_sof_t sof_fc = {
+ .dt_av = PBPROC_FC_DT_SOF,
+ .access = false,
+ .snid = tp->config.snid,
+ .stei = stei,
+ .dtei = tp->config.tei,
+ .lid = lid,
+ .cfs = false,
+ .bdf = true,
+ .hp10df = false,
+ .hp11df = false,
+ .eks = encrypted ? 3 : 0xf,
+ .ppb = 42,
+ .ble = 0x42,
+ .pbsz = false,
+ .num_sym = MIN (symb_nb, 3u),
+ .tmi_av = tmi,
+ .fl_av = fl_tck / MAC_TCK_PER_FL,
+ .mpdu_cnt = 0,
+ .burst_cnt = 0,
+ .bdf = false,
+ .mrtfl = 0,
+ .dcppcf = false,
+ .mcf = false,
+ .mnbf = false,
+ .rsr = false,
+ .clst = 0,
+ .mfs_cmd_mgmt = PBPROC_FC_MFS_CMD_NOP,
+ .mfs_cmd_data = PBPROC_FC_MFS_CMD_NOP,
+ .mfs_rsp_mgmt = PBPROC_FC_MFS_RSP_ACK,
+ .mfs_rsp_data = PBPROC_FC_MFS_RSP_ACK,
+ .bm_sacki = 0,
+ .fccs_av = 0,
+ };
+ const uint pre_fc_fl_tck = MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_FL_TO_TCK (fl_tck / MAC_TCK_PER_FL);
+ uint nb_pb_it = pb_nb > PBPROC_SACKD_ANTICIP_PB_THRESHOLD
+ ? pb_nb - PBPROC_SACKD_ANTICIP_PB_NB : pb_nb;
+ scenario_entry_t entries[] = {
+ SCENARIO_ACTION (phy_rx_fc, .rx_date = date, .prp_won = prp_won,
+ .slot_count = 2,
+ .fc_av = PARENT_OF (pbproc_fc_t, sof,
+ &sof_fc)->words),
+ SCENARIO_EVENT (ca_backoff_deferred, .slot_count = 0),
+ SCENARIO_EVENT (ca_access_hold),
+ SCENARIO_EVENT (phy_rx_prepare, .short_ppdu = false,
+ .mod = PHY_MOD_ROBO, .fecrate = PHY_FEC_RATE_NONE,
+ .pb_size = PHY_PB_SIZE_NONE, .gil = PHY_GIL_NONE,
+ .tonemap_index = 0, .symbol_nb = symb_nb),
+ SCENARIO_EVENT (phy_pbdma_start, .bypass_aes = !encrypted,
+ .nb_total = pb_nb, .nb_ready = pb_nb,
+ .nb_pb_it = nb_pb_it),
+ /* if (pb_nb != nb_pb_it) { */
+ SCENARIO_ACTION (phy_pbdma, .pb_it = true, .crc_bitmap = crc_error,
+ .crc_bitmap_bits = nb_pb_it),
+ SCENARIO_EVENT (phy_pbdma_update, .nb_ready = pb_nb,
+ .nb_pb_it = pb_nb),
+ /* } */
+ SCENARIO_ACTION (phy_pbdma, .pb_it = true, .end_rx_pb = true,
+ .pb_crc_error = !!crc_error, .crc_bitmap = crc_error,
+ .crc_bitmap_bits = pb_nb),
+ SCENARIO_EVENT (phy_tx_param, .fc_mode = PHY_FC_MODE_AV_1,
+ .short_ppdu = true),
+ SCENARIO_EVENT (phy_tx_frame, .date = date + pre_fc_fl_tck,
+ .want_conf = false, .stop_tx_on_prp_lost = false),
+ SCENARIO_EVENT (pbproc_rx_cb, .pb_nb = pb_nb),
+ SCENARIO_EVENT (ca_access_vcs_restart,
+ .start_date = date + pre_fc_fl_tck,
+ .length_tck = MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_CIFS_TCK,
+ .anticipation_tck = PBPROC_ANTICIP_TCK,
+ .eifs = false),
+ SCENARIO_END
+ };
+ if (!prp_won)
+ entries[1].event_id = SCENARIO_EVENT_ca_backoff_cancel;
+ if (pb_nb == nb_pb_it)
+ {
+ entries[5].event_id = SCENARIO_NOP_ID;
+ entries[6].event_id = SCENARIO_NOP_ID;
+ }
+ scenario_globals_t globals = {
+ .tp = tp,
+ };
+ blk_t *first, *last;
+ first = blk_alloc_desc_range (pool_pb_nb, &last);
+ pbproc_rx_segment_refill (tp->pbproc, PARENT_OF (pb_t, blk, first),
+ PARENT_OF (pb_t, blk, last), pool_pb_nb);
+ scenario_run (t, entries, &globals);
+ test_fail_unless (tp->pbproc->rx_pool_size == pool_pb_nb - pb_nb);
+ if (tp->pbproc->rx_pool_size)
+ {
+ blk_release_desc_range (&tp->pbproc->rx_pool_head->blk,
+ &tp->pbproc->rx_pool_tail->blk);
+ tp->pbproc->rx_pool_head = tp->pbproc->rx_pool_tail = NULL;
+ tp->pbproc->rx_pool_size = 0;
+ }
+ if (tmi != PHY_MOD_ROBO || (encrypted && sta_auth))
+ dbg_check (mac_store_sta_remove (tp->store, stei));
+ tp->config.authenticated = false;
+ test_fail_unless (tp->pbproc->fsm.current_state == PBPROC_FSM_STATE_IDLE);
+}
+
+void
+rx_beacon_test (test_t t, test_pbproc_t *tp, u32 date, uint symb_nb)
+{
+ test_within (t);
+ pbproc_fc_beacon_t beacon_fc = {
+ .dt_av = PBPROC_FC_DT_BEACON,
+ .access = false,
+ .snid = tp->config.snid,
+ .bts_lsb24 = 0x345678,
+ .bts_msb8 = 0x12,
+ .bto0 = 0x0123,
+ .bto1_lsb8 = 0x34,
+ .bto1_msb8 = 0x12,
+ .bto2 = 0x2345,
+ .bto3_lsb8 = 0x56,
+ .bto3_msb8 = 0x34,
+ .fccs_av = 0,
+ };
+ const uint pre_fc_fl_tck = MAC_PREAMBLE_HYBRID_TCK + MAC_FC_10_TCK
+ + MAC_FC_AV_TCK + MAC_PAYLOAD_TCK (symb_nb, MAC_DX567_TCK)
+ + MAC_B2BIFS_TCK;
+ scenario_entry_t entries[] = {
+ SCENARIO_ACTION (phy_rx_fc, .rx_date = date, .rx_sysdate = date / 2,
+ .prp_won = false,
+ .fc_av = PARENT_OF (pbproc_fc_t, beacon,
+ &beacon_fc)->words),
+ SCENARIO_EVENT (ca_backoff_cancel),
+ SCENARIO_EVENT (ca_access_hold),
+ SCENARIO_EVENT (phy_rx_prepare, .short_ppdu = false,
+ .mod = PHY_MOD_MINI_ROBO,
+ .fecrate = PHY_FEC_RATE_NONE,
+ .pb_size = PHY_PB_SIZE_NONE, .gil = PHY_GIL_NONE,
+ .tonemap_index = 0, .symbol_nb = symb_nb),
+ SCENARIO_EVENT (phy_pbdma_start, .bypass_aes = true,
+ .nb_total = 1, .nb_ready = 1, .nb_pb_it = 1),
+ SCENARIO_EVENT (ca_access_vcs_restart,
+ .start_date = date,
+ .length_tck = pre_fc_fl_tck,
+ .anticipation_tck = PBPROC_ANTICIP_TCK,
+ .eifs = false),
+ SCENARIO_ACTION (phy_pbdma, .pb_it = true, .end_rx_pb = true),
+ SCENARIO_EVENT (pbproc_rx_beacon_cb),
+ SCENARIO_END
+ };
+ scenario_globals_t globals = {
+ .tp = tp,
+ };
+ blk_t *pb;
+ pb = blk_alloc_desc ();
+ uint old_pool_size = tp->pbproc->rx_pool_size;
+ pbproc_rx_segment_refill (tp->pbproc, PB_FROM_BLK (pb), PB_FROM_BLK (pb),
+ 1);
+ scenario_run (t, entries, &globals);
+ test_fail_unless (tp->pbproc->rx_pool_size == old_pool_size);
+ test_fail_unless (old_pool_size != 0 || tp->pbproc->rx_pool_head == NULL);
+ test_fail_unless (tp->pbproc->fsm.current_state == PBPROC_FSM_STATE_IDLE);
+}
+
+void
+rx_data_basic_test_case (test_t t)
+{
+ test_pbproc_t tp;
+ test_case_begin (t, "basic");
+ test_pbproc_init (&tp);
+ test_begin (t, "robo unicast")
+ {
+ rx_data_test (t, &tp, 5462132, 91, 5, 5, false, PHY_MOD_ROBO, 0,
+ false, false, 0, NULL);
+ rx_data_test (t, &tp, 5462132, 91, 5, 7, true, PHY_MOD_ROBO, 0,
+ false, false, 0, NULL);
+ } test_end;
+ test_begin (t, "hs-robo unicast")
+ {
+ rx_data_test (t, &tp, 54621, 46, 5, 5, false, PHY_MOD_HS_ROBO, 0,
+ false, false, 0, NULL);
+ } test_end;
+ test_begin (t, "tm unicast")
+ {
+ rx_data_test (t, &tp, 54621, 4, 6, 6, false, 5, 10, false, false, 0,
+ NULL);
+ rx_data_test (t, &tp, 54621, 1, 1, 1, false, 5, 10, false, false, 0,
+ NULL);
+ rx_data_test (t, &tp, 54621, 2, 2, 2, false, 5, 10, false, false, 0,
+ NULL);
+ } test_end;
+ test_begin (t, "tm unicast large")
+ {
+ rx_data_test (t, &tp, 541, 25, 41, 41, false, 5, 10, false, false, 0,
+ NULL);
+ } test_end;
+ test_begin (t, "robo unicast encrypted sta unknown")
+ {
+ rx_data_test (t, &tp, 5462132, 91, 5, 5, false, PHY_MOD_ROBO, 0,
+ true, false, 0, NULL);
+ rx_data_test (t, &tp, 5462132, 91, 5, 5, false, PHY_MOD_ROBO, 0,
+ true, false, 1, NULL);
+ } test_end;
+ test_begin (t, "robo unicast encrypted sta known")
+ {
+ rx_data_test (t, &tp, 5462132, 91, 5, 5, false, PHY_MOD_ROBO, 0,
+ true, true, 0, NULL);
+ rx_data_test (t, &tp, 5462132, 91, 5, 5, false, PHY_MOD_ROBO, 0,
+ true, true, 1, NULL);
+ } test_end;
+ test_begin (t, "robo unicast crc error none")
+ {
+ u32 crc_error[8] = { 0x00, };
+ rx_data_test (t, &tp, 5462132, 91, 5, 5, false, PHY_MOD_ROBO, 0,
+ false, false, 0, crc_error);
+ } test_end;
+ test_begin (t, "robo unicast crc error one")
+ {
+ u32 crc_error[8] = { 0x01, };
+ rx_data_test (t, &tp, 5462132, 91, 5, 5, false, PHY_MOD_ROBO, 0,
+ false, false, 0, crc_error);
+ } test_end;
+ test_begin (t, "robo unicast crc error many")
+ {
+ u32 crc_error[8] = { 0x1d, };
+ rx_data_test (t, &tp, 5462132, 91, 5, 5, false, PHY_MOD_ROBO, 0,
+ false, false, 0, crc_error);
+ } test_end;
+ test_begin (t, "tm unicast large crc error few")
+ {
+ u32 crc_error[8] = { 0x10000001, 0x010 };
+ rx_data_test (t, &tp, 541, 25, 41, 41, false, 5, 10, false, false, 0,
+ crc_error);
+ } test_end;
+ test_begin (t, "tm unicast large crc error many")
+ {
+ u32 crc_error[8] = { 0xffefdff7, 0x1fb };
+ rx_data_test (t, &tp, 541, 25, 41, 41, false, 5, 10, false, false, 0,
+ crc_error);
+ } test_end;
+ test_begin (t, "beacon")
+ {
+ rx_beacon_test (t, &tp, 123654, 6);
+ blk_t *pb;
+ pb = blk_alloc_desc ();
+ pbproc_rx_segment_refill (tp.pbproc, PB_FROM_BLK (pb),
+ PB_FROM_BLK (pb), 1);
+ rx_beacon_test (t, &tp, 123654, 6);
+ } test_end;
+ test_pbproc_uninit (&tp);
+}
+
+enum rx_data_nfu_t
+{
+ NFU_SACK,
+ NFU_SOF_ACCESS,
+ NFU_SOF_SNID,
+ NFU_SOF_TEI,
+};
+typedef enum rx_data_nfu_t rx_data_nfu_t;
+
+void
+rx_data_nfu_test (test_t t, test_pbproc_t *tp, u32 date, rx_data_nfu_t nfu)
+{
+ test_within (t);
+ uint length_tck;
+ pbproc_fc_t fc;
+ const uint sof_fl_tck = MAC_PAYLOAD_TCK (45, MAC_DX417_TCK)
+ + MAC_RIFS_DEFAULT_TCK;
+ pbproc_fc_sof_t sof_fc = {
+ .dt_av = PBPROC_FC_DT_SOF,
+ .access = nfu == NFU_SOF_ACCESS,
+ .snid = nfu != NFU_SOF_SNID ? tp->config.snid : tp->config.snid + 1,
+ .stei = 2,
+ .dtei = nfu != NFU_SOF_TEI ? tp->config.tei : tp->config.tei + 8,
+ .lid = 1,
+ .cfs = false,
+ .bdf = true,
+ .hp10df = false,
+ .hp11df = false,
+ .eks = 0xf,
+ .ppb = 42,
+ .ble = 0x42,
+ .pbsz = false,
+ .num_sym = MIN (45u, 3u),
+ .tmi_av = PHY_MOD_ROBO,
+ .fl_av = sof_fl_tck / MAC_TCK_PER_FL,
+ .mpdu_cnt = 0,
+ .burst_cnt = 0,
+ .bdf = false,
+ .mrtfl = 0,
+ .dcppcf = false,
+ .mcf = false,
+ .mnbf = false,
+ .rsr = false,
+ .clst = 0,
+ .mfs_cmd_mgmt = PBPROC_FC_MFS_CMD_NOP,
+ .mfs_cmd_data = PBPROC_FC_MFS_CMD_NOP,
+ .mfs_rsp_mgmt = PBPROC_FC_MFS_RSP_ACK,
+ .mfs_rsp_data = PBPROC_FC_MFS_RSP_ACK,
+ .bm_sacki = 0,
+ .fccs_av = 0,
+ };
+ pbproc_fc_sack_t sack_fc = {
+ .dt_av = PBPROC_FC_DT_SACK,
+ .access = false,
+ .snid = tp->config.snid,
+ .dtei = tp->config.tei,
+ .cfs = false,
+ .bdf = true,
+ .svn = 0,
+ .rrtf = false,
+ .mfs_rsp_data = PBPROC_FC_MFS_RSP_ACK,
+ .mfs_rsp_mgmt = PBPROC_FC_MFS_RSP_ACK,
+ .sackt3 = 0,
+ .sackt2 = 0,
+ .sackt1 = 0,
+ .sackt0 = 0,
+ .sacki[0] = 0,
+ .sacki[1] = 0,
+ .sacki_last = 0,
+ .fccs_av = 0,
+ };
+ if (nfu == NFU_SACK)
+ {
+ fc.sack = sack_fc;
+ length_tck = MAC_PREAMBLE_TCK + MAC_FC_AV_TCK + MAC_CIFS_TCK;
+ }
+ else
+ {
+ fc.sof = sof_fc;
+ length_tck = MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_FL_TO_TCK (sof_fl_tck / MAC_TCK_PER_FL)
+ + MAC_PREAMBLE_TCK + MAC_FC_AV_TCK + MAC_CIFS_TCK;
+ }
+ scenario_entry_t entries[] = {
+ SCENARIO_ACTION (phy_rx_fc, .rx_date = date, .prp_won = false,
+ .slot_count = 2, .fc_av = fc.words),
+ SCENARIO_EVENT (ca_backoff_cancel),
+ SCENARIO_EVENT (ca_access_hold),
+ SCENARIO_EVENT (phy_rx_prepare, .short_ppdu = true),
+ SCENARIO_EVENT (ca_access_vcs_restart,
+ .start_date = date,
+ .length_tck = length_tck,
+ .anticipation_tck = PBPROC_ANTICIP_TCK,
+ .eifs = false),
+ SCENARIO_END
+ };
+ scenario_globals_t globals = {
+ .tp = tp,
+ };
+ scenario_run (t, entries, &globals);
+ test_fail_unless (tp->pbproc->fsm.current_state == PBPROC_FSM_STATE_IDLE);
+}
+
+enum rx_data_sack_error_t
+{
+ SACK_ERROR_TM_TMI_UNAVAILABLE,
+ SACK_ERROR_TM_STA_UNAVAILABLE,
+ SACK_ERROR_ENC_STA_NO_NEK,
+ SACK_ERROR_ENC_NO_EKS,
+};
+typedef enum rx_data_sack_error_t rx_data_sack_error_t;
+
+void
+rx_data_sack_error_test (test_t t, test_pbproc_t *tp,
+ rx_data_sack_error_t sack_error)
+{
+ uint date = 123456;
+ test_within (t);
+ uint sack_uniform[] = {
+ PBPROC_FC_SACKI_UNIFORM_TMI_RESTART,
+ PBPROC_FC_SACKI_UNIFORM_TMI_RESTART,
+ PBPROC_FC_SACKI_UNIFORM_NEK_ERROR,
+ PBPROC_FC_SACKI_UNIFORM_NEK_ERROR,
+ };
+ const uint fl_tck = MAC_PAYLOAD_TCK (45, MAC_DX417_TCK)
+ + MAC_RIFS_DEFAULT_TCK;
+ bool sta = false;
+ if (sack_error == SACK_ERROR_TM_TMI_UNAVAILABLE
+ || sack_error == SACK_ERROR_ENC_STA_NO_NEK)
+ {
+ mac_store_sta_add (tp->store, 2);
+ sta = true;
+ }
+ uint tmi, eks;
+ if (sack_error == SACK_ERROR_TM_TMI_UNAVAILABLE
+ || sack_error == SACK_ERROR_TM_STA_UNAVAILABLE)
+ {
+ tmi = 5;
+ eks = 0xf;
+ }
+ else
+ {
+ tmi = PHY_MOD_ROBO;
+ eks = 3;
+ }
+ pbproc_fc_sof_t fc = {
+ .dt_av = PBPROC_FC_DT_SOF,
+ .access = false,
+ .snid = tp->config.snid,
+ .stei = 2,
+ .dtei = tp->config.tei,
+ .lid = 1,
+ .cfs = false,
+ .bdf = true,
+ .hp10df = false,
+ .hp11df = false,
+ .eks = eks,
+ .ppb = 42,
+ .ble = 0x42,
+ .pbsz = false,
+ .num_sym = MIN (45u, 3u),
+ .tmi_av = tmi,
+ .fl_av = fl_tck / MAC_TCK_PER_FL,
+ .mpdu_cnt = 0,
+ .burst_cnt = 0,
+ .bdf = false,
+ .mrtfl = 0,
+ .dcppcf = false,
+ .mcf = false,
+ .mnbf = false,
+ .rsr = false,
+ .clst = 0,
+ .mfs_cmd_mgmt = PBPROC_FC_MFS_CMD_NOP,
+ .mfs_cmd_data = PBPROC_FC_MFS_CMD_NOP,
+ .mfs_rsp_mgmt = PBPROC_FC_MFS_RSP_ACK,
+ .mfs_rsp_data = PBPROC_FC_MFS_RSP_ACK,
+ .bm_sacki = 0,
+ .fccs_av = 0,
+ };
+ uint pre_fc_fl_tck = MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_FL_TO_TCK (fl_tck / MAC_TCK_PER_FL);
+ scenario_entry_t entries[] = {
+ SCENARIO_ACTION (phy_rx_fc, .rx_date = date, .prp_won = false,
+ .slot_count = 2,
+ .fc_av = PARENT_OF (pbproc_fc_t, sof, &fc)->words),
+ SCENARIO_EVENT (ca_backoff_cancel),
+ SCENARIO_EVENT (ca_access_hold),
+ SCENARIO_EVENT (phy_rx_prepare, .short_ppdu = true),
+ SCENARIO_EVENT (phy_tx_param, .fc_mode = PHY_FC_MODE_AV_1,
+ .short_ppdu = true),
+ SCENARIO_EVENT (phy_tx_frame, .date = date + pre_fc_fl_tck,
+ .want_conf = false, .stop_tx_on_prp_lost = false),
+ SCENARIO_EVENT (ca_access_vcs_restart,
+ .start_date = date + pre_fc_fl_tck,
+ .length_tck = MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_CIFS_TCK,
+ .anticipation_tck = PBPROC_ANTICIP_TCK,
+ .eifs = false),
+ SCENARIO_END
+ };
+ scenario_globals_t globals = {
+ .tp = tp,
+ };
+ scenario_run (t, entries, &globals);
+ /* Check SACK. */
+ pbproc_fc_sack_t sack = PARENT_OF (pbproc_fc_t, words,
+ tp->pbproc->phy->tx_fc)->sack;
+ test_fail_unless (sack.dt_av == PBPROC_FC_DT_SACK);
+ test_fail_unless (sack.access == false);
+ test_fail_unless (sack.snid == tp->config.snid);
+ test_fail_unless (sack.dtei == 2);
+ test_fail_unless (sack.cfs == false);
+ test_fail_unless (sack.bdf == false);
+ test_fail_unless (sack.svn == 0);
+ test_fail_unless (sack.rrtf == 0);
+ test_fail_unless (sack.mfs_rsp_data == PBPROC_FC_MFS_RSP_ACK);
+ test_fail_unless (sack.mfs_rsp_mgmt == PBPROC_FC_MFS_RSP_ACK);
+ test_fail_unless (sack.sackt3 == 0);
+ test_fail_unless (sack.sackt2 == 0);
+ test_fail_unless (sack.sackt1 == 0);
+ test_fail_unless (sack.sackt0 == PBPROC_FC_SACKT_UNIFORM);
+ test_fail_unless (sack.sacki[0] == sack_uniform[sack_error]);
+ test_fail_unless (sack.sacki[1] == 0);
+ test_fail_unless (sack.sacki_last == 0);
+ /* Cleanup. */
+ if (sta)
+ dbg_check (mac_store_sta_remove (tp->store, 2));
+ test_fail_unless (tp->pbproc->fsm.current_state == PBPROC_FSM_STATE_IDLE);
+}
+
+void
+rx_data_errors_test_case (test_t t)
+{
+ test_pbproc_t tp;
+ test_case_begin (t, "errors");
+ test_pbproc_init (&tp);
+ test_begin (t, "crc error")
+ {
+ uint date = 12345678;
+ scenario_entry_t entries[] = {
+ SCENARIO_ACTION (phy_rx_fc, .rx_date = date,
+ .rx_sysdate = date * 21 / 20,
+ .prp_won = false, .fc_av = NULL),
+ SCENARIO_EVENT (ca_backoff_cancel),
+ SCENARIO_EVENT (ca_access_hold),
+ SCENARIO_EVENT (phy_rx_prepare, .short_ppdu = true),
+ SCENARIO_EVENT (ca_access_vcs_restart,
+ .start_date = date,
+ .length_tck = MAC_EIFS_AV_TCK,
+ .anticipation_tck = PBPROC_ANTICIP_TCK,
+ .eifs = true),
+ SCENARIO_EVENT (phy_rx_activate, .now = true,
+ .pre_detection = true),
+ SCENARIO_END
+ };
+ scenario_globals_t globals = {
+ .tp = &tp,
+ };
+ scenario_run (t, entries, &globals);
+ test_fail_unless (tp.pbproc->fsm.current_state
+ == PBPROC_FSM_STATE_IDLE);
+ } test_end;
+ test_begin (t, "unknown fc")
+ {
+ uint date = 654879;
+ pbproc_fc_generic_t fc = {
+ .dt_av = 0x7,
+ .access = false,
+ .snid = tp.config.snid,
+ };
+ scenario_entry_t entries[] = {
+ SCENARIO_ACTION (phy_rx_fc, .rx_date = date,
+ .rx_sysdate = date * 21 / 20,
+ .prp_won = false,
+ .fc_av = PARENT_OF (pbproc_fc_t, generic,
+ &fc)->words),
+ SCENARIO_EVENT (ca_backoff_cancel),
+ SCENARIO_EVENT (ca_access_hold),
+ SCENARIO_EVENT (phy_rx_prepare, .short_ppdu = true),
+ SCENARIO_EVENT (ca_access_vcs_restart,
+ .start_date = date,
+ .length_tck = MAC_EIFS_AV_TCK,
+ .anticipation_tck = PBPROC_ANTICIP_TCK,
+ .eifs = true),
+ SCENARIO_EVENT (phy_rx_activate, .now = true,
+ .pre_detection = true),
+ SCENARIO_END
+ };
+ scenario_globals_t globals = {
+ .tp = &tp,
+ };
+ scenario_run (t, entries, &globals);
+ test_fail_unless (tp.pbproc->fsm.current_state
+ == PBPROC_FSM_STATE_IDLE);
+ } test_end;
+ test_begin (t, "nfu sack")
+ {
+ rx_data_nfu_test (t, &tp, 123546, NFU_SACK);
+ } test_end;
+ test_begin (t, "nfu sof")
+ {
+ rx_data_nfu_test (t, &tp, 12354, NFU_SOF_ACCESS);
+ rx_data_nfu_test (t, &tp, 1235, NFU_SOF_SNID);
+ rx_data_nfu_test (t, &tp, 123, NFU_SOF_TEI);
+ } test_end;
+ test_begin (t, "sack error invalid tm")
+ {
+ rx_data_sack_error_test (t, &tp, SACK_ERROR_TM_TMI_UNAVAILABLE);
+ rx_data_sack_error_test (t, &tp, SACK_ERROR_TM_STA_UNAVAILABLE);
+ } test_end;
+ test_begin (t, "sack error encryption")
+ {
+ rx_data_sack_error_test (t, &tp, SACK_ERROR_ENC_STA_NO_NEK);
+ rx_data_sack_error_test (t, &tp, SACK_ERROR_ENC_NO_EKS);
+ } test_end;
+ test_pbproc_uninit (&tp);
+}
+
+void
+rx_data_test_suite (test_t t)
+{
+ test_suite_begin (t, "rx data");
+ rx_data_basic_test_case (t);
+ rx_data_errors_test_case (t);
+ test_case_begin (t, "memory");
+ test_begin (t, "memory")
+ {
+ test_fail_unless (blk_check_memory ());
+ } test_end;
+}
+
diff --git a/cesar/mac/pbproc/test/pbproc/src/scenario.c b/cesar/mac/pbproc/test/pbproc/src/scenario.c
new file mode 100644
index 0000000000..60c2b35e71
--- /dev/null
+++ b/cesar/mac/pbproc/test/pbproc/src/scenario.c
@@ -0,0 +1,50 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file src/scenario.c
+ * \brief Scenario support.
+ * \ingroup test
+ */
+#include "common/std.h"
+
+#include "inc/scenario.h"
+
+scenario_t scenario;
+
+void
+scenario_run (test_t t, scenario_entry_t *entries,
+ scenario_globals_t *globals)
+{
+ test_within (t);
+ dbg_assert (entries);
+ dbg_assert_print (entries[0].event_id == SCENARIO_ACTION_ID,
+ "First entry should be an action");
+ /* Initialise the scenario. */
+ scenario.t = t;
+ scenario.current = scenario.entries = entries;
+ scenario.globals = globals;
+ /* Run. */
+ while (scenario.current->event_id != SCENARIO_NULL_ID)
+ {
+ if (scenario.current->event_id == SCENARIO_NOP_ID)
+ scenario.current++;
+ else
+ {
+ test_fail_unless (scenario.current->event_id == SCENARIO_ACTION_ID,
+ "Expected event did not occurs at %d",
+ scenario.current - scenario.entries);
+ scenario_entry_t *action = scenario.current++;
+ action->action_cb (globals, &action->params);
+ }
+ }
+ /* Uninitialise the scenario. */
+ scenario.t = NULL;
+ scenario.current = scenario.entries = NULL;
+ scenario.globals = NULL;
+}
+
diff --git a/cesar/mac/pbproc/test/pbproc/src/scenario_defs.c b/cesar/mac/pbproc/test/pbproc/src/scenario_defs.c
new file mode 100644
index 0000000000..f361c6ca5b
--- /dev/null
+++ b/cesar/mac/pbproc/test/pbproc/src/scenario_defs.c
@@ -0,0 +1,109 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file src/scenario_defs.c
+ * \brief Scenario actions.
+ * \ingroup test
+ */
+#include "common/std.h"
+
+#include "inc/scenario.h"
+#include "mac/pbproc/inc/context.h"
+#include "hal/phy/inc/context.h"
+#include "mac/ca/inc/context.h"
+
+void
+scenario_action_phy_rx_fc_cb (scenario_globals_t *globals,
+ scenario_params_t *params)
+{
+ scenario_action_phy_rx_fc_t *p = &params->action_phy_rx_fc;
+ phy_t *phy = globals->tp->pbproc->phy;
+ phy->rx_sysdate = p->rx_sysdate;
+ phy->prp_won = p->prp_won;
+ phy->slot_count = p->slot_count;
+ /* Call callbacks. */
+ if (phy->rx_fc_cb (phy->user_data, p->rx_date, p->fc_av))
+ phy->deferred_cb (phy->deferred_cb);
+}
+
+void
+scenario_action_phy_access_cb (scenario_globals_t *globals,
+ scenario_params_t *params)
+{
+ scenario_action_phy_access_t *p = &params->action_phy_access;
+ ca_t *ca = globals->tp->ca;
+ phy_t *phy = globals->tp->pbproc->phy;
+ /* Prepare parameters. */
+ if (p->access_param)
+ ca->access_param = *p->access_param;
+ phy->prp_won = p->prp_won;
+ phy->slot_count = p->slot_count;
+ /* Call callbacks. */
+ if (phy->access_cb (phy->user_data))
+ phy->deferred_cb (phy->deferred_cb);
+}
+
+void
+scenario_action_phy_access_conf_cb (scenario_globals_t *globals,
+ scenario_params_t *params)
+{
+ phy_t *phy = globals->tp->pbproc->phy;
+ /* Call callbacks. */
+ if (phy->access_conf_cb (phy->user_data))
+ phy->deferred_cb (phy->deferred_cb);
+}
+
+void
+scenario_action_phy_pbdma_cb (scenario_globals_t *globals,
+ scenario_params_t *params)
+{
+ scenario_action_phy_pbdma_t *p = &params->action_phy_pbdma;
+ phy_t *phy = globals->tp->pbproc->phy;
+ /* Prepare parameters. */
+ phy_pbdma_status_t status;
+ *(u32 *) &status = 0;
+ status.pb_null = p->pb_null;
+ status.pb_crc_error = p->pb_crc_error;
+ status.pb_it = p->pb_it;
+ status.end_rx_pb = p->end_rx_pb;
+ status.end_tx_pb = p->end_tx_pb;
+ status.end_chandata = p->end_chandata;
+ status.null_pb_index = p->null_pb_index;
+ uint i;
+ if (p->crc_bitmap)
+ {
+ dbg_assert (p->crc_bitmap_bits < 256);
+ for (i = 0; i < p->crc_bitmap_bits / 32; i++)
+ phy->crc_bitmap[i] = p->crc_bitmap[i];
+ if (p->crc_bitmap_bits % 32 != 0)
+ {
+ phy->crc_bitmap[i] =
+ p->crc_bitmap[i] & BITS_ONES (p->crc_bitmap_bits % 32);
+ i++;
+ }
+ for (; i < COUNT (phy->crc_bitmap); i++)
+ phy->crc_bitmap[i] = 0;
+ }
+ else
+ for (i = 0; i < COUNT (phy->crc_bitmap); i++)
+ phy->crc_bitmap[i] = 0;
+ /* Call callbacks. */
+ if (phy->pbdma_cb (phy->user_data, *(u32 *) &status))
+ phy->deferred_cb (phy->deferred_cb);
+}
+
+void
+scenario_action_pbproc_activate_cb (scenario_globals_t *globals,
+ scenario_params_t *params)
+{
+ scenario_action_pbproc_activate_t *p = &params->action_pbproc_activate;
+ pbproc_t *pbproc = globals->tp->pbproc;
+ /* Call function. */
+ pbproc_activate (pbproc, p->flag);
+}
+
diff --git a/cesar/mac/pbproc/test/pbproc/src/test_pbproc.c b/cesar/mac/pbproc/test/pbproc/src/test_pbproc.c
new file mode 100644
index 0000000000..71c426d737
--- /dev/null
+++ b/cesar/mac/pbproc/test/pbproc/src/test_pbproc.c
@@ -0,0 +1,193 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file src/test_pbproc.c
+ * \brief PBProc test.
+ * \ingroup test
+ */
+#include "common/std.h"
+
+#include "lib/test.h"
+#include "lib/trace.h"
+
+#include "inc/test_pbproc.h"
+
+#include "inc/scenario.h"
+
+#include "mac/pbproc/inc/context.h"
+
+void
+prep_mpdu_test_suite (test_t t);
+
+void
+tx_data_test_suite (test_t t);
+
+void
+rx_data_test_suite (test_t t);
+
+void
+test_pbproc_rx_cb (void *user, mfs_t *mfs, mfs_t *mfs_mme,
+ const pbproc_rx_params_t *rx_params,
+ pb_t *pb_first, pb_t *pb_last,
+ uint pb_nb, pb_t *chandata_first, uint chandata_nb)
+{
+ dbg_assert_ptr (user);
+ dbg_assert_ptr (rx_params);
+ if (pb_nb)
+ {
+ dbg_assert_ptr (pb_first);
+ dbg_assert_ptr (pb_last);
+ }
+ else
+ dbg_assert (pb_first == NULL && pb_last == NULL);
+ scenario_event (pbproc_rx_cb, params);
+ test_fail_unless (pb_nb == params->pb_nb);
+ blk_release_desc_range (&pb_first->blk, &pb_last->blk);
+ /* TODO: more verifications. */
+ dbg_assert_print (chandata_first == NULL && chandata_nb == 0,
+ "Not handled yet");
+}
+
+void
+test_pbproc_rx_beacon_cb (void *user, pb_beacon_t *pb,
+ pbproc_rx_beacon_params_t *params)
+{
+ dbg_assert_ptr (user);
+ dbg_assert_ptr (pb);
+ dbg_assert (params == (void *) (pb->data + MAC_PB136_BYTES));
+ scenario_event (pbproc_rx_beacon_cb);
+ blk_release_desc (&pb->blk);
+ /* TODO: more verifications. */
+}
+
+void
+test_pbproc_init (test_pbproc_t *ctx)
+{
+ dbg_assert (ctx);
+ lib_rnd_init (ctx->rnd, 1234);
+ mac_config_init (&ctx->config);
+ ctx->config.tei = 1;
+ ctx->config.snid = 1;
+ ctx->config.seed = 42;
+ ctx->store = mac_store_init ();
+ ctx->pbproc = pbproc_init (&ctx->config, ctx->store);
+ pbproc_init_cb (ctx->pbproc, ctx, test_pbproc_rx_cb,
+ test_pbproc_rx_beacon_cb);
+ pbproc_get_phy (ctx->pbproc);
+ ctx->ca = pbproc_get_ca (ctx->pbproc);
+}
+
+void
+test_pbproc_uninit (test_pbproc_t *ctx)
+{
+ dbg_assert (ctx);
+ ctx->ca = NULL;
+ pbproc_uninit (ctx->pbproc);
+ ctx->pbproc = NULL;
+ mac_store_uninit (ctx->store);
+ ctx->store = NULL;
+}
+
+void
+test_pbproc_init_suite (test_t t)
+{
+ test_suite_begin (t, "init");
+ test_case_begin (t, "basic");
+ test_pbproc_t ctx;
+ test_begin (t, "init uninit")
+ {
+ test_pbproc_init (&ctx);
+ test_pbproc_uninit (&ctx);
+ test_pbproc_init (&ctx);
+ test_pbproc_uninit (&ctx);
+ } test_end;
+ test_begin (t, "rx segment refill")
+ {
+ test_pbproc_init (&ctx);
+ blk_t *first, *last;
+ first = blk_alloc_desc_range (10, &last);
+ pbproc_rx_segment_refill (ctx.pbproc, PB_FROM_BLK (first),
+ PB_FROM_BLK (last), 10);
+ first = blk_alloc_desc_range (10, &last);
+ pbproc_rx_segment_refill (ctx.pbproc, PB_FROM_BLK (first),
+ PB_FROM_BLK (last), 10);
+ test_pbproc_uninit (&ctx);
+ } test_end;
+ test_begin (t, "activate deactivate")
+ {
+ test_pbproc_init (&ctx);
+ scenario_entry_t entries[] = {
+ SCENARIO_ACTION (pbproc_activate, .flag = true),
+ SCENARIO_EVENT (ca_access_activate, .date = 0,
+ .anticipation_tck = PBPROC_ANTICIP_TCK,
+ .coexistence_mode = MAC_COEXISTENCE_AV_ONLY_MODE,
+ .hybrid = false, .nek_switch = 0),
+ SCENARIO_EVENT (phy_rx_param, .fc_mode = PHY_FC_MODE (false, 1)),
+ SCENARIO_EVENT (phy_rx_activate, .now = true,
+ .pre_detection = true),
+ SCENARIO_ACTION (pbproc_activate, .flag = false),
+ SCENARIO_EVENT (phy_rx_activate, .now = true,
+ .pre_detection = false),
+ SCENARIO_EVENT (ca_access_deactivate),
+ SCENARIO_END
+ };
+ scenario_globals_t globals = {
+ .tp = &ctx,
+ };
+ scenario_run (t, entries, &globals);
+ test_pbproc_uninit (&ctx);
+ } test_end;
+ test_begin (t, "aifs")
+ {
+ test_pbproc_init (&ctx);
+ ca_access_param_t access_param = {
+ .mfs = NULL, .access_date = 0, .cw_start_date = 0,
+ };
+ scenario_entry_t entries[] = {
+ SCENARIO_ACTION (phy_access, .access_param = &access_param,
+ .prp_won = true, .slot_count = 64),
+ SCENARIO_EVENT (ca_access_hold),
+ SCENARIO_EVENT (phy_rx_activate, .now = true,
+ .pre_detection = false),
+ SCENARIO_EVENT (ca_backoff_cancel),
+ SCENARIO_EVENT (ca_access_aifs,
+ .coexistence_mode = MAC_COEXISTENCE_AV_ONLY_MODE,
+ .hybrid = false, .nek_switch = 0),
+ SCENARIO_EVENT (phy_rx_param, .fc_mode = PHY_FC_MODE (false, 1)),
+ SCENARIO_END
+ };
+ scenario_globals_t globals = {
+ .tp = &ctx,
+ };
+ scenario_run (t, entries, &globals);
+ test_fail_unless (ctx.pbproc->fsm.current_state
+ == PBPROC_FSM_STATE_IDLE);
+ test_pbproc_uninit (&ctx);
+ } test_end;
+ test_case_begin (t, "memory");
+ test_begin (t, "memory")
+ {
+ test_fail_unless (blk_check_memory ());
+ } test_end;
+}
+
+int
+main (int argc, char **argv)
+{
+ test_t t;
+ trace_init ();
+ test_init (t, argc, argv);
+ test_pbproc_init_suite (t);
+ prep_mpdu_test_suite (t);
+ tx_data_test_suite (t);
+ rx_data_test_suite (t);
+ trace_uninit ();
+ test_result (t);
+ return test_nb_failed (t) == 0 ? 0 : 1;
+}
+
diff --git a/cesar/mac/pbproc/test/pbproc/src/tx_data.c b/cesar/mac/pbproc/test/pbproc/src/tx_data.c
new file mode 100644
index 0000000000..82bd017747
--- /dev/null
+++ b/cesar/mac/pbproc/test/pbproc/src/tx_data.c
@@ -0,0 +1,270 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file src/tx_data.c
+ * \brief TX Data automaton test.
+ * \ingroup test
+ */
+#include "common/std.h"
+
+#include "inc/scenario.h"
+
+#include "inc/test_pbproc.h"
+#include "inc/utils.h"
+
+#include "mac/common/timings.h"
+#include "mac/pbproc/inc/context.h"
+
+void
+tx_data_test (test_t t, test_pbproc_t *tp, u32 date, uint mfs_seg_nb,
+ uint duration_tck, uint symb_nb, uint data_seg_nb_total)
+{
+ test_within (t);
+ const uint lid = 1;
+ const uint dtei = 2;
+ const uint beacon_tck = MAC_MS_TO_TCK (1000) / 50;
+ mfs_tx_t *mfs = utils_mfs_tx_prepare (false, false, lid, dtei,
+ mfs_seg_nb);
+ ca_access_param_t access = {
+ .mfs = mfs,
+ .access_date = date,
+ .beacon_period_start_date = date / beacon_tck * beacon_tck,
+ .duration_tck = duration_tck,
+ .cfp = false,
+ .hybrid = false,
+ };
+ pbproc_fc_sack_t sack_fc = {
+ .dt_av = PBPROC_FC_DT_SACK,
+ .access = false,
+ .snid = tp->config.snid,
+ .dtei = tp->config.tei,
+ .cfs = false,
+ .bdf = true,
+ .svn = 0,
+ .rrtf = false,
+ .mfs_rsp_data = PBPROC_FC_MFS_RSP_ACK,
+ .mfs_rsp_mgmt = PBPROC_FC_MFS_RSP_ACK,
+ .sackt3 = 0,
+ .sackt2 = 0,
+ .sackt1 = 0,
+ .sackt0 = 0,
+ .sacki[0] = 0,
+ .sacki[1] = 0,
+ .sacki_last = 0,
+ .fccs_av = 0,
+ };
+ const uint initial_pb_nb = MIN (data_seg_nb_total, 4u);
+ const uint pre_fc_fl_tck = MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (symb_nb, MAC_DX417_TCK) + MAC_RIFS_DEFAULT_TCK;
+ scenario_entry_t entries[] = {
+ SCENARIO_ACTION (phy_access, .access_param = &access,
+ .prp_won = true, .slot_count = 2),
+ SCENARIO_EVENT (ca_access_hold),
+ SCENARIO_EVENT (phy_pbdma_start, .bypass_aes = true,
+ .nb_total = data_seg_nb_total,
+ .nb_ready = initial_pb_nb, .nb_pb_it = 0),
+ SCENARIO_EVENT (phy_tx_param, .fc_mode = PHY_FC_MODE_AV_1,
+ .short_ppdu = false, .mod = PHY_MOD_ROBO,
+ .fecrate = PHY_FEC_RATE_1_2,
+ .pb_size = PHY_PB_SIZE_520, .gil = PHY_GIL_417,
+ .tonemap_index = 0),
+ SCENARIO_EVENT (phy_tx_frame, .date = date, .want_conf = true,
+ .stop_tx_on_prp_lost = true),
+ SCENARIO_EVENT (ca_access_vcs_restart, .start_date = date,
+ .length_tck = MAC_EIFS_AV_TCK,
+ .anticipation_tck = PBPROC_ANTICIP_TCK,
+ .eifs = true),
+ SCENARIO_ACTION (phy_access_conf),
+ SCENARIO_EVENT (phy_pbdma_update, .nb_ready = data_seg_nb_total,
+ .nb_pb_it = 0),
+ SCENARIO_EVENT (ca_backoff_deferred, .slot_count = 0),
+ SCENARIO_EVENT (ca_access_vcs_restart,
+ .start_date = date + pre_fc_fl_tck,
+ .length_tck = MAC_EIFS_AV_TCK,
+ .anticipation_tck = PBPROC_ANTICIP_TCK,
+ .eifs = true),
+ SCENARIO_EVENT (phy_rx_activate, .now = false,
+ .date = date + pre_fc_fl_tck,
+ .pre_detection = true),
+ SCENARIO_ACTION (phy_rx_fc, .rx_date = date + pre_fc_fl_tck,
+ .fc_av = (u32 *) &sack_fc),
+ SCENARIO_EVENT (phy_rx_prepare, .short_ppdu = true),
+ SCENARIO_EVENT (ca_mfs_update, .mfs = mfs),
+ SCENARIO_EVENT (ca_backoff_success),
+ SCENARIO_EVENT (ca_access_vcs_restart,
+ .start_date = date + pre_fc_fl_tck,
+ .length_tck = MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_CIFS_TCK,
+ .anticipation_tck = PBPROC_ANTICIP_TCK,
+ .eifs = false),
+ SCENARIO_END
+ };
+ scenario_globals_t globals = {
+ .tp = tp,
+ };
+ scenario_run (t, entries, &globals);
+ utils_mfs_tx_cleanup (mfs);
+ test_fail_unless (tp->pbproc->fsm.current_state == PBPROC_FSM_STATE_IDLE);
+}
+
+void
+tx_data_noseg_test (test_t t, test_pbproc_t *tp, u32 date, uint duration_tck,
+ bool prp_won)
+{
+ test_within (t);
+ const uint lid = 1;
+ const uint dtei = 2;
+ const uint beacon_tck = MAC_MS_TO_TCK (1000) / 50;
+ mfs_tx_t *mfs = utils_mfs_tx_prepare (false, false, lid, dtei,
+ 0);
+ ca_access_param_t access = {
+ .mfs = mfs,
+ .access_date = date,
+ .beacon_period_start_date = date / beacon_tck * beacon_tck,
+ .duration_tck = duration_tck,
+ .cfp = false,
+ .hybrid = false,
+ };
+ scenario_entry_t *entries;
+ scenario_entry_t entries_prp_won[] = {
+ SCENARIO_ACTION (phy_access, .access_param = &access,
+ .prp_won = true, .slot_count = 0),
+ SCENARIO_EVENT (ca_access_hold),
+ SCENARIO_EVENT (ca_access_defer, .date = date,
+ .anticipation_tck = PBPROC_ANTICIP_TCK),
+ SCENARIO_END
+ };
+ scenario_entry_t entries_prp_lost[] = {
+ SCENARIO_ACTION (phy_access, .access_param = &access,
+ .prp_won = false, .slot_count = 0),
+ SCENARIO_EVENT (ca_access_hold),
+ SCENARIO_EVENT (ca_backoff_cancel),
+ SCENARIO_EVENT (ca_access_vcs_restart,
+ .start_date = 0,
+ .length_tck = MAC_EIFS_AV_TCK,
+ .anticipation_tck = PBPROC_ANTICIP_TCK,
+ .eifs = true),
+ SCENARIO_END
+ };
+ entries = prp_won ? entries_prp_won : entries_prp_lost;
+ scenario_globals_t globals = {
+ .tp = tp,
+ };
+ scenario_run (t, entries, &globals);
+ utils_mfs_tx_cleanup (mfs);
+ test_fail_unless (tp->pbproc->fsm.current_state == PBPROC_FSM_STATE_IDLE);
+}
+
+void
+tx_data_beacon_test (test_t t, test_pbproc_t *tp, u32 date, uint duration_tck,
+ uint symb_nb)
+{
+ test_within (t);
+ const uint beacon_tck = MAC_MS_TO_TCK (1000) / 50;
+ mfs_tx_t *mfs = utils_mfs_tx_prepare (true, false, MAC_LID_SPC_CENTRAL,
+ MAC_TEI_BCAST, 0);
+ mfs->cfp = true;
+ mfs->beacon = true;
+ pb_beacon_t *pb = PARENT_OF (pb_beacon_t, blk, blk_alloc_desc ());
+ pbproc_tx_beacon_params_t params = {
+ { 0x0123, 0x4242, 0xabab, 0x5555 }, pb->data + 123
+ };
+ pbproc_mfs_beacon_prepare (tp->pbproc, mfs, pb, &params);
+ ca_access_param_t access = {
+ .mfs = mfs,
+ .access_date = date,
+ .beacon_period_start_date = date / beacon_tck * beacon_tck,
+ .duration_tck = duration_tck,
+ .cfp = true,
+ .hybrid = true,
+ };
+ const uint pre_fc_fl_tck = MAC_PREAMBLE_HYBRID_TCK + MAC_FC_10_TCK
+ + MAC_FC_AV_TCK + MAC_PAYLOAD_TCK (symb_nb, MAC_DX567_TCK)
+ + MAC_B2BIFS_TCK;
+ scenario_entry_t entries[] = {
+ SCENARIO_ACTION (phy_access, .access_param = &access,
+ .prp_won = true, .slot_count = 0),
+ SCENARIO_EVENT (ca_access_hold),
+ SCENARIO_EVENT (phy_tx_fc10, .fc_10 = 0),
+ SCENARIO_EVENT (phy_pbdma_start, .bypass_aes = true,
+ .nb_total = 1,
+ .nb_ready = 1, .nb_pb_it = 0),
+ SCENARIO_EVENT (phy_tx_param, .fc_mode = PHY_FC_MODE_HYBRID_1,
+ .short_ppdu = false, .mod = PHY_MOD_MINI_ROBO,
+ .fecrate = PHY_FEC_RATE_1_2,
+ .pb_size = PHY_PB_SIZE_136, .gil = PHY_GIL_567,
+ .tonemap_index = 0),
+ SCENARIO_EVENT (phy_tx_frame, .date = date, .want_conf = true,
+ .stop_tx_on_prp_lost = false),
+ SCENARIO_ACTION (phy_access_conf),
+ SCENARIO_EVENT (phy_pbdma_update, .nb_ready = 1, .nb_pb_it = 1),
+ SCENARIO_ACTION (phy_pbdma, .pb_it = true, .end_tx_pb = true),
+ SCENARIO_EVENT (ca_mfs_update, .mfs = mfs),
+ SCENARIO_EVENT (ca_backoff_success),
+ SCENARIO_EVENT (ca_access_vcs_restart,
+ .start_date = date + pre_fc_fl_tck,
+ .length_tck = 0,
+ .anticipation_tck = PBPROC_ANTICIP_TCK,
+ .eifs = false),
+ SCENARIO_END
+ };
+ scenario_globals_t globals = {
+ .tp = tp,
+ };
+ scenario_run (t, entries, &globals);
+ utils_mfs_tx_cleanup (mfs);
+ test_fail_unless (tp->pbproc->fsm.current_state == PBPROC_FSM_STATE_IDLE);
+}
+
+void
+tx_data_basic_test_case (test_t t)
+{
+ test_pbproc_t tp;
+ test_case_begin (t, "basic");
+ test_pbproc_init (&tp);
+ test_begin (t, "unicast")
+ {
+ tx_data_test (t, &tp, 5462132, 30,
+ MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (91, MAC_DX417_TCK)
+ + MAC_RIFS_DEFAULT_TCK + MAC_PREAMBLE_TCK
+ + MAC_FC_AV_TCK,
+ 91, 5);
+ tx_data_noseg_test (t, &tp, 5462132,
+ MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (91, MAC_DX417_TCK)
+ + MAC_RIFS_DEFAULT_TCK + MAC_PREAMBLE_TCK
+ + MAC_FC_AV_TCK, true);
+ tx_data_noseg_test (t, &tp, 5462132,
+ MAC_PREAMBLE_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (91, MAC_DX417_TCK)
+ + MAC_RIFS_DEFAULT_TCK + MAC_PREAMBLE_TCK
+ + MAC_FC_AV_TCK, false);
+ } test_end;
+ test_begin (t, "beacon")
+ {
+ tx_data_beacon_test (t, &tp, 123, MAC_PREAMBLE_HYBRID_TCK
+ + MAC_FC_10_TCK + MAC_FC_AV_TCK
+ + MAC_PAYLOAD_TCK (6, MAC_DX567_TCK)
+ + MAC_B2BIFS_TCK, 6);
+ } test_end;
+ test_pbproc_uninit (&tp);
+}
+
+void
+tx_data_test_suite (test_t t)
+{
+ test_suite_begin (t, "tx data");
+ tx_data_basic_test_case (t);
+ test_case_begin (t, "memory");
+ test_begin (t, "memory")
+ {
+ test_fail_unless (blk_check_memory ());
+ } test_end;
+}
+
diff --git a/cesar/mac/pbproc/test/pbproc/src/utils.c b/cesar/mac/pbproc/test/pbproc/src/utils.c
new file mode 100644
index 0000000000..49e429e090
--- /dev/null
+++ b/cesar/mac/pbproc/test/pbproc/src/utils.c
@@ -0,0 +1,148 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file src/utils.c
+ * \brief Utilities.
+ * \ingroup test
+ */
+#include "common/std.h"
+
+#include "inc/utils.h"
+
+#include "lib/blk.h"
+#include "mac/common/timings.h"
+#include "mac/pbproc/pbproc.h"
+#include "mac/pbproc/inc/context.h"
+
+mfs_tx_t *
+utils_mfs_tx_prepare (bool bcast, bool mme, uint lid, uint tei, uint seg_nb)
+{
+ /* Create an MFS. */
+ mfs_tx_t *mfs = blk_alloc ();
+ mfs_tx_init (mfs, bcast, mme, lid, tei);
+ if (seg_nb)
+ {
+ /* Add blocks to it. */
+ blk_t *blk_first, *blk_last;
+ blk_first = blk_alloc_desc_range (seg_nb, &blk_last);
+ pb_t *seg_first, *seg_last;
+ seg_first = PARENT_OF (pb_t, blk, blk_first);
+ seg_last = PARENT_OF (pb_t, blk, blk_last);
+ pb_t *seg, *lseg;
+ for (lseg = NULL, seg = seg_first;
+ lseg != seg_last;
+ lseg = seg, seg = seg->next)
+ {
+ seg->header.ssn = mfs->next_ssn++;
+ seg->header.mfbo = 0;
+ seg->header.vpbf = true;
+ seg->header.mmqf = mme;
+ seg->header.mfbf = false;
+ seg->header.opsf = false;
+ seg->header.rsvd = 0;
+ }
+ pbproc_mfs_insert (mfs, seg_first, seg_last, seg_nb, 0);
+ pbproc_mfs_provide (mfs, seg_nb);
+ }
+ return mfs;
+}
+
+void
+utils_mfs_tx_cleanup (mfs_tx_t *mfs)
+{
+ if (mfs->head)
+ {
+ blk_release_desc_range (&mfs->head->blk, &mfs->tail->blk);
+ mfs->head = mfs->tail = NULL;
+ }
+ blk_release (mfs);
+}
+
+tonemap_t *
+utils_sta_prepare_default_tonemap (test_pbproc_t *tp, bool tx, uint tei,
+ uint tmi, uint tm_mod, uint tm_max_fl_tck,
+ uint *dx)
+{
+ dbg_assert (tmi < TONEMAP_INDEX_NB);
+ dbg_assert (dx);
+ mac_store_sta_add (tp->store, tei);
+ sta_t *sta = mac_store_sta_get (tp->store, tei);
+ dbg_assert (sta);
+ if (tm_max_fl_tck)
+ {
+ uint max_fl_av = (tm_max_fl_tck + MAC_TCK_PER_FL) / MAC_TCK_PER_FL;
+ if (tx)
+ sta->tx_tonemaps->max_fl_av = max_fl_av;
+ else
+ sta->rx_tonemaps->max_fl_av = max_fl_av;
+ }
+ if (tx)
+ sta->tx_tonemaps->default_tmi = tmi;
+ else
+ sta->rx_tonemaps->default_tmi = tmi;
+ tonemap_t *tm = NULL;
+ if (tmi >= PHY_MOD_ROBO_NB)
+ {
+ /* Create a tonemap. */
+ tm = tonemap_alloc ();
+ if (tx)
+ sta->tx_tonemaps->tm[tmi] = tm;
+ else
+ sta->rx_tonemaps->tm[tmi] = tm;
+ tm->strict = false;
+ tm->cpf = true;
+ tm->fecrate = PHY_FEC_RATE_16_21;
+ tm->gil = PHY_GIL_417;
+ tm->bits_per_symbol = tm_mod * tp->config.tonemask_info.carrier_nb;
+ tm->ble = tonemap_ble (tm->bits_per_symbol, tm->fecrate,
+ CONST_UF32 (0.0), tm->gil);
+ /* Do not fill tonemap, unused. */
+ }
+ else
+ {
+ /* Use a ROBO one. */
+ tm = &tp->config.tonemask_info.tonemap_robo[tmi];
+ }
+ blk_release (sta);
+ *dx = tm->gil == PHY_GIL_417 ? MAC_DX417_TCK
+ : (tm->gil == PHY_GIL_567 ? MAC_DX567_TCK : MAC_DX3534_TCK);
+ return tm;
+}
+
+void
+utils_prepare_encryption (test_pbproc_t *tp, bool encrypted, bool sta_auth,
+ uint tei, uint nek_switch)
+{
+ dbg_assert (tp);
+ dbg_assert (nek_switch == 0 || nek_switch == 1);
+ if (encrypted)
+ {
+ tp->config.authenticated = true;
+ tp->config.nek[nek_switch].eks = 3;
+ tp->config.nek[nek_switch].nek[0] = 0x0123567;
+ tp->config.nek[nek_switch].nek[1] = 0x1235678;
+ tp->config.nek[nek_switch].nek[2] = 0x2356789;
+ tp->config.nek[nek_switch].nek[3] = 0x356789a;
+ tp->config.nek[!nek_switch].eks = MAC_EKS_CLEAR;
+ if (sta_auth)
+ {
+ sta_t *sta = mac_store_sta_get (tp->store, tei);
+ dbg_assert (sta);
+ sta->authenticated = true;
+ sta->nek = &tp->config.nek;
+ blk_release (sta);
+ }
+ /* Setup allocation. */
+ tp->pbproc->alloc.nek_switch = nek_switch;
+ }
+ else
+ {
+ tp->config.authenticated = false;
+ }
+}
+
diff --git a/cesar/mac/pbproc/test/sacki/Makefile b/cesar/mac/pbproc/test/sacki/Makefile
new file mode 100644
index 0000000000..f01ab6532d
--- /dev/null
+++ b/cesar/mac/pbproc/test/sacki/Makefile
@@ -0,0 +1,10 @@
+BASE = ../../../..
+
+HOST_DEFS += -DPBPROC_SACKI_ENC_DEBUG -DPBPROC_SACKI_DEC_DEBUG
+
+HOST_PROGRAMS = test_sacki
+test_sacki_SOURCES = test_sacki.c
+test_sacki_MODULES = lib mac/pbproc
+mac_pbproc_MODULE_SOURCES = sacki_enc.c sacki_dec.c
+
+include $(BASE)/common/make/top.mk
diff --git a/cesar/mac/pbproc/test/sacki/src/test_sacki.c b/cesar/mac/pbproc/test/sacki/src/test_sacki.c
new file mode 100644
index 0000000000..adf56781d3
--- /dev/null
+++ b/cesar/mac/pbproc/test/sacki/src/test_sacki.c
@@ -0,0 +1,411 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file src/test_sacki.c
+ * \brief Test SACKI compression/decompression.
+ * \ingroup test
+ */
+#include "common/std.h"
+
+#include "mac/pbproc/inc/sacki_enc.h"
+#include "mac/pbproc/inc/sacki_dec.h"
+
+#include "lib/test.h"
+#include "lib/rnd.h"
+#include <string.h>
+
+#define NB_ITER 1000
+
+struct test_t *debug_test_global;
+
+uint
+bits_get (const char *s, u32 *bits)
+{
+ u32 b = 0;
+ uint bb = 0;
+ while (*s)
+ {
+ while (*s == ' ')
+ s++;
+ dbg_assert (*s == '0' || *s == '1');
+ if (*s++ == '1')
+ b |= 1u << (bb % 32);
+ bb++;
+ if (bb % 32 == 0)
+ {
+ bits[bb / 32 - 1] = b;
+ b = 0;
+ }
+ }
+ if (bb % 32)
+ {
+ bits[bb / 32] = b;
+ }
+ return bb;
+}
+
+void
+bits_put (const u32 *bits, uint bitsl, char *s)
+{
+ uint i;
+ for (i = 0; i < bitsl; i++)
+ {
+ *s++ = bits[i / 32] & (1u << (i % 32)) ? '1' : '0';
+ }
+ *s++ = '\0';
+}
+
+void
+bits_compare (test_t t, u32 *bits, uint bitsl, const char *s)
+{
+ test_within (t);
+ uint cmpsize = 2 * MAX (bitsl, strlen (s)) + 1;
+ char cmp[cmpsize], *cmpp = cmp;
+ uint b = 0;
+ bool bone;
+ uint error = 0;
+ const char *model = s;
+ while (*s)
+ {
+ while (*s == ' ')
+ {
+ s++;
+ *cmpp++ = ' ';
+ }
+ dbg_assert (*s == '0' || *s == '1');
+ if (b == bitsl)
+ {
+ *cmpp++ = '!';
+ *cmpp++ = '<';
+ error++;
+ break;
+ }
+ else
+ {
+ bone = bits[b / 32] & (1u << (b % 32));
+ b++;
+ if ((bone && *s == '0') || (!bone && *s == '1'))
+ {
+ *cmpp++ = '!';
+ error++;
+ }
+ *cmpp++ = bone ? '1' : '0';
+ s++;
+ }
+ }
+ if (b != bitsl)
+ {
+ *cmpp++ = '!';
+ *cmpp++ = '>';
+ error++;
+ while (b < bitsl)
+ {
+ bone = bits[b / 32] & (1u << (b % 32));
+ b++;
+ *cmpp++ = bone ? '1' : '0';
+ }
+ }
+ *cmpp++ = '\0';
+ test_verbose_print ("%s %s %s", cmp, error == 0 ? "==" : "!=", model);
+ test_fail_unless (error == 0, "mismatch");
+}
+
+void
+bits_rnd (lib_rnd_t *rnd, char *s, uint min, uint max, u32 ratio_nok)
+{
+ uint nb = (max == min ? 0 : lib_rnd_uniform (rnd, max - min)) + min;
+ for (; nb; nb--)
+ {
+ *s++ = lib_rnd_flip_coin (rnd, ratio_nok) ? '1' : '0';
+ }
+ *s = '\0';
+}
+
+void
+pbproc_sacki_enc_debug (u32 code, uint codel, uint eat)
+{
+ if (!debug_test_global)
+ return;
+ test_within (debug_test_global);
+ char code_s[32 + 1];
+ bits_put (&code, codel, code_s);
+ test_verbose_print ("%d => %s", eat, code_s);
+}
+
+void
+sacki_enc_test_case (test_t t, const char *name, const char *bmp_s,
+ const char *si_s)
+{
+ u32 bmp[8];
+ uint bmpl;
+ debug_test_global = t;
+ test_case_begin (t, name);
+ bmpl = bits_get (bmp_s, bmp);
+ test_begin (t, "encoding")
+ {
+ pbproc_sacki_enc_t se;
+ pbproc_sacki_enc_init (&se, 72);
+ test_verbose_print ("%s =>", bmp_s);
+ pbproc_sacki_enc_process (&se, bmp, bmpl, true);
+ bits_compare (t, se.si, se.sis, si_s);
+ } test_end;
+ test_begin (t, "encoding 2 step")
+ {
+ uint i;
+ for (i = 1; i < bmpl; i++)
+ {
+ pbproc_sacki_enc_t se;
+ pbproc_sacki_enc_init (&se, 72);
+ test_verbose_print ("%s (%d-%d) =>", bmp_s, i, bmpl);
+ pbproc_sacki_enc_process (&se, bmp, i, false);
+ test_verbose_print ("second step");
+ pbproc_sacki_enc_process (&se, bmp, bmpl, true);
+ bits_compare (t, se.si, se.sis, si_s);
+ }
+ } test_end;
+ test_begin (t, "encoding with offset")
+ {
+ static const char *pad = "101101101000100011011000100011111000111110"
+ "101001001101011111011100011100";
+ char sip_s[72 + 1 + strlen (si_s) + 1];
+ uint i;
+ for (i = 0; i < 72; i++)
+ {
+ pbproc_sacki_enc_t se;
+ pbproc_sacki_enc_init (&se, 72 - i);
+ strncpy (sip_s, pad, i);
+ sip_s[i] = '\0';
+ se.sis = bits_get (sip_s, se.si);
+ sip_s[i] = ' ';
+ uint j, k;
+ for (j = 0, k = 0; j < 72 - i; k++)
+ {
+ sip_s[i + 1 + k] = si_s[k];
+ if (si_s[k] == '0' || si_s[k] == '1')
+ j++;
+ }
+ sip_s[i + 1 + k] = '\0';
+ test_verbose_print ("%s (+%d) =>", bmp_s, i);
+ pbproc_sacki_enc_process (&se, bmp, bmpl, true);
+ bits_compare (t, se.si, se.sis, sip_s);
+ }
+ } test_end;
+ debug_test_global = NULL;
+}
+
+void
+sacki_enc_test_suite (test_t t)
+{
+ test_suite_begin (t, "sacki enc");
+ sacki_enc_test_case (
+ t, "first",
+ "111011000110100010001000011101100011010001000100001",
+ "11111111101110111100100101111001111111110111011110010010111100110");
+ sacki_enc_test_case (
+ t, "long",
+ "0000 0000 001 0001 0000 101 0000 0000 0000 0000 0000 11 0000 11 0000"
+ " 0000 0000 0000 0000 001 0000 0000 0000 0000 11 11 100 0000 0000 010"
+ " 0000 0000 0000 0000 0000 0000 0",
+ "0 0 101 1110 0 111101 0 0 0 0 0 11111 0 11111 0 0 0 0 0 101 0 0 0 0"
+ " 11111 11111 110 0 0 100 0 0 0 0 0 0 0");
+ sacki_enc_test_case (
+ t, "too long",
+ "0000 0000 001 0001 0000 101 0000 0000 0000 0000 0000 11 0000 11 0000"
+ " 0000 0000 0000 0000 001 0000 0000 0000 0000 11 11 100 0000 0000 010"
+ " 0000 0000 0000 0000 0000 0000 0000 011 11 0001",
+ "0 0 101 1110 0 111101 0 0 0 0 0 11111 0 11111 0 0 0 0 0 101 0 0 0 0"
+ " 11111 11111 110 0 0 100 0 0 0 0 0 0 0 111");
+}
+
+void
+pbproc_sacki_dec_debug (uint eat, uint prod, uint nok0, uint nok1, uint nok2)
+{
+ if (!debug_test_global)
+ return;
+ test_within (debug_test_global);
+ test_verbose_print ("%d => %d, %d-%d-%d", eat, prod, nok0, nok1, nok2);
+}
+
+uint last_nok;
+
+void
+test_sacki_dec_nok_cb (void *user, uint first, uint nb)
+{
+ dbg_assert (user);
+ dbg_assert (nb);
+ u32 *bmp = user;
+ uint i;
+ for (i = first; i < first + nb; i++)
+ {
+ bmp[i / 32] |= 1u << (i % 32);
+ }
+ last_nok = first;
+}
+
+void
+sacki_dec_test_case (test_t t, const char *name, const char *si_s, uint sil,
+ const char *bmp_s, uint pbl)
+{
+ u32 si[3];
+ u32 bmp[8];
+ uint sir;
+ debug_test_global = t;
+ test_case_begin (t, name);
+ si[0] = 0; si[1] = 0; si[2] = 0;
+ bits_get (si_s, si);
+ test_begin (t, "decoding")
+ {
+ test_verbose_print ("%s => %d", si_s, pbl);
+ memset (bmp, 0, sizeof (bmp));
+ sir = pbproc_sacki_dec_process (si, 72, pbl, bmp,
+ test_sacki_dec_nok_cb);
+ bits_compare (t, bmp, pbl, bmp_s);
+ test_fail_unless (sil == 72 - sir, "sir mismatch: %d != 72 - %d", sil,
+ sir);
+ } test_end;
+ debug_test_global = NULL;
+}
+
+void
+sacki_dec_burst_test_case (test_t t, const char *name, const char *si_s,
+ uint sil,
+ const char *bmp0_s, uint pb0l,
+ const char *bmp1_s, uint pb1l,
+ const char *bmp2_s, uint pb2l,
+ const char *bmp3_s, uint pb3l)
+{
+ u32 si[3];
+ u32 bmp[8];
+ debug_test_global = t;
+ test_case_begin (t, name);
+ si[0] = 0; si[1] = 0; si[2] = 0;
+ bits_get (si_s, si);
+ const char *bmp_s[4] = { bmp0_s, bmp1_s, bmp2_s, bmp3_s };
+ uint pbl[4] = { pb0l, pb1l, pb2l, pb3l };
+ test_begin (t, "decoding")
+ {
+ test_verbose_print ("%s => %d, %d, %d, %d", si_s, pb0l, pb1l, pb2l,
+ pb3l);
+ uint i;
+ uint sir = 72;
+ for (i = 0; i < COUNT (bmp_s); i++)
+ {
+ memset (bmp, 0, sizeof (bmp));
+ sir = pbproc_sacki_dec_process (si, sir, pbl[i], bmp,
+ test_sacki_dec_nok_cb);
+ bits_compare (t, bmp, pbl[i], bmp_s[i]);
+ }
+ test_fail_unless (sil == 72 - sir, "sir mismatch: %d != 72 - %d", sil,
+ sir);
+ } test_end;
+ debug_test_global = NULL;
+}
+
+void
+sacki_dec_test_suite (test_t t)
+{
+ test_suite_begin (t, "sacki dec");
+ sacki_dec_test_case (
+ t, "first",
+ "11111111101110111100100101111001111111110111011110010010111100110",
+ 65, "111011000110100010001000011101100011010001000100001", 51);
+ sacki_dec_test_case (
+ t, "long",
+ "0 0 101 1110 0 111101 0 0 0 0 0 11111 0 11111 0 0 0 0 0 101 0 0 0 0"
+ " 11111 11111 110 0 0 100 0 0 0 0 0 0 0", 69,
+ "0000 0000 001 0001 0000 101 0000 0000 0000 0000 0000 11 0000 11 0000"
+ " 0000 0000 0000 0000 001 0000 0000 0000 0000 11 11 100 0000 0000 010"
+ " 0000 0000 0000 0000 0000 0000 0", 132);
+ sacki_dec_test_case (
+ t, "too long",
+ "0 0 101 1110 0 111101 0 0 0 0 0 11111 0 11111 0 0 0 0 0 101 0 0 0 0"
+ " 11111 11111 110 0 0 100 0 0 0 0 0 0 0 111", 69,
+ "0000 0000 001 0001 0000 101 0000 0000 0000 0000 0000 11 0000 11 0000"
+ " 0000 0000 0000 0000 001 0000 0000 0000 0000 11 11 100 0000 0000 010"
+ " 0000 0000 0000 0000 0000 0000 0000 111 11 1111", 144);
+ sacki_dec_burst_test_case (
+ t, "burst",
+ "0 111101 100 101 11111 1110"
+ " 0 11111 111101 110 0 0"
+ " 101 111100 110 0 0 0 11111 111101"
+ " 0 0 110", 70,
+ "0000 101 010 001 11 0001", 19,
+ "0000 11 101 100 0000 0000", 20,
+ "001 011 100 0000 0000 0000 11 101", 26,
+ "0000 0000 100", 11);
+}
+
+void
+sacki_encdec_test_suite (test_t t)
+{
+ test_suite_begin (t, "sacki encdec");
+ test_case_begin (t, "random");
+ lib_rnd_t rnd[1];
+ lib_rnd_init (rnd, 1234);
+ static const struct {
+ uint r;
+ const char *name;
+ } ratios[] = {
+ { LIB_RND_RATIO (0.0), "zero" },
+ { LIB_RND_RATIO (0.05), "rare" },
+ { LIB_RND_RATIO (0.2), "few" },
+ { LIB_RND_RATIO (0.5), "mean" },
+ { LIB_RND_RATIO (0.7), "many" },
+ { LIB_RND_RATIO (0.99999), "one" },
+ };
+ uint j;
+ for (j = 0; j < COUNT (ratios); j++)
+ {
+ test_begin (t, ratios[j].name)
+ {
+ char bmp_s[257];
+ u32 bmp[8];
+ uint bmpl;
+ uint i;
+ for (i = 0; i < NB_ITER; i++)
+ {
+ /* Random pattern. */
+ bits_rnd (rnd, bmp_s, 1, 256, ratios[j].r);
+ bmpl = bits_get (bmp_s, bmp);
+ /* Encode. */
+ pbproc_sacki_enc_t se;
+ pbproc_sacki_enc_init (&se, 72);
+ pbproc_sacki_enc_process (&se, bmp, bmpl, true);
+ char si_s[73];
+ bits_put (se.si, se.sis, si_s);
+ test_verbose_print ("%s => %s", bmp_s, si_s);
+ /* Decode. */
+ last_nok = bmpl;
+ memset (bmp, 0, sizeof (bmp));
+ pbproc_sacki_dec_process (se.si, 72, bmpl, bmp,
+ test_sacki_dec_nok_cb);
+ if (se.sis == 72)
+ {
+ /* SACKI too small. */
+ bmpl = last_nok;
+ bmp_s[bmpl] = '\0';
+ test_verbose_print ("reduced to %d", bmpl);
+ }
+ /* Compare. */
+ bits_compare (t, bmp, bmpl, bmp_s);
+ }
+ } test_end;
+ }
+}
+
+int
+main (int argc, char **argv)
+{
+ test_t t;
+ test_init (t, argc, argv);
+ sacki_enc_test_suite (t);
+ sacki_dec_test_suite (t);
+ sacki_encdec_test_suite (t);
+ test_result (t);
+ return test_nb_failed (t) == 0 ? 0 : 1;
+}