Commit b38c672c authored by Reto Da Forno's avatar Reto Da Forno
Browse files

gloria cleanup and rx callback added

parent 3807038d
......@@ -63,7 +63,7 @@ void gloria_run_flood(gloria_flood_t* flood, void (*callback)())
current_flood->msg_received = current_flood->initial;
current_flood->last_active_slot = gloria_calculate_last_active_slot(current_flood);
current_flood->remaining_retransmissions = current_flood->max_retransmissions;
current_flood->rem_retransmissions = current_flood->max_retransmissions;
current_flood->ack_message.protocol_id = PROTOCOL_ID_GLORIA;
current_flood->ack_message.type = 0;
......@@ -182,7 +182,7 @@ static void gloria_rx_callback(uint8_t* payload, uint8_t size)
gloria_finish_slot();
}
else if (size == GLORIA_ACK_LENGTH) {
gloria_ack_message_t* ack_message = (gloria_ack_message_t*) payload;
gloria_ack_msg_t* ack_message = (gloria_ack_msg_t*) payload;
if (ack_message->dst) {
current_flood->acked = true;
current_flood->ack_message.dst = ack_message->dst;
......@@ -232,10 +232,14 @@ static void gloria_process_rx(uint8_t* payload, uint8_t size)
}
current_flood->first_rx_index = current_flood->header.slot_index;
current_flood->last_active_slot = gloria_calculate_last_active_slot(current_flood);
// set guard time to 0 as node is now synced to this flood
current_flood->guard_time = 0;
// user-defined RX callback (NOTE: execution time must be short / in the microsecond range, otherwise the Gloria slotOverhead must be adjusted)
if (current_flood->rx_cb) {
current_flood->rx_cb();
}
current_flood->last_active_slot = gloria_calculate_last_active_slot(current_flood); // must be after rx callback
current_flood->guard_time = 0; // set guard time to 0 as node is now synced to this flood
// check if node is also the destination
if (current_flood->ack_mode && (header->dst == current_flood->node_id)) {
......
......@@ -103,11 +103,7 @@ inline bool gloria_is_not_finished(gloria_flood_t* flood) {
* flood was not acked
*/
inline bool gloria_valid_to_send(gloria_flood_t* flood) {
if (
flood->msg_received
&& flood->remaining_retransmissions
&& !flood->acked
) {
if (flood->msg_received && flood->rem_retransmissions && !flood->acked) {
return true;
}
else {
......@@ -117,7 +113,7 @@ inline bool gloria_valid_to_send(gloria_flood_t* flood) {
inline bool gloria_is_ack_slot(gloria_flood_t* flood) {
return (flood->ack_mode && flood->header.slot_index % 2);
return (flood->ack_mode && (flood->header.slot_index % 2));
}
......
......@@ -39,33 +39,29 @@
/* internal state */
static gloria_flood_t flood; // flood struct which (serves as input, state, and output to/from gloria_run_flood)
static uint8_t gloria_payload[GLORIA_INTERFACE_MAX_PAYLOAD_LEN]; // buffer for the message
static bool flood_running; // indicates whether flood is onging or not
static bool flood_completed; // indicates whether the flood completed (N_TX reached)
static uint8_t lastrun_n_rx_started = 0; // number of rx started events during the last Gloria run
static bool lastrun_t_ref_updated = false; // indicates whether last_t_ref has been updated during the last flood
static uint64_t last_t_ref = 0; // reference time (updated if gloria_start is called with sync_slot=true)
static int8_t internal_power = GLORIA_INTERFACE_POWER; // internal state for power (can be adapted from the upper layer)
static uint8_t internal_modulation = GLORIA_INTERFACE_MODULATION; // internal state for the radio modulation (can be adapted from the upper layer)
static uint8_t internal_band = GLORIA_INTERFACE_RF_BAND; // internal state for the frequency band (can be adapted from the upper layer)
static bool internal_enable_flood_printing = false; // enable printing of finished (i.e. completely received/transmitted) floods
static gloria_flood_cb_t flood_cb = 0; // user-defined callback; only called if flood participation terminates before gloria_stop() is called
static gloria_pkt_filter_cb_t pkt_filter_cb = 0; // a user-defined packet filter callback function
static uint64_t tx_start_timestamp = 0; // an optional user-defined TX start marker
static uint8_t tx_delay_slots = 0; // TX delay after reception, in number of slots
static gloria_flood_t flood; // flood struct which (serves as input, state, and output to/from gloria_run_flood)
static uint8_t gloria_payload[GLORIA_INTERFACE_MAX_PAYLOAD_LEN]; // buffer for the message
static bool flood_running; // indicates whether flood is onging or not
static bool flood_completed; // indicates whether the flood completed (N_TX reached)
static uint8_t lastrun_n_rx_started; // number of rx started events during the last Gloria run
static bool lastrun_t_ref_updated; // indicates whether last_t_ref has been updated during the last flood
static uint64_t last_t_ref = 0; // reference time (updated if gloria_start is called with sync_slot=true)
static int8_t internal_power = GLORIA_INTERFACE_POWER; // internal state for power (can be adapted from the upper layer)
static uint8_t internal_modulation = GLORIA_INTERFACE_MODULATION; // internal state for the radio modulation (can be adapted from the upper layer)
static uint8_t internal_band = GLORIA_INTERFACE_RF_BAND; // internal state for the frequency band (can be adapted from the upper layer)
static bool internal_enable_flood_printing = false; // enable printing of finished (i.e. completely received/transmitted) floods
static uint64_t tx_start_timestamp = 0; // an optional user-defined TX start marker
#if GLORIA_INTERFACE_APPEND_TIMESTAMP
static uint8_t last_timestamp[GLORIA_TIMESTAMP_LENGTH]; // last received 64-bit hstimer timestamp
static uint8_t last_timestamp[GLORIA_TIMESTAMP_LENGTH]; // last received 64-bit hstimer timestamp
#endif /* GLORIA_INTERFACE_APPEND_TIMESTAMP */
/* variables to store gloria_start arguments */
static uint16_t arg_is_initiator = 0; // ID of the inititator
static uint8_t* arg_payload_ptr = NULL; // pointer to payload of currently ongoing flood
static bool arg_sync_slot; // holds state whether current flood is used to update last_t_ref or not
static uint8_t* arg_payload_ptr = NULL; // pointer to payload of currently ongoing flood
static bool arg_sync_slot; // holds state whether current flood is used to update last_t_ref or not
/* Private Function Prototypes */
static void gloria_flood_callback(void);
static void flood_callback(void);
static void copy_payload(void);
static void update_t_ref(void);
......@@ -104,10 +100,8 @@ void gloria_start(bool is_initiator,
GLORIA_START_IND();
/* store arguments for further use */
arg_is_initiator = is_initiator;
arg_payload_ptr = payload;
// arg_payload_len: stored during argument check
arg_sync_slot = sync_slot;
arg_payload_ptr = payload;
arg_sync_slot = sync_slot;
/* initialize internal state */
flood_running = true; // keep ordering: first internal state variable to update here
......@@ -116,51 +110,70 @@ void gloria_start(bool is_initiator,
lastrun_t_ref_updated = false;
// last_t_ref: not initialized here since old values of previous floods are still valid and useful if current flood does not update the value
/* prepare flood struct */
memset(&flood, 0, sizeof(gloria_flood_t)); // reset struct
flood.marker = 0;
flood.modulation = internal_modulation;
flood.power = internal_power;
flood.band = internal_band;
flood.flood_idx = 0;
flood.max_retransmissions = n_tx_max;
flood.ack_mode = 0;
flood.max_acks = 0;
flood.data_slots = GLORIA_INTERFACE_MAX_SLOTS;
flood.sync_timer = 0; // do not automatically adjust the hs timer offset
flood.lp_listening = false;
flood.radio_no_sleep = true;
flood.node_id = 0; // unused
flood.tx_delay_slots = tx_delay_slots;
flood.pkt_filter = pkt_filter_cb;
flood.header.type = 0;
flood.header.sync = (GLORIA_INTERFACE_APPEND_TIMESTAMP != 0); // no sync flood (i.e. timestamp for absolute sync to initiator is not included in to payload)
flood.header.slot_index = 0;
// flood.reconstructed_marker: initialization not necessary -> initialized in gloria_run_flood()
flood.ack_mode = 0;
flood.band = internal_band;
flood.data_slots = GLORIA_INTERFACE_MAX_SLOTS;
flood.guard_time = 0;
flood.header.protocol_id = PROTOCOL_ID_GLORIA;
flood.header.type = 0;
flood.header.sync = (GLORIA_INTERFACE_APPEND_TIMESTAMP != 0); // no sync flood (i.e. timestamp for absolute sync to initiator is not included in to payload)
flood.header.slot_index = 0;
flood.initial = is_initiator;
flood.lp_listening = false;
flood.max_retransmissions = n_tx_max;
flood.modulation = internal_modulation;
flood.payload = gloria_payload;
flood.payload_size = 0;
flood.power = internal_power;
flood.radio_no_sleep = true;
flood.rem_retransmissions = n_tx_max;
flood.rssi = 0;
flood.rx_timeout = 0;
flood.snr = 0;
flood.sync_timer = false; // do not automatically adjust the hs timer offset
// unused fields or internal state of Gloria (initialized in gloria_run_flood)
flood.acked = false;
flood.ack_counter = 0;
flood.crc_error = false;
flood.crc_timeout = false;
flood.current_tx_marker = 0;
flood.first_rx_index = 0;
flood.flood_idx = 0;
flood.header_size = 0;
flood.header.src = 0;
flood.header.dst = 0;
flood.last_active_slot = 0;
flood.max_acks = 0;
flood.msg_received = false;
flood.node_id = 0;
flood.received_marker = 0;
flood.reconstructed_marker = 0;
flood.stop = false;
memset(&flood.ack_message, 0, sizeof(gloria_ack_msg_t));
// don't change the following fields (they are reset in gloria_stop and can be modified by the user prior to the call to gloria_start)
//flood.flood_cb = NULL;
//flood.filter_cb = NULL;
//flood.rx_cb = NULL;
//flood.tx_delay_slots = 0;
if (is_initiator) {
// send flood
// set the TX marker (timestamp when flood shall start) must be set on the initiator
if (tx_start_timestamp && (tx_start_timestamp > hs_timer_get_current_timestamp())) {
// user-defined start time
flood.marker = tx_start_timestamp;
flood.marker = tx_start_timestamp;
} else {
// use current timestamp
flood.marker = ((hs_timer_get_current_timestamp() + (GLORIA_SCHEDULE_GRANULARITY - 1))) / GLORIA_SCHEDULE_GRANULARITY * GLORIA_SCHEDULE_GRANULARITY;
flood.marker = ((hs_timer_get_current_timestamp() + (GLORIA_SCHEDULE_GRANULARITY - 1))) / GLORIA_SCHEDULE_GRANULARITY * GLORIA_SCHEDULE_GRANULARITY;
}
flood.initial = true; // this node is the initator
flood.payload = gloria_payload;
flood.payload_size = payload_len;
flood.payload_size = payload_len;
memcpy(gloria_payload, payload, payload_len);
}
else {
// receive flood
flood.payload = gloria_payload;
flood.marker = 0;
flood.rx_timeout = 0;
flood.guard_time = 0;
flood.initial = false;
flood.marker = 0;
// clear the receive buffer
memset(payload, 0, GLORIA_INTERFACE_MAX_PAYLOAD_LEN);
}
......@@ -174,7 +187,7 @@ void gloria_start(bool is_initiator,
SUSPEND_SYSTICK();
#endif /* GLORIA_INTERFACE_DISABLE_INTERRUPTS */
gloria_run_flood(&flood, &gloria_flood_callback);
gloria_run_flood(&flood, &flood_callback);
}
......@@ -183,7 +196,7 @@ uint8_t gloria_stop(void)
// only stop if flood is not terminated yet
if (flood_running) {
if (!flood_completed && arg_is_initiator) {
if (!flood_completed && flood.initial) {
// If this node is initiator, we can detect if flood did not terminate and warn the user
LOG_WARNING("Stopping glossy while flood sending is still ongoing!");
}
......@@ -239,13 +252,14 @@ uint8_t gloria_stop(void)
}
/* clear arg variables */
arg_is_initiator = false;
arg_payload_ptr = NULL;
arg_sync_slot = false;
flood_cb = NULL;
pkt_filter_cb = NULL;
tx_delay_slots = 0;
tx_start_timestamp = 0;
arg_payload_ptr = NULL;
arg_sync_slot = false;
tx_start_timestamp = 0;
flood.flood_cb = NULL;
flood.filter_cb = NULL;
flood.rx_cb = NULL;
flood.tx_delay_slots = 0;
#if GLORIA_INTERFACE_DISABLE_INTERRUPTS
HAL_NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn);
......@@ -253,9 +267,9 @@ uint8_t gloria_stop(void)
RESUME_SYSTICK();
#endif /* GLORIA_INTERFACE_DISABLE_INTERRUPTS */
GLORIA_STOP_IND();
flood_running = false; // keep ordering: last internal state variable updated here
GLORIA_STOP_IND();
}
return flood.msg_received;
......@@ -375,15 +389,21 @@ void gloria_enable_flood_printing(bool enable)
}
void gloria_register_flood_callback(gloria_flood_cb_t cb)
void gloria_register_flood_callback(gloria_flood_cb_t flood_cb)
{
flood_cb = cb;
flood.flood_cb = flood_cb;
}
void gloria_set_pkt_filter(gloria_pkt_filter_cb_t filter_cb)
void gloria_set_pkt_filter(gloria_filter_cb_t filter_cb)
{
pkt_filter_cb = filter_cb;
flood.filter_cb = filter_cb;
}
void gloria_register_rx_callback(gloria_rx_cb_t rx_cb)
{
flood.rx_cb = rx_cb;
}
......@@ -395,7 +415,7 @@ void gloria_set_tx_marker(uint64_t timestamp_hs)
void gloria_set_tx_delay(uint8_t delay_slots)
{
tx_delay_slots = delay_slots;
flood.tx_delay_slots = delay_slots;
}
......@@ -414,9 +434,9 @@ void gloria_get_received_timestamp(uint8_t* out_timestamp)
/* PRIVATE FUNCTIONS **********************************************************/
static void gloria_flood_callback(void)
static void flood_callback(void)
{
gloria_flood_cb_t cb = flood_cb;
gloria_flood_cb_t cb = flood.flood_cb;
// flood completed
flood_completed = true;
......@@ -448,6 +468,7 @@ static void copy_payload(void)
}
}
/*
* Updates the last_t_ref and lastrun_t_ref_updated based on the flood.reconstructed_marker
*/
......
......@@ -306,7 +306,7 @@ void gloria_enable_flood_printing(bool enable);
* flood stops before gloria_stop() is called!
* \param cb: callback function
*/
void gloria_register_flood_callback(gloria_flood_cb_t cb);
void gloria_register_flood_callback(gloria_flood_cb_t flood_cb);
/**
* \brief Set a custom RX packet filter
......@@ -319,7 +319,16 @@ void gloria_register_flood_callback(gloria_flood_cb_t cb);
* execution times may disrupt the Gloria timing.
* \note The callback function will be cleared in gloria_stop().
*/
void gloria_set_pkt_filter(gloria_pkt_filter_cb_t filter_cb);
void gloria_set_pkt_filter(gloria_filter_cb_t filter_cb);
/**
* \brief Register a function that is called upon reception of a packet.
* \param Pointer to a callback function
* \note The callback function must be short. If the execution time is
* larger than a few microseconds, the Gloria slotOverhead must
* be adjusted.
*/
void gloria_register_rx_callback(gloria_rx_cb_t rx_cb);
/**
* \brief Set the transmission start time (TX marker) for the initiator.
......
......@@ -257,7 +257,7 @@ static void gloria_radio_setup_callback() {
}
static void gloria_radio_tx_callback() {
current_flood->remaining_retransmissions -= 1;
current_flood->rem_retransmissions--;
callback();
}
......@@ -283,7 +283,7 @@ static void gloria_radio_rx_callback(uint8_t* payload, uint16_t size, int16_t r
}
// check packet type and apply user-defined packet filter
else if ((current_flood->header.protocol_id != PROTOCOL_ID_GLORIA) ||
(current_flood->pkt_filter && (size > current_flood->header_size) && !current_flood->pkt_filter(payload + current_flood->header_size, size - current_flood->header_size))) {
(current_flood->filter_cb && (size > current_flood->header_size) && !current_flood->filter_cb(payload + current_flood->header_size, size - current_flood->header_size))) {
gloria_radio_continue_rx();
}
else {
......
......@@ -33,14 +33,15 @@
typedef void (* gloria_flood_cb_t)(void);
typedef bool (* gloria_pkt_filter_cb_t)(uint8_t*, uint8_t);
typedef bool (* gloria_filter_cb_t)(uint8_t*, uint8_t);
typedef bool (* gloria_rx_cb_t)(void);
typedef struct __attribute__((__packed__, __aligned__(1))) {
uint8_t protocol_id : 4; // protocol ID
uint8_t type : 3; // msg type
uint8_t sync: 1; // 1: message includes ts for sync, 0: no ts
uint8_t dst;
} gloria_ack_message_t;
} gloria_ack_msg_t;
typedef struct __attribute__((__packed__, __aligned__(1))) {
uint8_t protocol_id : 4; // protocol ID
......@@ -53,63 +54,57 @@ typedef struct __attribute__((__packed__, __aligned__(1))) {
typedef struct {
// parameters to specify before flood start
gloria_flood_cb_t callback; // callback function after flood finished
gloria_header_t header; // header of the gloria message
gloria_flood_cb_t flood_cb; // callback function after flood finished
gloria_rx_cb_t rx_cb; // user-defined RX callback function (NOTE: execution time must be short / in the microsecond range, otherwise the Gloria slotOverhead must be adjusted)
gloria_filter_cb_t filter_cb; // user-defined RX packet filter
gloria_header_t header; // header of the gloria message
gloria_ack_msg_t ack_message; // contains the ack_message to send / that was received
void* payload; // pointer to the payload to send
uint64_t marker; // set flood start timestamp; has to be a multiple of GLORIA_SCHEDULE_GRANULARITY for the initiator;
// can be set to determine start of rx;
uint64_t marker; // set flood start timestamp; has to be a multiple of GLORIA_SCHEDULE_GRANULARITY for the initiator; can be set to determine start of rx
uint64_t received_marker; // flood marker that was received during the flood; equal to marker for the initiator
uint64_t reconstructed_marker; // reconstructed marker from a message receive; equal to marker for the initiator
uint64_t current_tx_marker; // save ts of current transmission
uint32_t rx_timeout; // specific time (in hs_timer_ticks) to listen before returning if no flood was received
uint8_t band; // radio_band_t selection as defined in radio_constants.h [0-51]
uint8_t modulation; // radio_config_t selection as defined in radio_constants.h [0-9]
int8_t power; // power for this flood
uint8_t payload_size; // size of the raw payload (without header or timestamp)
// max payload = 255 - GLORIA_HEADER_LENGTH (- GLORIA_TIMESTAMP_LENGTH (if sync flood))
uint32_t guard_time; // guard time in hs timer ticks is the time that the nodes starts to listen earlier and ends later
uint16_t flood_idx; // allows to assign the flood an id
uint16_t node_id;
uint8_t header_size; // size of the message header (GLORIA_HEADER_LENGTH or GLORIA_HEADER_LENGTH_MIN)
uint8_t payload_size; // size of the raw payload (without header or timestamp); max payload = 255 - GLORIA_HEADER_LENGTH (- GLORIA_TIMESTAMP_LENGTH (if sync flood))
uint8_t data_slots; // max number of data slots for this flood; for ack floods this is also the number of ack slots
uint8_t last_active_slot; // last slot the node should send / receive (different for nodes)
uint8_t rem_retransmissions; // remaining retransmissions for this node
uint8_t max_retransmissions; // max number of retransmissions for this flood
uint8_t tx_delay_slots; // TX delay after a reception, in number of slots (default: 0)
uint8_t max_acks; // max number of acks to send
uint8_t ack_mode; // 2: initiator waits for ack, 1: send ack to save energy, 0: no ack requested
uint8_t ack_counter; // number of acks sent
uint8_t band; // radio_band_t selection as defined in radio_constants.h [0-51]
uint8_t modulation; // radio_config_t selection as defined in radio_constants.h [0-9]
int8_t power; // power for this flood
int8_t first_rx_index; // used to save slot number of first receive
int8_t snr; // save snr of received data msg
int8_t rssi; // save rssi of received data msg
bool initial; // 1: initiator of the flood
bool sync_timer; // specify if gloria should adapt the timer offset to sync to the initiator clock
bool lp_listening; // don't listen continuously but only for a short time each slot until a message is received
uint32_t guard_time; // guard time in hs timer ticks is the time that the nodes starts to listen earlier and ends later
gloria_pkt_filter_cb_t pkt_filter; // user-defined RX packet filter
// parameters used during flood run
bool msg_received; // true: successfully received a message; false: no message received; set to 1 at flood start for the initiator
bool acked; // true: flood ack msg received
uint8_t remaining_retransmissions; // remaining retransmissions for this node
uint8_t ack_counter; // number of acks sent
int8_t first_rx_index; // used to save slot number of first receive
uint8_t last_active_slot; // last slot the node should send / receive (different for nodes)
uint64_t received_marker; // flood marker that was received during the flood; equal to marker for the initiator
uint64_t reconstructed_marker; // reconstructed marker from a message receive; equal to marker for the initiator
uint64_t current_tx_marker; // save ts of current transmission
uint8_t header_size; // size of the message header (GLORIA_HEADER_LENGTH or GLORIA_HEADER_LENGTH_MIN)
gloria_ack_message_t ack_message; // contains the ack_message to send / that was received
// parameters that contain additional information
bool crc_error; // true: crc_error occurred during flood (msg was received but the crc failed)
bool crc_timeout; // true: crc_timeout occurred during flood (a header_error interrupt occurred)
int8_t snr; // save snr of received data msg
int8_t rssi; // save rssi of received data msg
uint16_t flood_idx; // allows to assign the flood an id
bool radio_no_sleep; // true: don't put radio into sleep mode even if tx marker is far in the future
bool stop; // if set to true, the flood will be stopped at the end of the current slot
uint16_t node_id;
uint8_t tx_delay_slots; // TX delay after a reception, in number of slots (default: 0)
} gloria_flood_t;
_Static_assert(sizeof(gloria_ack_message_t) == GLORIA_ACK_LENGTH, "gloria_ack_message_t is not GLORIA_ACK_LENGTH bytes in size!");
_Static_assert(sizeof(gloria_ack_msg_t) == GLORIA_ACK_LENGTH, "gloria_ack_msg_t is not GLORIA_ACK_LENGTH bytes in size!");
_Static_assert(sizeof(gloria_header_t) == GLORIA_HEADER_LENGTH, "gloria_header_t is not GLORIA_HEADER_LENGTH bytes in size!");
#endif /* PROTOCOL_GLORIA_GLORIA_STRUCTURES_H_ */
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment