summaryrefslogtreecommitdiff
path: root/cesar
diff options
context:
space:
mode:
authorNicolas Schodet2010-12-08 18:03:56 +0100
committerNicolas Schodet2010-12-08 18:03:56 +0100
commitea67c2479c758683132147aaedae88b8cae8a185 (patch)
treea55e0e363a9371daa9f713e4f41f7ec2ee2c3f17 /cesar
parent4f47819a5e258f8ec78f728306f03171836094a1 (diff)
parent879c5d0937bbfc176170ae51c571245e32016183 (diff)
Merge branch 'master' into av
Diffstat (limited to 'cesar')
-rw-r--r--cesar/common/make/config.mk2
-rw-r--r--cesar/common/tests/tests2
-rw-r--r--cesar/cp/defs.h5
-rw-r--r--cesar/cp/sta/action/src/drv.c11
-rw-r--r--cesar/cp/sta/action/src/misc.c4
-rw-r--r--cesar/cp/sta/action/test/utest/src/drv.c64
-rw-r--r--cesar/cp/sta/action/test/utest/src/misc.c4
-rw-r--r--cesar/cp/sta/mgr/src/sta_mgr.c4
-rw-r--r--cesar/hal/arch/io.h3
-rw-r--r--cesar/hal/hle/Config1
-rw-r--r--cesar/hal/hle/Module4
-rw-r--r--cesar/hal/hle/defs.h7
-rw-r--r--cesar/hal/hle/doc/claudia_ipmbox.odtbin190080 -> 196207 bytes
-rw-r--r--cesar/hal/hle/inc/hal_ipmbox.h9
-rw-r--r--cesar/hal/hle/inc/ipmbox.h7
-rw-r--r--cesar/hal/hle/ipmbox.h9
-rw-r--r--cesar/hal/hle/maximus/src/maximus_ipmbox.c4
-rw-r--r--cesar/hal/hle/maximus/test/src/test_maximus_ipmbox.c2
-rw-r--r--cesar/hal/hle/src/ipmbox.c36
-rw-r--r--cesar/hal/hle/src/ipmbox_debug_dump.c114
-rw-r--r--cesar/hal/hle/test/Config1
-rw-r--r--cesar/hal/hle/test/src/hal_hle_ipmbox.c157
-rw-r--r--cesar/hal/leon/src/fatal_button.c3
-rw-r--r--cesar/hal/phy/inc/phy_params.txt6
-rw-r--r--cesar/hal/phy/inc/regs.h13
-rw-r--r--cesar/hal/phy/spoc/Module2
-rw-r--r--cesar/hal/phy/spoc/inc/utils.h30
-rw-r--r--cesar/hal/phy/spoc/spoc.h4
-rw-r--r--cesar/hal/phy/spoc/src/spoc_regs.c24
-rw-r--r--cesar/hal/phy/spoc/src/utils.c64
-rw-r--r--cesar/hal/phy/spoc/test/Makefile14
-rw-r--r--cesar/hal/phy/spoc/test/src/spoc_coeff_check.c13
-rw-r--r--cesar/hal/phy/spoc/test/src/test_spoc.c91
-rw-r--r--cesar/hal/phy/src/phy.c136
-rw-r--r--cesar/hal/phy/src/phy_params.pl1
-rw-r--r--cesar/hal/phy/test/phy/doc/test_phy.txt4
-rw-r--r--cesar/hal/phy/test/phy/src/test_phy.c3
-rw-r--r--cesar/lib/dbg.h67
-rw-r--r--cesar/lib/src/dbg.c131
-rw-r--r--cesar/lib/src/trace.c16
-rw-r--r--cesar/lib/test/utils/src/test_utils.c7
-rw-r--r--cesar/lib/utils.h15
42 files changed, 951 insertions, 143 deletions
diff --git a/cesar/common/make/config.mk b/cesar/common/make/config.mk
index b49ae019f8..ab56cfc786 100644
--- a/cesar/common/make/config.mk
+++ b/cesar/common/make/config.mk
@@ -21,7 +21,7 @@ MODULE_CONFIG_FORCE := $(if $(call list-neq,$(MODULE_LIST),$(ALL_MODULES)),MODUL
HEADERS_CONFIG_STAMP := $(HEADERS_CONFIG)/headers.stamp
.PHONY: BUILD_INFO_FORCE
-BUILD_INFO_FLAGS := -i implementation
+BUILD_INFO_FLAGS := -i implementation -i project -i version
COMPILE_DEPS += $(HEADERS_CONFIG_STAMP) $(OBJ_INC_DIR)/module_config.h $(OBJ_INC_DIR)/build_info.h
diff --git a/cesar/common/tests/tests b/cesar/common/tests/tests
index 8a6c547d8c..b8b2a25445 100644
--- a/cesar/common/tests/tests
+++ b/cesar/common/tests/tests
@@ -477,7 +477,7 @@ region: ./obj/region
hal/phy/spoc/test:
make host.all
-spoc: ./obj/spoc_host_check_coeff
+test_spoc: ./obj/test_spoc
test_general/station/compliance:
make
diff --git a/cesar/cp/defs.h b/cesar/cp/defs.h
index 0e33ccc898..8e94fc878e 100644
--- a/cesar/cp/defs.h
+++ b/cesar/cp/defs.h
@@ -13,8 +13,6 @@
* \ingroup cp
*/
-#include "build_info.h"
-
/* Timeout value. */
#define CP_TIMEOUT_MS 1000
@@ -68,9 +66,6 @@
#define CP_BIDIRECTIONAL_BURSTING_CAP false
#define CP_BIDIRECTIONAL_BURSTING_CAP_MAX 2
-/** Implementation Version. */
-#define CP_IMPLEMENTATION_VERSION BUILD_INFO_IMPLEMENTATION
-
/** Minimum size of NPW password. */
#define CP_NPW_MIN_SIZE 8 // bytes
#define CP_NPW_MAX_SIZE 64 // bytes
diff --git a/cesar/cp/sta/action/src/drv.c b/cesar/cp/sta/action/src/drv.c
index 292f7ad47c..ba1707a384 100644
--- a/cesar/cp/sta/action/src/drv.c
+++ b/cesar/cp/sta/action/src/drv.c
@@ -446,7 +446,16 @@ cp_sta_action_drv__drv_sta_status_common (cp_t *ctx,
dbg_assert (ctx);
dbg_assert (data);
- if (cp_sta_own_data_get_tei (ctx) == MAC_TEI_UNASSOCIATED)
+ if (cp_sta_own_data_get_cco_status (ctx))
+ {
+ cp_net_t *net = cp_sta_mgr_get_our_avln (ctx);
+ data->cco = CP_MSG_DRV_STA_STATUS_CCO_CCO;
+ if (net->num_associated_stas)
+ data->status = CP_MSG_DRV_STA_STATUS_STATUS_AUTH;
+ else
+ data->status = CP_MSG_DRV_STA_STATUS_STATUS_UNASSOC;
+ }
+ else if (cp_sta_own_data_get_tei (ctx) == MAC_TEI_UNASSOCIATED)
{
data->status = CP_MSG_DRV_STA_STATUS_STATUS_UNASSOC;
data->cco = CP_MSG_DRV_STA_STATUS_CCO_STA;
diff --git a/cesar/cp/sta/action/src/misc.c b/cesar/cp/sta/action/src/misc.c
index 81094a3854..f3c52e69c8 100644
--- a/cesar/cp/sta/action/src/misc.c
+++ b/cesar/cp/sta/action/src/misc.c
@@ -27,6 +27,8 @@
#include "mac/common/timings.h"
#include "cp/fsm/fsm.h"
+#include "build_info.h"
+
void
cp_sta_action_misc_init (cp_t *ctx)
{
@@ -682,7 +684,7 @@ cp_sta_action_process_cm_sta_cap_req (cp_t *ctx, cp_mme_rx_t *rx_mme)
data.homeplug_101_int = CP_HOMEPLUG_AV101;
data.regulatory_cap = CP_REGULATORY_CAP;
data.bidir_burst = CP_BIDIRECTIONAL_BURSTING_CAP;
- data.implementation_version = CP_IMPLEMENTATION_VERSION;
+ data.implementation_version = BUILD_INFO_IMPLEMENTATION;
cp_msg_cm_sta_cap_cnf_send (ctx, &rx_mme->peer, &data);
}
diff --git a/cesar/cp/sta/action/test/utest/src/drv.c b/cesar/cp/sta/action/test/utest/src/drv.c
index 6634136d46..7f471319d5 100644
--- a/cesar/cp/sta/action/test/utest/src/drv.c
+++ b/cesar/cp/sta/action/test/utest/src/drv.c
@@ -620,19 +620,19 @@ drv_get_sta_status_test_case (test_t t)
{
test_sta_action_t ctx;
test_case_begin (t, "DRV_GET_STA_STATUS");
+ cp_mme_peer_t peer = CP_MME_PEER(0x1, MAC_TEI_FOREIGN);
+ test_sta_action_init (&ctx);
- test_begin (t, "Good and bad")
- {
- cp_mme_peer_t peer = CP_MME_PEER(0x1, MAC_TEI_FOREIGN);
- test_sta_action_init (&ctx);
+ scenario_globals_t globals = {
+ .cp = &ctx.cp,
+ };
- scenario_globals_t globals = {
- .cp = &ctx.cp,
- };
+ cp_sta_own_data_set_tei (&ctx.cp, 1);
+ cp_sta_own_data_set_security_level (&ctx.cp, CP_SECURITY_LEVEL_HS);
- cp_sta_own_data_set_tei (&ctx.cp, 1);
- cp_sta_own_data_set_security_level (&ctx.cp, CP_SECURITY_LEVEL_HS);
+ test_begin (t, "Good and bad")
+ {
scenario_entry_t entries[] = {
SCENARIO_ACTION (drv__drv_sta_status_req,
.peer = peer),
@@ -663,6 +663,52 @@ drv_get_sta_status_test_case (test_t t)
scenario_run (t, entries, &globals);
}
test_end;
+ test_begin (t, "UCCo/CCo status")
+ {
+ scenario_entry_t entries_ucco[] = {
+ SCENARIO_ACTION (drv__drv_sta_status_req,
+ .peer = peer),
+ SCENARIO_EVENT (cp_msg_drv_sta_status_req_receive,
+ .ok = true),
+ SCENARIO_EVENT (cp_msg_drv_sta_status_cnf_send,
+ .peer = peer,
+ .result = CP_MSG_DRV_RESULT_SUCCESS,
+ .status = CP_MSG_DRV_STA_STATUS_STATUS_UNASSOC,
+ .cco = CP_MSG_DRV_STA_STATUS_CCO_CCO,
+ .preferred_cco = false,
+ .backup_cco = false,
+ .simple_connect = false),
+ SCENARIO_END
+ };
+ /* Set our AVLN. */
+ cp_snid_t snid = cp_sta_own_data_get_snid (&ctx.cp);
+ cp_nid_t nid = cp_sta_own_data_get_nid (&ctx.cp);
+ cp_net_t *net = cp_sta_mgr_add_avln (&ctx.cp, snid, nid);
+ cp_sta_mgr_set_our_avln (&ctx.cp, net);
+ cp_sta_own_data_set_cco_status (&ctx.cp, true);
+ net->num_associated_stas = 0;
+ scenario_run (t, entries_ucco, &globals);
+
+ scenario_entry_t entries_cco[] = {
+ SCENARIO_ACTION (drv__drv_sta_status_req,
+ .peer = peer),
+ SCENARIO_EVENT (cp_msg_drv_sta_status_req_receive,
+ .ok = true),
+ SCENARIO_EVENT (cp_msg_drv_sta_status_cnf_send,
+ .peer = peer,
+ .result = CP_MSG_DRV_RESULT_SUCCESS,
+ .status = CP_MSG_DRV_STA_STATUS_STATUS_AUTH,
+ .cco = CP_MSG_DRV_STA_STATUS_CCO_CCO,
+ .preferred_cco = false,
+ .backup_cco = false,
+ .simple_connect = false),
+ SCENARIO_END
+ };
+ /* Set our AVLN. */
+ net->num_associated_stas = 1;
+ scenario_run (t, entries_cco, &globals);
+ }
+ test_end;
}
void
diff --git a/cesar/cp/sta/action/test/utest/src/misc.c b/cesar/cp/sta/action/test/utest/src/misc.c
index 1920dbcc44..df68c86d77 100644
--- a/cesar/cp/sta/action/test/utest/src/misc.c
+++ b/cesar/cp/sta/action/test/utest/src/misc.c
@@ -22,6 +22,8 @@
#include "mac/common/timings.h"
#include "cp/sta/action/action.h"
+#include "build_info.h"
+
void
misc_whoru_test_case (test_t t)
{
@@ -1830,7 +1832,7 @@ misc_sta_cap_test_case (test_t t)
.homeplug_101_int = CP_HOMEPLUG_AV101,
.regulatory_cap = CP_REGULATORY_CAP,
.bidir_burst = CP_BIDIRECTIONAL_BURSTING_CAP,
- .implementation_version = CP_IMPLEMENTATION_VERSION),
+ .implementation_version = BUILD_INFO_IMPLEMENTATION),
SCENARIO_END
};
scenario_run (t, entries, &globals);
diff --git a/cesar/cp/sta/mgr/src/sta_mgr.c b/cesar/cp/sta/mgr/src/sta_mgr.c
index 012aea58ea..d8910c04c5 100644
--- a/cesar/cp/sta/mgr/src/sta_mgr.c
+++ b/cesar/cp/sta/mgr/src/sta_mgr.c
@@ -170,6 +170,8 @@ cp_sta_mgr_sta_add_realy (cp_t *ctx, cp_net_t *net, cp_tei_t tei,
if (MAC_TEI_IS_STA (tei))
sta->net->num_associated_stas ++;
+ if (net == ctx->sta_mgr.our_avln && sta->net->num_associated_stas == 1)
+ cp_fsm_post_new_event (ctx, bare, sta_status_changed);
net->num_visible_stas ++;
net->num_stas ++;
@@ -681,6 +683,8 @@ cp_sta_mgr_sta_remove (cp_t *ctx, cp_sta_t * station)
if (MAC_TEI_IS_STA (cp_sta_get_tei (&sta->public_data)))
sta->net->num_associated_stas--;
+ if (net == ctx->sta_mgr.our_avln && sta->net->num_associated_stas == 0)
+ cp_fsm_post_new_event (ctx, bare, sta_status_changed);
cp_sta_mgr_elects_sta_partial_ack (ctx);
diff --git a/cesar/hal/arch/io.h b/cesar/hal/arch/io.h
index 5e66f59b3a..be06d65647 100644
--- a/cesar/hal/arch/io.h
+++ b/cesar/hal/arch/io.h
@@ -79,7 +79,8 @@ arch_io_write (const char *text, uint text_size);
} while (0)
# define arch_io_write(text, text_size) do { \
- write (1, (text), (text_size)); \
+ if (text_size) \
+ write (1, (text), (text_size)); \
} while (0)
#endif /* !(defined (ECOS) && ECOS) */
diff --git a/cesar/hal/hle/Config b/cesar/hal/hle/Config
new file mode 100644
index 0000000000..6e41f6bf52
--- /dev/null
+++ b/cesar/hal/hle/Config
@@ -0,0 +1 @@
+CONFIG_IPMBOX_DEBUG_DUMP = n
diff --git a/cesar/hal/hle/Module b/cesar/hal/hle/Module
index e3d78156f4..5ba71bcf93 100644
--- a/cesar/hal/hle/Module
+++ b/cesar/hal/hle/Module
@@ -1 +1,5 @@
SOURCES := hal_ipmbox.c ipmbox.c
+
+ifeq ($(CONFIG_IPMBOX_DEBUG_DUMP),y)
+SOURCES += ipmbox_debug_dump.c
+endif
diff --git a/cesar/hal/hle/defs.h b/cesar/hal/hle/defs.h
index c934d165a6..546eda230e 100644
--- a/cesar/hal/hle/defs.h
+++ b/cesar/hal/hle/defs.h
@@ -26,6 +26,8 @@
#define IPMBOX_REG__PARAM_INTERFACE_TYPE 19, 12 /* 8 bits. */
#define IPMBOX_REG__PARAM_INTERFACE_LENGTH 30, 20 /* 11 bits. */
+#define IPMBOX_REG__PARAM_DEBUG_DUMP_LENGTH 27, 12 /* 16 bits. */
+
/** Message header (32 bits). */
struct ipmbox_msg_hdr_t
{
@@ -46,8 +48,9 @@ enum hle_msg_type_t
HLE_MSG_TYPE_BUFFER_ADD = 0x01, /*< Buffer alloc message type. */
HLE_MSG_TYPE_SEND_DONE = 0x02, /*< Buffer dealloc message type. */
HLE_MSG_TYPE_INTERFACE = 0x03, /*< Interface message type. */
- HLE_MSG_TYPE_NB, /*< Number of defined message types. */
- HLE_MSG_TYPE_NONE = HLE_MSG_TYPE_NB /*< Invalid message type. */
+ HLE_MSG_TYPE_BASE_NB, /*< Number of defined base message types. */
+ HLE_MSG_TYPE_DEBUG_DUMP = 0x40, /*< Debug dump message type. */
+ HLE_MSG_TYPE_NONE = 0xff /*< Invalid message type. */
};
typedef enum hle_msg_type_t hle_msg_type_t;
diff --git a/cesar/hal/hle/doc/claudia_ipmbox.odt b/cesar/hal/hle/doc/claudia_ipmbox.odt
index 8c257be59e..760fb0bb60 100644
--- a/cesar/hal/hle/doc/claudia_ipmbox.odt
+++ b/cesar/hal/hle/doc/claudia_ipmbox.odt
Binary files differ
diff --git a/cesar/hal/hle/inc/hal_ipmbox.h b/cesar/hal/hle/inc/hal_ipmbox.h
index cd4a853edb..a04367a78b 100644
--- a/cesar/hal/hle/inc/hal_ipmbox.h
+++ b/cesar/hal/hle/inc/hal_ipmbox.h
@@ -77,6 +77,15 @@ clr_L2Aa_interrupt (void)
}
/**
+ * Read the Arm to Leon Interrupt.
+ */
+extern inline bool
+get_A2Lt_interrupt (void)
+{
+ return (A2L_IT & A2LT_MASK) ? true : false;
+}
+
+/**
* Set the Leon to Arm Interrupt.
*/
extern inline void
diff --git a/cesar/hal/hle/inc/ipmbox.h b/cesar/hal/hle/inc/ipmbox.h
index 7ad0518a85..a273a8edfa 100644
--- a/cesar/hal/hle/inc/ipmbox.h
+++ b/cesar/hal/hle/inc/ipmbox.h
@@ -102,4 +102,11 @@ struct ipmbox_t {
cyg_handle_t rx_it_handle;
};
+/**
+ * Initialise debug dump code.
+ * \param ctx ipmbox context
+ */
+void
+ipmbox_debug_dump_init (ipmbox_t *ctx);
+
#endif /* ipmbox_h */
diff --git a/cesar/hal/hle/ipmbox.h b/cesar/hal/hle/ipmbox.h
index 9507383928..e0d79c5e8d 100644
--- a/cesar/hal/hle/ipmbox.h
+++ b/cesar/hal/hle/ipmbox.h
@@ -57,6 +57,15 @@ ipmbox_uninit (ipmbox_t *ctx);
void
ipmbox_tx (ipmbox_t *ctx, u32 *first_msg, uint length);
+/**
+ * Receive message from mailbox, interrupts locked.
+ * \param ctx ipmbox context
+ * \param first_msg pointer to store first received message address
+ * \return total length (in word) of received messages
+ */
+uint
+ipmbox_rx_sync (ipmbox_t *ctx, const u32 **first_msg);
+
END_DECLS
#endif /* hal_hle_ipmbox_h */
diff --git a/cesar/hal/hle/maximus/src/maximus_ipmbox.c b/cesar/hal/hle/maximus/src/maximus_ipmbox.c
index ac2dfc2596..5f66c4bb1e 100644
--- a/cesar/hal/hle/maximus/src/maximus_ipmbox.c
+++ b/cesar/hal/hle/maximus/src/maximus_ipmbox.c
@@ -203,9 +203,9 @@ ipmbox_tx (ipmbox_t *ctx, u32 *first_msg, uint length)
else
{
ipmbox_msg_hdr_t hdr = *(ipmbox_msg_hdr_t *)first_msg;
- dbg_assert(HLE_MSG_TYPE_NB > hdr.type);
+ dbg_assert(HLE_MSG_TYPE_BASE_NB > hdr.type);
dbg_assert(1 == hdr.length);
- if ((HLE_MSG_TYPE_NB <= hdr.type)
+ if ((HLE_MSG_TYPE_BASE_NB <= hdr.type)
|| (1 != hdr.length))
{
errno = EINVAL;
diff --git a/cesar/hal/hle/maximus/test/src/test_maximus_ipmbox.c b/cesar/hal/hle/maximus/test/src/test_maximus_ipmbox.c
index 0fb58ada0f..98ae2f38ea 100644
--- a/cesar/hal/hle/maximus/test/src/test_maximus_ipmbox.c
+++ b/cesar/hal/hle/maximus/test/src/test_maximus_ipmbox.c
@@ -150,7 +150,7 @@ void ipmbox_tx_test_case(test_t t)
errno = 0;
} test_end;
- for (hdr.type = HLE_MSG_TYPE_DATA; hdr.type < HLE_MSG_TYPE_NB; hdr.type++)
+ for (hdr.type = HLE_MSG_TYPE_DATA; hdr.type < HLE_MSG_TYPE_BASE_NB; hdr.type++)
{
/* Fill sci data. */
diff --git a/cesar/hal/hle/src/ipmbox.c b/cesar/hal/hle/src/ipmbox.c
index 002d5c9863..890b8fb9c1 100644
--- a/cesar/hal/hle/src/ipmbox.c
+++ b/cesar/hal/hle/src/ipmbox.c
@@ -20,6 +20,8 @@
#include "hal/hle/inc/ipmbox.h"
#include "hal/hle/defs.h"
+#include "config/ipmbox.h"
+
/** Rx Mailbox interrupt number */
#define MAILBOX_RX_IT_NUM CYGNUM_HAL_INTERRUPT_GIC2_14
@@ -129,6 +131,35 @@ void mailbox_rx_dsr (cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t dat
A2Lt_it_enable ();
}
+#if CONFIG_IPMBOX_DEBUG_DUMP
+
+uint
+ipmbox_rx_sync (ipmbox_t *ctx, const u32 **first_msg)
+{
+ uint size;
+ /* Only if interrupt set. */
+ if (get_A2Lt_interrupt ())
+ {
+ /* Clear interrupt. */
+ clr_A2Lt_interrupt ();
+ /* Try to slurp all RX queue. */
+ size = A2L_RING_USED_WORDS (A2L_HEAD, A2L_TAIL);
+ if (size)
+ {
+ /* Copy messages out of mailbox, because callback can not handle
+ * circular buffers. */
+ halmbx_copy_from_ring (rx_msgs, size);
+ /* Return received messages. */
+ *first_msg = rx_msgs;
+ return size;
+ }
+ }
+ /* Nothing. */
+ return 0;
+}
+
+#endif /* CONFIG_IPMBOX_DEBUG_DUMP */
+
/**
* Uninitialise the HAL HLE.
* \param ctx ipmbox context
@@ -182,6 +213,11 @@ ipmbox_t * ipmbox_init (void *user_data, ipmbox_rx_cb_t rx_cb)
/* Unmask. */
cyg_drv_interrupt_unmask (MAILBOX_RX_IT_NUM);
+#if CONFIG_IPMBOX_DEBUG_DUMP
+ /* Register debug dump code. */
+ ipmbox_debug_dump_init (ctx);
+#endif
+
return ctx;
}
diff --git a/cesar/hal/hle/src/ipmbox_debug_dump.c b/cesar/hal/hle/src/ipmbox_debug_dump.c
new file mode 100644
index 0000000000..1a459c39e1
--- /dev/null
+++ b/cesar/hal/hle/src/ipmbox_debug_dump.c
@@ -0,0 +1,114 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2010 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file hal/hle/src/ipmbox_debug_dump.c
+ * \brief Handle debug dump over mailbox.
+ * \ingroup hal_hle
+ *
+ * This implements a debug dump over the mailbox to be used for fatal error
+ * dumps.
+ *
+ * When a buffer is to be dumped, this codes reads all messages from mailbox
+ * and only process debug messages. If a message gives a debug buffer, it is
+ * filled and sent back to ARM side.
+ */
+#include "common/std.h"
+
+#include "hal/hle/ipmbox.h"
+#include "hal/hle/defs.h"
+
+/**
+ * Synchronous dump to ARM side.
+ * \param user user parameter (ipmbox context)
+ * \param text text buffer with text to write
+ * \param text_size size of text to write, or 0 for end of dump
+ * \return sent size
+ */
+int
+ipmbox_dump (void *user, const char *text, uint text_size)
+{
+ const u32 *msg_buffer;
+ uint msg_buffer_length;
+ const u32 *m, *mend;
+ uint msg, type;
+ u32 *buffer;
+ uint buffer_length;
+ uint dump, dumped;
+ u32 w;
+ uint wb;
+ int sent = text_size;
+ bool end_of_dump = text_size == 0;
+ ipmbox_t *ctx = user;
+ dbg_assert (ctx);
+ /** Loop until satisfied. */
+ while (text_size || end_of_dump)
+ {
+ /* Get mailbox content. */
+ msg_buffer = NULL;
+ msg_buffer_length = ipmbox_rx_sync (ctx, &msg_buffer);
+ m = msg_buffer;
+ mend = msg_buffer + msg_buffer_length;
+ /* Read messages. */
+ while (m != mend)
+ {
+ msg = m[0];
+ type = BF_GET (IPMBOX_REG__MSG_TYPE, msg);
+ switch (type)
+ {
+ case HLE_MSG_TYPE_DEBUG_DUMP:
+ /* Dump buffer. */
+ buffer_length =
+ BF_GET (IPMBOX_REG__PARAM_DEBUG_DUMP_LENGTH, msg);
+ buffer = (u32 *) m[1];
+ /* Fill it, little endian. */
+ dumped = dump = MIN (text_size, buffer_length);
+ for (; dump >= 4; dump -= 4)
+ {
+ w = *text++;
+ w |= *text++ << 8;
+ w |= *text++ << 16;
+ w |= *text++ << 24;
+ *buffer++ = w;
+ }
+ w = 0; wb = 0;
+ for (; dump; dump--)
+ {
+ w |= *text++ << wb;
+ wb += 8;
+ }
+ if (wb)
+ *buffer++ = w;
+ text_size -= dumped;
+ /* Send back message. */
+ u32 msg_tx[2];
+ msg_tx[0] = BF_FILL (IPMBOX_REG,
+ (MSG_TYPE, HLE_MSG_TYPE_DEBUG_DUMP),
+ (MSG_LENGTH, 1),
+ (PARAM_DEBUG_DUMP_LENGTH, dumped));
+ msg_tx[1] = m[1];
+ ipmbox_tx (ctx, msg_tx, 2);
+ /* Clear end_of_dump flag, it was sent. */
+ end_of_dump = false;
+ break;
+ default:
+ /* Ignore message. */
+ break;
+ }
+ /* Message length + the message header. */
+ m += BF_GET (IPMBOX_REG__MSG_LENGTH, msg) + 1;
+ }
+ }
+ return sent;
+}
+
+void
+ipmbox_debug_dump_init (ipmbox_t *ctx)
+{
+ dbg_register_dump_callback (ipmbox_dump, ctx);
+}
+
diff --git a/cesar/hal/hle/test/Config b/cesar/hal/hle/test/Config
new file mode 100644
index 0000000000..d164b2c80e
--- /dev/null
+++ b/cesar/hal/hle/test/Config
@@ -0,0 +1 @@
+CONFIG_IPMBOX_DEBUG_DUMP = y
diff --git a/cesar/hal/hle/test/src/hal_hle_ipmbox.c b/cesar/hal/hle/test/src/hal_hle_ipmbox.c
index 5bd60daeb5..5073425ee1 100644
--- a/cesar/hal/hle/test/src/hal_hle_ipmbox.c
+++ b/cesar/hal/hle/test/src/hal_hle_ipmbox.c
@@ -41,6 +41,9 @@ ipmbox_t *ctx;
bool dsr_posted;
+int
+ipmbox_dump (void *user, const char *text, uint text_size);
+
void my_callback(void *user_data, u32 *first_msg, uint length)
{
}
@@ -249,6 +252,158 @@ test_ipmbox_budget (void)
} test_end;
}
+void
+test_ipmbox_sync (void)
+{
+ uint i, j;
+ test_case_begin (test, "sync");
+ ctx = ipmbox_init (NULL, my_callback); /* Callback not used. */
+ utest_A2L_head = A2L_RING_BASE_ADDR;
+ utest_A2L_tail = A2L_RING_BASE_ADDR;
+ /* Read with roll-over. */
+ test_begin (test, "rollover")
+ {
+ /* Fill mailbox with a roll-over. */
+ utest_A2L_head += A2L_RING_SIZE * 3 / 4;
+ utest_A2L_tail = utest_A2L_head;
+ for (i = 0, j = A2L_RING_WORDS * 3 / 4;
+ i < A2L_RING_WORDS / 4;
+ i++, j++)
+ A2L_ring[j] = i;
+ for (j = 0;
+ i < A2L_RING_WORDS / 2;
+ i++, j++)
+ A2L_ring[j] = i;
+ utest_A2L_tail += A2L_RING_SIZE / 2;
+ /* Set interrupt. */
+ utest_A2L_it = A2LT_MASK;
+ /* Read everything. */
+ const u32 *rx_msg = NULL;
+ uint rx_msg_length;
+ rx_msg_length = ipmbox_rx_sync (ctx, &rx_msg);
+ /* Check result. */
+ test_fail_unless (rx_msg_length == A2L_RING_WORDS / 2);
+ test_fail_unless (rx_msg);
+ for (i = 0; i < rx_msg_length; i++)
+ test_fail_unless (rx_msg[i] == i);
+ } test_end;
+ /* No interrupt. */
+ test_begin (test, "no interrupt")
+ {
+ /* Read everything. */
+ const u32 *rx_msg = NULL;
+ uint rx_msg_length;
+ rx_msg_length = ipmbox_rx_sync (ctx, &rx_msg);
+ /* Check result. */
+ test_fail_unless (rx_msg_length == 0);
+ test_fail_unless (rx_msg == NULL);
+ } test_end;
+ /* Nothing to read. */
+ test_begin (test, "nothing to read")
+ {
+ /* Set interrupt. */
+ utest_A2L_it = A2LT_MASK;
+ /* Read everything. */
+ const u32 *rx_msg = NULL;
+ uint rx_msg_length;
+ rx_msg_length = ipmbox_rx_sync (ctx, &rx_msg);
+ /* Check result. */
+ test_fail_unless (rx_msg_length == 0);
+ test_fail_unless (rx_msg == NULL);
+ } test_end;
+}
+
+static void
+test_ipmbox_debug_dump_step (test_t test, uint *i, uint *n, const char *sdump,
+ const char *s1, const char *s2)
+{
+ test_within (test);
+ char buffer1[16];
+ char buffer2[16];
+ /* Fill mailbox with a debug dump message. */
+ A2L_ring[*i + 0] = 0x10140;
+ A2L_ring[*i + 1] = (u32) buffer1;
+ utest_A2L_tail += 8;
+ *n += 8;
+ if (s2)
+ {
+ A2L_ring[*i + 2] = 0x10140;
+ A2L_ring[*i + 3] = (u32) buffer2;
+ utest_A2L_tail += 8;
+ *n += 8;
+ }
+ utest_A2L_it = A2LT_MASK;
+ /* Dump. */
+ ipmbox_dump (ctx, sdump, strlen (sdump));
+ /* Check result, little endian. */
+#if DEFS_BIG_ENDIAN
+# error "test defined for little endian"
+#endif
+ test_fail_unless (utest_L2A_tail - utest_L2A_head == *n);
+ test_fail_unless (L2A_ring[*i + 0] == (0x140 | strlen (s1) << 12));
+ test_fail_unless (L2A_ring[*i + 1] == (u32) buffer1);
+ test_fail_unless (memcmp (buffer1, s1, strlen (s1)) == 0);
+ *i += 2;
+ if (s2)
+ {
+ test_fail_unless (L2A_ring[*i + 0] == (0x140 | strlen (s2) << 12));
+ test_fail_unless (L2A_ring[*i + 1] == (u32) buffer2);
+ test_fail_unless (memcmp (buffer2, s2, strlen (s2)) == 0);
+ *i += 2;
+ }
+}
+
+void
+test_ipmbox_debug_dump (void)
+{
+ uint i, n;
+ test_case_begin (test, "debug dump");
+ ctx = ipmbox_init (NULL, my_callback); /* Callback not used. */
+ utest_A2L_head = A2L_RING_BASE_ADDR;
+ utest_A2L_tail = utest_A2L_head;
+ utest_L2A_head = L2A_RING_BASE_ADDR;
+ utest_L2A_tail = utest_L2A_head;
+ i = 0;
+ n = 0;
+ /* Various sizes. */
+ test_begin (test, "1 char")
+ {
+ test_ipmbox_debug_dump_step (test, &i, &n, "a", "a", NULL);
+ } test_end;
+ test_begin (test, "2 char")
+ {
+ test_ipmbox_debug_dump_step (test, &i, &n, "ba", "ba", NULL);
+ } test_end;
+ test_begin (test, "3 char")
+ {
+ test_ipmbox_debug_dump_step (test, &i, &n, "cba", "cba", NULL);
+ } test_end;
+ test_begin (test, "4 char")
+ {
+ test_ipmbox_debug_dump_step (test, &i, &n, "dcba", "dcba", NULL);
+ } test_end;
+ test_begin (test, "5 char")
+ {
+ test_ipmbox_debug_dump_step (test, &i, &n, "edcba", "edcba", NULL);
+ } test_end;
+ test_begin (test, "16 char")
+ {
+ test_ipmbox_debug_dump_step (test, &i, &n, "0123456789abcdef",
+ "0123456789abcdef", NULL);
+ } test_end;
+ /* Buffer overflow. */
+ test_begin (test, "17 char, buffer overflow")
+ {
+ test_ipmbox_debug_dump_step (test, &i, &n, "0123456789abcdefg",
+ "0123456789abcdef", "g");
+ } test_end;
+ /* End of dump. */
+ test_begin (test, "end of dump")
+ {
+ test_ipmbox_debug_dump_step (test, &i, &n, "", "", NULL);
+ } test_end;
+}
+
int main (int argc, char **argv)
{
test_init (test, argc, argv);
@@ -258,7 +413,9 @@ int main (int argc, char **argv)
test_ipmbox_tx();
test_ipmbox_irq();
test_ipmbox_budget();
+ test_ipmbox_sync();
test_ipmbox_uninit();
+ test_ipmbox_debug_dump();
test_result (test);
return test_nb_failed (test) == 0 ? 0 : 1;
diff --git a/cesar/hal/leon/src/fatal_button.c b/cesar/hal/leon/src/fatal_button.c
index 19a16e5151..a52f1e6044 100644
--- a/cesar/hal/leon/src/fatal_button.c
+++ b/cesar/hal/leon/src/fatal_button.c
@@ -76,7 +76,6 @@ leon_fatal_button_init (void)
| LEON_GPIO_IT_CONFIG_EDGE
| CONFIG_GPIO_LEON_FATAL_BUTTON_GPIO);
/* Register callback to dbg lib. */
- dbg_assert (!dbg_fatal_cb[0]);
- dbg_fatal_cb[0] = leon_fatal_sync;
+ dbg_register_fatal_callback (0, leon_fatal_sync);
}
diff --git a/cesar/hal/phy/inc/phy_params.txt b/cesar/hal/phy/inc/phy_params.txt
index 62e2bcad9d..73218216d4 100644
--- a/cesar/hal/phy/inc/phy_params.txt
+++ b/cesar/hal/phy/inc/phy_params.txt
@@ -68,10 +68,10 @@ rx_spoc_filter_shift = (d_mul, 0), (m_mul, 0), (m_add1, 0),
(m_add5, 0), (m_add6, 0)
rx_spoc_offset_blk_exp = (spoc_tx, 0)
-wiener_real = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
-wiener_imag = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+wiener_real = { 0, 0, 0, 0, 0, 41989, 45323, 48035, 50037, 51265, 51679, 51265, 50037, 48035, 45323, 41989, 0, 0, 0, 0, 0 }
+wiener_imag = { 0, 0, 0, 0, 0, -7484, -6689, -5441, -3835, -1981, 0, 1981, 3835, 5441, 6689, 7484, 0, 0, 0, 0, 0}
wiener_spoc_filter_shift = (d_mul, 0), (m_mul, 0), (m_add1, 0),
(m_add2, 0), (m_add3, 1), (m_add4, 0),
(m_add5, 0), (m_add6, 0)
-wiener_spoc_offset_blk_exp = (spoc_tx, 1)
+wiener_spoc_offset_blk_exp = (spoc_tx, -2)
diff --git a/cesar/hal/phy/inc/regs.h b/cesar/hal/phy/inc/regs.h
index 81dfd31fe4..8d5934a609 100644
--- a/cesar/hal/phy/inc/regs.h
+++ b/cesar/hal/phy/inc/regs.h
@@ -312,6 +312,19 @@ typedef u32 uint32_t;
#define PHY_DSPSS_SPOC_SET_REQUEST__RX 2
#define PHY_DSPSS_SPOC_SET_REQUEST__WIENER 3
+/* SPOC_DEBUG_MODE */
+#define PHY_DSPSS_SPOC_DEBUG_MODE__RX_OR_WIENER_IN_TX_MEMORY 0, 0
+#define PHY_DSPSS_SPOC_DEBUG_MODE__D_MATRIX_UNUSED 1, 1
+#define PHY_DSPSS_SPOC_DEBUG_MODE__M_MATRIX_UNUSED 2, 2
+#define PHY_DSPSS_SPOC_DEBUG_MODE__M_MATRIX_WITHOUT_PHASE 3, 3
+#define PHY_DSPSS_SPOC_DEBUG_MODE__BYPASS 4, 4
+
+/* WIENER_PHASE_CORRECTION */
+#define PHY_DSPSS_WIENER_PHASE_CORRECTION__IND_MAX_IFFT_ON_CHEPRE 8, 0
+#define PHY_DSPSS_WIENER_PHASE_CORRECTION__SOFT_PHASE 17, 9
+#define PHY_DSPSS_WIENER_PHASE_CORRECTION__SOFT_PHASE_EN 18, 18
+#define PHY_DSPSS_WIENER_PHASE_CORRECTION__PHASE_CORRECTION_EN 19, 19
+
/* WIENER_CHANNEL_MAX_DETECTION_PARAM */
#define PHY_DSPSS_WIENER_CHANNEL_MAX_DETECTION_PARAM__FREQ_HOLE_WIDTH 7, 0
#define PHY_DSPSS_WIENER_CHANNEL_MAX_DETECTION_PARAM__SOFT_ADDR 16, 8
diff --git a/cesar/hal/phy/spoc/Module b/cesar/hal/phy/spoc/Module
index 0a7f2b4b11..75a0c66074 100644
--- a/cesar/hal/phy/spoc/Module
+++ b/cesar/hal/phy/spoc/Module
@@ -1 +1 @@
-SOURCES := spoc.c spoc_regs.c
+SOURCES := spoc.c spoc_regs.c utils.c
diff --git a/cesar/hal/phy/spoc/inc/utils.h b/cesar/hal/phy/spoc/inc/utils.h
new file mode 100644
index 0000000000..de9de6103a
--- /dev/null
+++ b/cesar/hal/phy/spoc/inc/utils.h
@@ -0,0 +1,30 @@
+#ifndef inc_utils_h
+#define inc_utils_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2010 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file hal/phy/spoc/inc/utils.h
+ * \brief SPOC utilities.
+ * \ingroup hal_phy
+ */
+
+BEGIN_DECLS
+
+/**
+ * Find first and last unmasked carriers.
+ * \param tonemask tonemask data
+ * \param first_unmasked will receive first unmasked carrier
+ * \param last_unmasked will receive last unmasked carrier
+ */
+void
+phy_spoc_analyse_tonemask (const u32 *tonemask, uint *first_unmasked,
+ uint *last_unmasked);
+
+END_DECLS
+
+#endif /* inc_utils_h */
diff --git a/cesar/hal/phy/spoc/spoc.h b/cesar/hal/phy/spoc/spoc.h
index 5cc7e19ce1..7288d09852 100644
--- a/cesar/hal/phy/spoc/spoc.h
+++ b/cesar/hal/phy/spoc/spoc.h
@@ -86,9 +86,11 @@ phy_spoc_compute_all (s32 rho_q30, phy_spoc_coeff_t *coeff);
* Initialise SPOC initial state.
* \param ctx phy context
* \param rho_q30 initial frequency error, Q30 format
+ * \param tonemask tonemask data
+ * \param carrier_nb number of active carriers in the given tone mask
*/
void
-phy_spoc_init (phy_t *ctx, s32 rho_q30);
+phy_spoc_init (phy_t *ctx, s32 rho_q30, const u32 *tonemask, uint carrier_nb);
/**
* Set SPOC coefficients for TX.
diff --git a/cesar/hal/phy/spoc/src/spoc_regs.c b/cesar/hal/phy/spoc/src/spoc_regs.c
index 4e56762ecd..6b79046823 100644
--- a/cesar/hal/phy/spoc/src/spoc_regs.c
+++ b/cesar/hal/phy/spoc/src/spoc_regs.c
@@ -17,18 +17,21 @@
#include "hal/phy/inc/regs.h"
#include "hal/phy/spoc/inc/defs.h"
+#include "hal/phy/spoc/inc/utils.h"
#include "hal_phy_params.h"
/**
* Set SPOC coefficients for Wiener.
* \param ctx phy context
+ * \param tonemask tonemask data
+ * \param carrier_nb number of active carriers in the given tone mask
*/
static void
-phy_spoc_wiener_set (phy_t *ctx);
+phy_spoc_wiener_set (phy_t *ctx, const u32 *tonemask, uint carrier_nb);
void
-phy_spoc_init (phy_t *ctx, s32 rho_q30)
+phy_spoc_init (phy_t *ctx, s32 rho_q30, const u32 *tonemask, uint carrier_nb)
{
/* Compute coefficients for 0 frequency error. */
phy_spoc_coeff_t coeff;
@@ -38,7 +41,7 @@ phy_spoc_init (phy_t *ctx, s32 rho_q30)
/* Set coefficients. */
phy_spoc_tx_set (ctx, &coeff);
phy_spoc_rx_set (ctx, &coeff);
- phy_spoc_wiener_set (ctx);
+ phy_spoc_wiener_set (ctx, tonemask, carrier_nb);
/* No bypass. */
PHY_DSPSS_SPOC_DEBUG_MODE = 0;
/* Channel maximum erasing. */
@@ -123,10 +126,13 @@ phy_spoc_rx_set (phy_t *ctx, phy_spoc_coeff_t *coeff)
}
static void
-phy_spoc_wiener_set (phy_t *ctx)
+phy_spoc_wiener_set (phy_t *ctx, const u32 *tonemask, uint carrier_nb)
{
uint i;
dbg_assert (ctx);
+ /* Analyse tonemask. */
+ uint first_unmasked, last_unmasked;
+ phy_spoc_analyse_tonemask (tonemask, &first_unmasked, &last_unmasked);
/* Fill registers. */
static const int wiener_real[] = PHY_PARAM_WIENER_REAL;
static const int wiener_imag[] = PHY_PARAM_WIENER_IMAG;
@@ -135,8 +141,10 @@ phy_spoc_wiener_set (phy_t *ctx)
PHY_DSPSS_SPOC_CP_PREBEGIN_n_WIENER_REAL_n[i] = wiener_real[i];
PHY_DSPSS_SPOC_CP_PREEND_n_WIENER_IMAG_n[i] = wiener_imag[i];
}
- PHY_DSPSS_SPOC_RHO_WIENER_USED_CARRIER = PHY_CARRIER_NB;
- PHY_DSPSS_SPOC_M_CENTRAL_WIENER_FIRST_CARRIER = PHY_CARRIER_OFFSET;
+ PHY_DSPSS_SPOC_RHO_WIENER_USED_CARRIER = /* See DSPSS spec. */
+ last_unmasked - first_unmasked + 21;
+ PHY_DSPSS_SPOC_M_CENTRAL_WIENER_FIRST_CARRIER = /* Idem. */
+ PHY_CARRIER_OFFSET + first_unmasked - 9;
PHY_DSPSS_SPOC_FILTER_SHIFT =
BF_FILL (PHY_DSPSS_SPOC_FILTER_SHIFT,
PHY_PARAM_WIENER_SPOC_FILTER_SHIFT);
@@ -147,5 +155,9 @@ phy_spoc_wiener_set (phy_t *ctx)
dbg_assert (PHY_DSPSS_SPOC_SET_REQUEST
== PHY_DSPSS_SPOC_SET_REQUEST__NONE);
PHY_DSPSS_SPOC_SET_REQUEST = PHY_DSPSS_SPOC_SET_REQUEST__WIENER;
+ /* Enable wiener. */
+ PHY_DSPSS_WIENER_PHASE_CORRECTION =
+ BF_FILL (PHY_DSPSS_WIENER_PHASE_CORRECTION,
+ (PHASE_CORRECTION_EN, 1));
}
diff --git a/cesar/hal/phy/spoc/src/utils.c b/cesar/hal/phy/spoc/src/utils.c
new file mode 100644
index 0000000000..4699fddc3f
--- /dev/null
+++ b/cesar/hal/phy/spoc/src/utils.c
@@ -0,0 +1,64 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2010 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file hal/phy/spoc/src/utils.c
+ * \brief SPOC utilities.
+ * \ingroup hal_phy
+ */
+#include "common/std.h"
+
+#include "inc/utils.h"
+#include "hal/phy/defs.h"
+
+void
+phy_spoc_analyse_tonemask (const u32 *tonemask, uint *first_unmasked,
+ uint *last_unmasked)
+{
+ uint i, j;
+ const u32 *tk;
+ u32 tkw, tkbit;
+ dbg_assert (tonemask);
+ /* Find first unmasked carrier. */
+ tk = tonemask;
+ /* Find first non full tonemask word. */
+ for (i = 0; i < PHY_CARRIER_NB / 32; i++)
+ {
+ tkw = *tk++;
+ if (tkw != 0xffffffff)
+ break;
+ }
+ dbg_assert (i < PHY_TONEMASK_WORDS / 32);
+ /* Find first zero tonemask bit. */
+ for (j = 0, tkbit = 1;
+ tkw & tkbit;
+ j++, tkbit <<= 1)
+ ;
+ dbg_assert (tkbit);
+ /* Found. */
+ *first_unmasked = i * 32 + j;
+ /* Find last unmasked carrier. */
+ tk = tonemask + PHY_TONEMASK_WORDS - 1;
+ /* Find last non full tonemask word. */
+ tkw = *tk | (PHY_CARRIER_NB % 32 ? ~BITS_ONES (PHY_CARRIER_NB % 32) : 0);
+ for (i = PHY_TONEMASK_WORDS - 1; i; i--)
+ {
+ if (tkw != 0xffffffff)
+ break;
+ tkw = *--tk;
+ }
+ dbg_assert (i != 0);
+ /* Find last zero tonemask bit. */
+ for (j = 31, tkbit = 1 << 31;
+ tkw & tkbit;
+ j--, tkbit >>= 1)
+ ;
+ dbg_assert (tkbit);
+ /* Found. */
+ *last_unmasked = i * 32 + j;
+}
+
diff --git a/cesar/hal/phy/spoc/test/Makefile b/cesar/hal/phy/spoc/test/Makefile
index c7300ed4f1..ab95f242ad 100644
--- a/cesar/hal/phy/spoc/test/Makefile
+++ b/cesar/hal/phy/spoc/test/Makefile
@@ -3,16 +3,16 @@ BASE = ../../../..
ECOS = y
TARGET = sparc
-HOST_PROGRAMS = spoc_host_check_coeff
-TARGET_PROGRAMS = spoc_target_check_coeff
+HOST_PROGRAMS = test_spoc
+TARGET_PROGRAMS = test_spoc_target
-spoc_host_check_coeff_SOURCES = spoc_coeff_check.c
-spoc_host_check_coeff_MODULES = lib hal/phy/spoc
+test_spoc_SOURCES = test_spoc.c spoc_coeff_check.c
+test_spoc_MODULES = lib hal/phy/spoc mac/common
-spoc_target_check_coeff_SOURCES = spoc_coeff_check.c
-spoc_target_check_coeff_MODULES = lib hal/arch hal/phy hal/phy/spoc
+test_spoc_target_SOURCES = test_spoc.c spoc_coeff_check.c
+test_spoc_target_MODULES = lib hal/arch hal/phy hal/phy/spoc mac/common
-hal_phy_spoc_MODULE_SOURCES = spoc.c
+hal_phy_spoc_MODULE_SOURCES = spoc.c utils.c
coeff_h = obj/inc/coeff.h
CLEAN_FILES += $(coeff_h)
diff --git a/cesar/hal/phy/spoc/test/src/spoc_coeff_check.c b/cesar/hal/phy/spoc/test/src/spoc_coeff_check.c
index 21deb2019b..00c96e8d28 100644
--- a/cesar/hal/phy/spoc/test/src/spoc_coeff_check.c
+++ b/cesar/hal/phy/spoc/test/src/spoc_coeff_check.c
@@ -117,16 +117,3 @@ test_spoc_coeff (test_t test)
}
}
-int
-main (int argc, char **argv)
-{
- test_t test;
-
- test_init (test, argc, argv);
-
- test_spoc_coeff (test);
-
- test_result (test);
- return (test_nb_failed (test) == 0 ? 0 : 1);
-}
-
diff --git a/cesar/hal/phy/spoc/test/src/test_spoc.c b/cesar/hal/phy/spoc/test/src/test_spoc.c
new file mode 100644
index 0000000000..0b6c45f4c8
--- /dev/null
+++ b/cesar/hal/phy/spoc/test/src/test_spoc.c
@@ -0,0 +1,91 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2010 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file src/test_spoc.c
+ * \brief SPOC module check.
+ * \ingroup test
+ */
+#include "common/std.h"
+#include "lib/test.h"
+#include "hal/phy/spoc/inc/utils.h"
+#include "mac/common/tonemask.h"
+
+#include <string.h>
+#include <stdio.h>
+
+void
+test_spoc_coeff (test_t test);
+
+static void
+test_spoc_analyse_tonemask (test_t t)
+{
+ volatile uint i, j;
+ tonemask_info_t ti;
+ uint carrier_nb;
+ uint first_unmasked, last_unmasked;
+ test_case_begin (t, "analyse_tonemask");
+ test_begin (t, "default")
+ {
+ carrier_nb = tonemask_default (ti.tonemask);
+ dbg_assert (carrier_nb == 917);
+ phy_spoc_analyse_tonemask (ti.tonemask, &first_unmasked,
+ &last_unmasked);
+ test_fail_unless (first_unmasked == 86 - PHY_CARRIER_OFFSET);
+ test_fail_unless (last_unmasked == 1143 - PHY_CARRIER_OFFSET);
+ } test_end;
+ test_begin (t, "full")
+ {
+ memset (ti.tonemask, 0, sizeof ti.tonemask);
+ carrier_nb = PHY_CARRIER_NB;
+ phy_spoc_analyse_tonemask (ti.tonemask, &first_unmasked,
+ &last_unmasked);
+ test_fail_unless (first_unmasked == 0);
+ test_fail_unless (last_unmasked == PHY_CARRIER_NB - 1);
+ } test_end;
+ for (i = 0; i < 32; i++)
+ for (j = 0; j < 32; j++)
+ {
+ char test_name[32];
+ snprintf (test_name, sizeof test_name, "begin %d end %d", i, j);
+ test_begin (t, test_name)
+ {
+ uint last_unmasked_expect;
+ memset (ti.tonemask, 0, sizeof ti.tonemask);
+ ti.tonemask[0] = ~(1u << i);
+ if (PHY_CARRIER_NB % 32 == 0 || j < PHY_CARRIER_NB % 32)
+ {
+ last_unmasked_expect = (PHY_TONEMASK_WORDS - 1) * 32 + j;
+ ti.tonemask[PHY_TONEMASK_WORDS - 1] = ~(1u << j);
+ }
+ else
+ {
+ last_unmasked_expect = (PHY_TONEMASK_WORDS - 2) * 32 + j;
+ ti.tonemask[PHY_TONEMASK_WORDS - 2] = ~(1u << j);
+ ti.tonemask[PHY_TONEMASK_WORDS - 1] = ~0u;
+ }
+ carrier_nb = 42; /* Not really used. */
+ phy_spoc_analyse_tonemask (ti.tonemask, &first_unmasked,
+ &last_unmasked);
+ test_fail_unless (first_unmasked == i);
+ test_fail_unless (last_unmasked == last_unmasked_expect);
+ } test_end;
+ }
+}
+
+int
+main (int argc, char **argv)
+{
+ test_t t;
+ test_init (t, argc, argv);
+ test_spoc_coeff (t);
+ test_suite_begin (t, "utils");
+ test_spoc_analyse_tonemask (t);
+ test_result (t);
+ return test_nb_failed (t) == 0 ? 0 : 1;
+}
+
diff --git a/cesar/hal/phy/src/phy.c b/cesar/hal/phy/src/phy.c
index 904f51a568..9a2191a535 100644
--- a/cesar/hal/phy/src/phy.c
+++ b/cesar/hal/phy/src/phy.c
@@ -251,36 +251,53 @@ phy_dsr (cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
#if DEBUG
-#include <stdio.h>
+/** Recorded date at fatal error. */
+u32 phy_fatal_date;
+
+/**
+ * Record urgent registers for fatal dump.
+ */
+static void
+phy_fatal (void)
+{
+ phy_fatal_date = phy_date ();
+}
/**
* Dump interesting parameters on fatal error.
*/
static void
-phy_fatal_dump (void)
+phy_fatal_dump (dbg_dump_callback_t dump_cb, void *dump_cb_user)
{
u32 resys_debug1 = PHY_DSPSS_RESYS_DEBUG_1;
- fprintf (stderr, "date: 0x%08x\n", PHY_PRATIC_STA_LOCAL_TIMER);
- fprintf (stderr, "last preamble: 0x%08x - %d / 3 - %d - %d\n",
- PHY_PRATIC_STA_LAST_RECEIVED_FRAME_DATE,
- BF_GET (PHY_DSPSS_RESYS_DETECT_OFFSET__PREAMBLE,
- PHY_DSPSS_RESYS_DETECT_OFFSET), PHY_PREAMBLE_SYNCP_TCK,
- PHY_RX_HARDWARE_DELAY_TCK);
- fprintf (stderr, "RESYS: exe: 0x%03x symbol: %d sample: %d trans: %d"
- " error fft: %d soft: 0x%08x\n",
- PHY_DSPSS_RESYS_EXE_INSTR_ADDR,
- BF_GET (PHY_DSPSS_RESYS_DEBUG_1__SYMBOL_COUNT, resys_debug1),
- BF_GET (PHY_DSPSS_RESYS_DEBUG_1__SAMPLE_COUNT, resys_debug1),
- BF_GET (PHY_DSPSS_RESYS_DEBUG_2__NEXT_SYMBOL_TRANSITION,
- PHY_DSPSS_RESYS_DEBUG_2),
- PHY_DSPSS_RESYS_ERROR_FFT_NUMBER,
- PHY_DSPSS_RESYS_TIME_TO_RISE_SOFTCOND);
- fprintf (stderr, "PB chain: 0x%08x\n", PHY_DSPSS_PB_CHAIN_INFO);
- fprintf (stderr, "TX chain: 0x%08x\n", PHY_DSPSS_TX_CHAIN_INFO);
- fprintf (stderr, "TX chain: 0x%08x\n", PHY_DSPSS_TX_CHAIN_INFO);
- fprintf (stderr, "time chain: in progress: %d\n",
- BF_GET (PHY_DSPSS_TIME_CHAIN_INFO__CREATION_IN_PROGRESS,
- PHY_DSPSS_TIME_CHAIN_INFO));
+ dbg_dump_printf (
+ dump_cb, dump_cb_user, "date: 0x%08x\n", phy_fatal_date);
+ dbg_dump_printf (
+ dump_cb, dump_cb_user, "last preamble: 0x%08x - %d / 3 - %d - %d\n",
+ PHY_PRATIC_STA_LAST_RECEIVED_FRAME_DATE,
+ BF_GET (PHY_DSPSS_RESYS_DETECT_OFFSET__PREAMBLE,
+ PHY_DSPSS_RESYS_DETECT_OFFSET), PHY_PREAMBLE_SYNCP_TCK,
+ PHY_RX_HARDWARE_DELAY_TCK);
+ dbg_dump_printf (
+ dump_cb, dump_cb_user, "RESYS: exe: 0x%03x symbol: %d sample: "
+ " %d trans: %d error fft: %d soft: 0x%08x\n",
+ PHY_DSPSS_RESYS_EXE_INSTR_ADDR,
+ BF_GET (PHY_DSPSS_RESYS_DEBUG_1__SYMBOL_COUNT, resys_debug1),
+ BF_GET (PHY_DSPSS_RESYS_DEBUG_1__SAMPLE_COUNT, resys_debug1),
+ BF_GET (PHY_DSPSS_RESYS_DEBUG_2__NEXT_SYMBOL_TRANSITION,
+ PHY_DSPSS_RESYS_DEBUG_2),
+ PHY_DSPSS_RESYS_ERROR_FFT_NUMBER,
+ PHY_DSPSS_RESYS_TIME_TO_RISE_SOFTCOND);
+ dbg_dump_printf (
+ dump_cb, dump_cb_user,
+ "PB chain: 0x%08x\nTX chain: 0x%08x\nRX chain: 0x%08x\n",
+ PHY_DSPSS_PB_CHAIN_INFO,
+ PHY_DSPSS_TX_CHAIN_INFO,
+ PHY_DSPSS_RX_CHAIN_INFO);
+ dbg_dump_printf (
+ dump_cb, dump_cb_user, "time chain: in progress: %d\n",
+ BF_GET (PHY_DSPSS_TIME_CHAIN_INFO__CREATION_IN_PROGRESS,
+ PHY_DSPSS_TIME_CHAIN_INFO));
u32 csma = PHY_PRATIC_CSMA;
char flag[8], *flagp = flag;
if (csma & BF_MASK (PHY_PRATIC_CSMA__FALSE_ALARM))
@@ -292,36 +309,40 @@ phy_fatal_dump (void)
if (csma & BF_MASK (PHY_PRATIC_CSMA__TX_CANCEL_DUE_TO_FALSE_ALARM))
*flagp++ = 'F';
*flagp = '\0';
- fprintf (stderr, "CSMA: cap: %us%um%u%s\n",
- BF_GET (PHY_PRATIC_CSMA__MPDU_CAP, csma),
- BF_GET (PHY_PRATIC_CSMA__SENT_CAP, csma),
- BF_GET (PHY_PRATIC_CSMA__MEDIUM_CAP, csma),
- flag);
- fprintf (stderr, "TMDMA: busy: %d\n",
- BF_GET (PHY_DSPSS_TMD_CTRL__BUSY, PHY_DSPSS_TMD_CTRL));
+ dbg_dump_printf (
+ dump_cb, dump_cb_user, "CSMA: cap: %us%um%u%s\n",
+ BF_GET (PHY_PRATIC_CSMA__MPDU_CAP, csma),
+ BF_GET (PHY_PRATIC_CSMA__SENT_CAP, csma),
+ BF_GET (PHY_PRATIC_CSMA__MEDIUM_CAP, csma),
+ flag);
+ dbg_dump_printf (
+ dump_cb, dump_cb_user, "TMDMA: busy: %d\n",
+ BF_GET (PHY_DSPSS_TMD_CTRL__BUSY, PHY_DSPSS_TMD_CTRL));
u32 pbdma_ctrl = PHY_PBDMA_CTRL_CONFIG;
u32 pbdma_status = PHY_PBDMA_STATUS_ERROR;
- fprintf (stderr, "PBDMA: data: %d chandata: %d pb null: %d index: %d"
- " fsm: %d it: %d end rx: %d end tx: %d end chandata: %d\n",
- BF_GET (PHY_PBDMA_CTRL_CONFIG__START_DATA, pbdma_ctrl),
- BF_GET (PHY_PBDMA_CTRL_CONFIG__START_CHANDATA, pbdma_ctrl),
- BF_GET (PHY_PBDMA_STATUS_ERROR__PB_NULL, pbdma_status),
- BF_GET (PHY_PBDMA_STATUS_ERROR__CURRENT_PB_INDEX, pbdma_status),
- BF_GET (PHY_PBDMA_STATUS_ERROR__FSM_STATE, pbdma_status),
- BF_GET (PHY_PBDMA_STATUS_ERROR__PB_IT, pbdma_status),
- BF_GET (PHY_PBDMA_STATUS_ERROR__END_RX_PB, pbdma_status),
- BF_GET (PHY_PBDMA_STATUS_ERROR__END_TX_PB, pbdma_status),
- BF_GET (PHY_PBDMA_STATUS_ERROR__END_CHANDATA, pbdma_status));
- fprintf (stderr, "PBDMA error: rx_header_load: %d ahb_response: %d"
- " chandata type: %d chandata size: %d\n",
- BF_GET (PHY_PBDMA_STATUS_ERROR__RX_HEADER_LOAD_ERROR,
- pbdma_status),
- BF_GET (PHY_PBDMA_STATUS_ERROR__AHB_RESPONSE_ERROR,
- pbdma_status),
- BF_GET (PHY_PBDMA_STATUS_ERROR__CHANDATA_TYPE_FORBIDDEN,
- pbdma_status),
- BF_GET (PHY_PBDMA_STATUS_ERROR__CHANDATA_SIZE_FORBIDDEN,
- pbdma_status));
+ dbg_dump_printf (
+ dump_cb, dump_cb_user, "PBDMA: data: %d chandata: %d pb null: %d"
+ " index: %d fsm: %d it: %d end rx: %d end tx: %d end chandata: %d\n",
+ BF_GET (PHY_PBDMA_CTRL_CONFIG__START_DATA, pbdma_ctrl),
+ BF_GET (PHY_PBDMA_CTRL_CONFIG__START_CHANDATA, pbdma_ctrl),
+ BF_GET (PHY_PBDMA_STATUS_ERROR__PB_NULL, pbdma_status),
+ BF_GET (PHY_PBDMA_STATUS_ERROR__CURRENT_PB_INDEX, pbdma_status),
+ BF_GET (PHY_PBDMA_STATUS_ERROR__FSM_STATE, pbdma_status),
+ BF_GET (PHY_PBDMA_STATUS_ERROR__PB_IT, pbdma_status),
+ BF_GET (PHY_PBDMA_STATUS_ERROR__END_RX_PB, pbdma_status),
+ BF_GET (PHY_PBDMA_STATUS_ERROR__END_TX_PB, pbdma_status),
+ BF_GET (PHY_PBDMA_STATUS_ERROR__END_CHANDATA, pbdma_status));
+ dbg_dump_printf (
+ dump_cb, dump_cb_user, "PBDMA error: rx_header_load: %d"
+ " ahb_response: %d chandata type: %d chandata size: %d\n",
+ BF_GET (PHY_PBDMA_STATUS_ERROR__RX_HEADER_LOAD_ERROR,
+ pbdma_status),
+ BF_GET (PHY_PBDMA_STATUS_ERROR__AHB_RESPONSE_ERROR,
+ pbdma_status),
+ BF_GET (PHY_PBDMA_STATUS_ERROR__CHANDATA_TYPE_FORBIDDEN,
+ pbdma_status),
+ BF_GET (PHY_PBDMA_STATUS_ERROR__CHANDATA_SIZE_FORBIDDEN,
+ pbdma_status));
}
#endif /* DEBUG */
@@ -397,7 +418,8 @@ phy_init (void *user_data, phy_rx_fc_cb_t rx_fc_cb, phy_access_cb_t access_cb,
ctx->resys_gil_table[PHY_GIL_3534] =
PHY_RESYS_GIL_OFFSET__VALUE_3534;
ctx->pbdma_start_on_resys_it = false;
- dbg_do (dbg_fatal_cb[1] = phy_fatal_dump);
+ dbg_do (dbg_register_fatal_callback (1, phy_fatal));
+ dbg_do (dbg_register_fatal_dump_callback (1, phy_fatal_dump));
/* Attach interrupt. */
cyg_drv_interrupt_create (LEON_ITC2_HIGH_PRIORITY_ITC1_IT,
LEON_ITC2_HIGH_PRIORITY_ITC1_IT_PRIORITY,
@@ -462,7 +484,8 @@ phy_init (void *user_data, phy_rx_fc_cb_t rx_fc_cb, phy_access_cb_t access_cb,
PHY_DSPSS_USED_CARRIERS_EXT10 = PHY_HP10_CARRIER_NB;
PHY_DSPSS_FIRST_CARRIER_EXT10 = PHY_HP10_CARRIER_OFFSET;
/* SPOC. */
- phy_spoc_init (ctx, 0);
+ PHY_DSPSS_SPOC_DEBUG_MODE = BF_FILL (PHY_DSPSS_SPOC_DEBUG_MODE,
+ (BYPASS, 1));
/* MIA. */
PHY_DSPSS_MIA_PARAM = PHY_PARAMS (PHY_DSPSS, MIA_PARAM, USE_SNR_IN_LLR);
PHY_DSPSS_MIA_SF_BPSK = PHY_PARAM_MIA_SF_BPSK;
@@ -607,7 +630,7 @@ phy_set_robo_param (phy_t *ctx, u32 *tonemask, uint carrier_nb)
}
static void
-phy_set_tunable_param (phy_t *ctx)
+phy_set_tunable_param (phy_t *ctx, const u32 *tonemask, uint carrier_nb)
{
uint i;
for (i = 0; i < COUNT (phy_tunable.mafadese_coef_filter_band0); i++)
@@ -616,7 +639,8 @@ phy_set_tunable_param (phy_t *ctx)
for (i = 0; i < COUNT (phy_tunable.mafadese_coef_filter_band1); i++)
PHY_DSPSS_MAFADESE_COEF_FILTER_BAND_1_n[i] =
phy_tunable.mafadese_coef_filter_band1[i];
- phy_spoc_init (ctx, phy_tunable.spoc_rho_initial_q30);
+ phy_spoc_init (ctx, phy_tunable.spoc_rho_initial_q30, tonemask,
+ carrier_nb);
}
static void
@@ -703,7 +727,7 @@ phy_set_tonemask (phy_t *ctx, u32 *tonemask, uint carrier_nb)
PHY_DSPSS_HP10_FC_MASK_1 = 0x000E0000;
PHY_DSPSS_HP10_FC_MASK_2 = 0xFFF00060;
/* Set tunable parameters. */
- phy_set_tunable_param (ctx);
+ phy_set_tunable_param (ctx, tonemask, carrier_nb);
/* Set ROBO parameters. */
phy_set_robo_param (ctx, tonemask, carrier_nb);
/* Create preamble and PRS. */
diff --git a/cesar/hal/phy/src/phy_params.pl b/cesar/hal/phy/src/phy_params.pl
index 44999bb14e..4070b06045 100644
--- a/cesar/hal/phy/src/phy_params.pl
+++ b/cesar/hal/phy/src/phy_params.pl
@@ -5,6 +5,7 @@ use warnings;
sub process_integer
{
my ($name, $value) = @_;
+ $name =~ s/(RX|TX|WIENER)_SPOC/SPOC/;
return $value =~ /^-/ ? "(BF_ONES (PHY_DSPSS_$name) & $value)" : $value;
}
diff --git a/cesar/hal/phy/test/phy/doc/test_phy.txt b/cesar/hal/phy/test/phy/doc/test_phy.txt
index 2888de4c9f..86b1252c32 100644
--- a/cesar/hal/phy/test/phy/doc/test_phy.txt
+++ b/cesar/hal/phy/test/phy/doc/test_phy.txt
@@ -475,6 +475,8 @@ TestPhy.set_tonemask
This function change the tonemask used by Test Phy.
+WARNING: This will reset SPOC frequency error to default value!
+
Parameters
~~~~~~~~~~
@@ -489,6 +491,8 @@ TestPhy.set_freqerror
This function sets SPOC to handle the given frequency error.
+WARNING: This must be done after tonemask is set!
+
Parameters
~~~~~~~~~~
diff --git a/cesar/hal/phy/test/phy/src/test_phy.c b/cesar/hal/phy/test/phy/src/test_phy.c
index 83571b5802..66481da416 100644
--- a/cesar/hal/phy/test/phy/src/test_phy.c
+++ b/cesar/hal/phy/test/phy/src/test_phy.c
@@ -437,7 +437,8 @@ test_phy_set_freqerror_fcall (fcall_ctx_t *fcall, fcall_param_t **param,
phy_spoc_compute_all (rho_q30, &coeff);
phy_spoc_tx_set (ctx->phy, &coeff);
phy_spoc_rx_set (ctx->phy, &coeff);
- phy_set_tonemask (ctx->phy, ctx->tonemask, ctx->tonemask_carrier_nb);
+ phy_prepare (ctx->phy, PHY_PREPARE_TYPE_PREAMBLE, true);
+ phy_prepare (ctx->phy, PHY_PREPARE_TYPE_PRS, true);
/* Return. */
fcall_param_reset (*param);
return 0;
diff --git a/cesar/lib/dbg.h b/cesar/lib/dbg.h
index e3fa337cb9..cc55b7f5a6 100644
--- a/cesar/lib/dbg.h
+++ b/cesar/lib/dbg.h
@@ -392,6 +392,30 @@ extern char dbg_fatal_text_[];
#endif /* !(DEBUG && CONFIG_DEBUG_FATAL_CATCH) */
+/**
+ * Callback for debug dump.
+ * \param user user parameter
+ * \param text text buffer with text to write
+ * \param text_size size of text to write, i.e. number of characters, or 0
+ * for end of dump
+ * \return should return size, any other value will stop dump
+ */
+typedef int (*dbg_dump_callback_t) (void *user, const char *text,
+ uint text_size);
+
+/**
+ * Callback for fatal error.
+ */
+typedef void (*dbg_fatal_callback_t) (void);
+
+/**
+ * Callback for fatal error dump.
+ * \param dump_cb dump callback
+ * \param dump_cb_user dump callback user parameter
+ */
+typedef void (*dbg_fatal_dump_callback_t) (dbg_dump_callback_t dump_cb,
+ void *dump_cb_user);
+
BEGIN_DECLS
/**
@@ -439,8 +463,6 @@ dbg_assert_perror_fail (const char *assertion, const char *file, uint line,
void
dbg_fatal_blind (void) __attribute__ ((__noreturn__));
-extern void (*dbg_fatal_cb[4]) (void);
-
/**
* Stop the program with a fatal error.
* \param fmt printf-like format string
@@ -458,6 +480,47 @@ void
dbg_vfatal (const char *fmt, va_list ap)
__attribute__ ((__noreturn__));
+/**
+ * Register a new dump callback.
+ * \param callback new dump callback
+ * \param user callback user parameter
+ */
+void
+dbg_register_dump_callback (dbg_dump_callback_t callback, void *user);
+
+/**
+ * Register a callback called on fatal error, before dump.
+ * \param priority define order in which callbacks are called, the lesser,
+ * the sooner
+ * \param callback callback to register
+ */
+void
+dbg_register_fatal_callback (uint priority, dbg_fatal_callback_t callback);
+
+/**
+ * Register a callback called on fatal error dump.
+ * \param priority define order in which callbacks are called, the lesser,
+ * the sooner
+ * \param callback callback to register
+ */
+void
+dbg_register_fatal_dump_callback (uint priority,
+ dbg_fatal_dump_callback_t callback);
+
+/**
+ * Formated output to debug dump.
+ * \param dump_cb dump callback
+ * \param dump_cb_user dump callback user parameter
+ * \param fmt printf-like format string
+ * \return output size
+ *
+ * \warning output size is limited to internal buffer size.
+ */
+int
+dbg_dump_printf (dbg_dump_callback_t dump_cb, void *dump_cb_user,
+ const char *fmt, ...)
+ __attribute__ ((format (printf, 3, 4)));
+
END_DECLS
#endif /* lib_dbg_h */
diff --git a/cesar/lib/src/dbg.c b/cesar/lib/src/dbg.c
index 3b5ae7c8c4..114fffedc4 100644
--- a/cesar/lib/src/dbg.c
+++ b/cesar/lib/src/dbg.c
@@ -13,13 +13,34 @@
#include "common/std.h"
#include "hal/arch/arch.h"
+#include "hal/arch/io.h"
#include "hal/gpio/gpio.h"
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
-void (*dbg_fatal_cb[4]) (void);
+#include "build_info.h"
+
+/** Fatal error callbacks. */
+dbg_fatal_callback_t dbg_fatal_cb[4];
+
+/** Fatal error dump callbacks. */
+dbg_fatal_dump_callback_t dbg_fatal_dump_cb[4];
+
+/** Dump callback. */
+dbg_dump_callback_t dbg_dump_cb;
+
+/** Dump callback user parameter. */
+void *dbg_dump_cb_user;
+
+/** Maximum size of fatal error text. */
+#define DBG_FATAL_TEXT_SIZE 256
+
+/** Version string. */
+#define DBG_VERSION \
+ "project: " BUILD_INFO_PROJECT "\n" \
+ "version: " BUILD_INFO_VERSION "\n"
ARCH_STACK_DECLARE (dbg_stack);
@@ -27,7 +48,7 @@ ARCH_STACK_DECLARE (dbg_stack);
# if CONFIG_DEBUG_FATAL_CATCH
int dbg_fatal_try_level_;
-char dbg_fatal_text_[2048];
+char dbg_fatal_text_[DBG_FATAL_TEXT_SIZE];
# endif
void
@@ -74,10 +95,26 @@ dbg_fatal (const char *fmt, ...)
va_end (ap);
}
+/**
+ * Default dump callback, dump on stderr.
+ * \param user ignored user parameter
+ * \param text text to dump
+ * \param text_size size of text or 0 for end of dump
+ * \return size of dumped text
+ */
+static int
+dbg_default_dump_cb (void *user, const char *text, uint text_size)
+{
+ dbg_assert ((text && text_size) || text_size == 0);
+ arch_io_write (text, text_size);
+ return text_size;
+}
+
static void
dbg_vfatal_internal (const char *fmt, va_list ap)
{
static bool in_fatal = false;
+ uint i;
/* Stop system. */
arch_stop ();
/* Signal on GPIOs. */
@@ -85,36 +122,56 @@ dbg_vfatal_internal (const char *fmt, va_list ap)
GPIO_SET (FATAL, 0);
GPIO_SETUP (FATAL_BLINK, GPIO_DIRECTION_OUT);
GPIO_SET (FATAL_BLINK, 0);
+ /* Call fatal callback. */
+ for (i = 0; i < COUNT (dbg_fatal_cb); i++)
+ if (dbg_fatal_cb[i])
+ dbg_fatal_cb[i] ();
#ifdef __sparc__
/* Amuse the user. */
- fputs (" \\|/ ____ \\|/\n"
- " \"@'/ ,. \\`@\"\n"
- " /_| \\__/ |_\\\n"
- " \\__U_/\n",
- stderr);
+ static const char sparc_sprite[] =
+ " \\|/ ____ \\|/\n"
+ " \"@'/ ,. \\`@\"\n"
+ " /_| \\__/ |_\\\n"
+ " \\__U_/\n";
+ dbg_default_dump_cb (NULL, sparc_sprite, strlen (sparc_sprite));
#endif
+ /* Get dump callback. */
+ dbg_dump_callback_t cb = dbg_dump_cb ? dbg_dump_cb : dbg_default_dump_cb;
/* Complain for bad treatments. */
- vfprintf (stderr, fmt, ap);
- fputc ('\n', stderr);
+ char fatal_text[DBG_FATAL_TEXT_SIZE];
+ uint fatal_text_len;
+ fatal_text_len = vsnprintf (fatal_text, sizeof (fatal_text), fmt, ap);
+ if (cb != dbg_default_dump_cb)
+ {
+ /* Always output on stderr. */
+ dbg_default_dump_cb (NULL, fatal_text, fatal_text_len);
+ dbg_default_dump_cb (NULL, "\n", 1);
+ }
+ cb (dbg_dump_cb_user, fatal_text, fatal_text_len);
+ cb (dbg_dump_cb_user, "\n", 1);
+ /* Dump version. */
+ cb (dbg_dump_cb_user, DBG_VERSION, strlen (DBG_VERSION));
+ /* Call fatal callbacks. */
if (!in_fatal)
{
in_fatal = true;
- uint i;
bool cb_called = false;
- for (i = 0; i < COUNT (dbg_fatal_cb); i++)
- if (dbg_fatal_cb[i])
+ for (i = 0; i < COUNT (dbg_fatal_dump_cb); i++)
+ if (dbg_fatal_dump_cb[i])
{
- dbg_fatal_cb[i] ();
+ dbg_fatal_dump_cb[i] (cb, dbg_dump_cb_user);
cb_called = true;
}
if (cb_called)
{
- fputc ('>', stderr);
- vfprintf (stderr, fmt, ap);
- fputc ('\n', stderr);
+ cb (dbg_dump_cb_user, ">", 1);
+ cb (dbg_dump_cb_user, fatal_text, fatal_text_len);
+ cb (dbg_dump_cb_user, "\n", 1);
}
in_fatal = false;
}
+ /* Signal end of dump. */
+ cb (dbg_dump_cb_user, NULL, 0);
/* Signal on blinking GPIO. */
#if CONFIG_GPIO_FATAL_BLINK
while (1)
@@ -146,3 +203,45 @@ dbg_vfatal (const char *fmt, va_list ap)
}
}
+void
+dbg_register_dump_callback (dbg_dump_callback_t callback, void *user)
+{
+ dbg_assert (callback);
+ dbg_assert (!dbg_dump_cb || dbg_dump_cb == callback);
+ dbg_dump_cb = callback;
+ dbg_dump_cb_user = user;
+}
+
+void
+dbg_register_fatal_callback (uint priority, dbg_fatal_callback_t callback)
+{
+ dbg_assert (callback);
+ dbg_assert (priority < COUNT (dbg_fatal_cb) && !dbg_fatal_cb[priority]);
+ dbg_fatal_cb[priority] = callback;
+}
+
+void
+dbg_register_fatal_dump_callback (uint priority,
+ dbg_fatal_dump_callback_t callback)
+{
+ dbg_assert (callback);
+ dbg_assert (priority < COUNT (dbg_fatal_dump_cb)
+ && !dbg_fatal_dump_cb[priority]);
+ dbg_fatal_dump_cb[priority] = callback;
+}
+
+int
+dbg_dump_printf (dbg_dump_callback_t dump_cb, void *dump_cb_user,
+ const char *fmt, ...)
+{
+ va_list ap;
+ char text[1024];
+ uint text_len;
+ /* Format string. */
+ va_start (ap, fmt);
+ text_len = vsnprintf (text, sizeof (text), fmt, ap);
+ va_end (ap);
+ /* Output to debug dump. */
+ return dump_cb (dump_cb_user, text, text_len);
+}
+
diff --git a/cesar/lib/src/trace.c b/cesar/lib/src/trace.c
index a411e769af..783612d3b8 100644
--- a/cesar/lib/src/trace.c
+++ b/cesar/lib/src/trace.c
@@ -46,14 +46,26 @@ struct trace_t
static trace_t trace_global;
+#if CONFIG_TRACE_ON_FATAL
+
+/**
+ * Called on fatal error.
+ */
+static void
+trace_dbg_fatal_dump_cb (dbg_dump_callback_t dump_cb, void *dump_cb_user)
+{
+ trace_bundle_dump_all ("fatal", dump_cb, dump_cb_user);
+}
+
+#endif /* CONFIG_TRACE_ON_FATAL */
+
void
trace_init (void)
{
trace_t * const ctx = &trace_global;
list_init (&ctx->buffers);
#if CONFIG_TRACE_ON_FATAL
- dbg_assert (!dbg_fatal_cb[2]);
- dbg_fatal_cb[2] = trace_dbg_dump_all;
+ dbg_register_fatal_dump_callback (2, trace_dbg_fatal_dump_cb);
#endif
}
diff --git a/cesar/lib/test/utils/src/test_utils.c b/cesar/lib/test/utils/src/test_utils.c
index f7c9a6402f..8b7beab993 100644
--- a/cesar/lib/test/utils/src/test_utils.c
+++ b/cesar/lib/test/utils/src/test_utils.c
@@ -24,6 +24,13 @@ bits_test_case (test_t t)
test_fail_unless (BITS_ONES (15) == 0x00007fff);
test_fail_unless (BITS_ONES (32) == 0xffffffff);
} test_end;
+ test_begin (t, "mask")
+ {
+ test_fail_unless (BITS_MASK (1, 14) == 0x00004000);
+ test_fail_unless (BITS_MASK (15, 7) == 0x003fff80);
+ test_fail_unless (BITS_MASK (32, 0) == 0xffffffff);
+ test_fail_unless (BITS_MASK (1, 31) == 0x80000000);
+ } test_end;
test_begin (t, "ones count")
{
test_fail_unless (BITS_ONES_COUNT ((u8) 0x00) == 0);
diff --git a/cesar/lib/utils.h b/cesar/lib/utils.h
index dafda4cd06..4d87d90515 100644
--- a/cesar/lib/utils.h
+++ b/cesar/lib/utils.h
@@ -145,13 +145,13 @@ lesseq_mod2p16 (u16 a, u16 b)
#define BF_ONES_(m, l) BITS_ONES ((m) - (l) + 1)
/** Return a bit mask composed of a number of shifted ones.
- * \param b number of one bits, 1 to 31
- * \param s shift, 0 to 30
+ * \param b number of one bits, 1 to 32
+ * \param s shift, 0 to 31
*
* - BITS_MASK (0, 0) => error
* - BITS_MASK (1, 14) => 0x00004000
* - BITS_MASK (15, 7) => 0x003fff80
- * - BITS_MASK (31, 0) => 0xffffffff
+ * - BITS_MASK (32, 0) => 0xffffffff
*/
#define BITS_MASK(b, s) (BITS_ONES (b) << (s))
@@ -245,12 +245,11 @@ lesseq_mod2p16 (u16 a, u16 b)
/** Return the number of one bits. */
#define BITS_ONES_COUNT(x) ({ \
typeof (x) _x = (x); \
- uint i, c = 0; \
- for (i = sizeof (_x) * 8; i; i--) \
+ uint c = 0; \
+ while (_x) \
{ \
- if (_x & 1) \
- c++; \
- _x >>= 1; \
+ _x = _x & (_x - 1); \
+ c++; \
} \
c; \
})