digipeater: improve beacon handling

This commit is contained in:
Thomas Kolb 2024-11-17 17:03:20 +01:00
parent 580e4005ed
commit 1c8e46f54a
3 changed files with 65 additions and 41 deletions

View file

@ -449,8 +449,6 @@ void connection_handle_ack(connection_ctx_t *ctx, uint8_t acked_seq, bool do_ack
break;
}
ctx->next_packet_index = 0;
size_t packets_to_remove = 0;
size_t packets_available = packet_queue_get_used_space(&ctx->packet_queue);
@ -464,13 +462,21 @@ void connection_handle_ack(connection_ctx_t *ctx, uint8_t acked_seq, bool do_ack
packets_to_remove++;
}
packet_queue_delete(&ctx->packet_queue, packets_to_remove);
if(packets_to_remove != 0) {
packet_queue_delete(&ctx->packet_queue, packets_to_remove);
packets_available = packet_queue_get_used_space(&ctx->packet_queue);
// send the next requested packet (all previous ones were deleted above).
assert(ctx->next_packet_index >= packets_to_remove);
ctx->next_packet_index -= packets_to_remove;
LOG(LVL_DEBUG, "handling ack for seq_nr %u, removed %zu packets, %zu packets remaining.", acked_seq, packets_to_remove, packets_available);
packets_available = packet_queue_get_used_space(&ctx->packet_queue);
ctx->retransmit_time = get_hires_time() + HRTIME_MS(RETRANSMIT_TIMEOUT_MS);
LOG(LVL_DEBUG, "handling ack for seq_nr %u, removed %zu packets, %zu packets remaining.", acked_seq, packets_to_remove, packets_available);
ctx->retransmit_time = get_hires_time() + HRTIME_MS(RETRANSMIT_TIMEOUT_MS);
} else {
LOG(LVL_DEBUG, "duplicate ACK for seq_nr %u", acked_seq);
}
if(do_ack && packets_available == 0) {
// no packets left in queue, but an acknowledgement must be

View file

@ -79,6 +79,25 @@ static result_t digipeater_handle_beacon_responses(digipeater_ctx_t *ctx, const
}
static size_t encode_beacon_packet(digipeater_ctx_t *ctx, uint8_t *buf, size_t buf_len)
{
// build a beacon packet
layer2_packet_header_t header;
ham64_t broadcast = {{0xFFFF, 0, 0, 0}, 1};
header.dst_addr = broadcast;
header.src_addr = ctx->my_addr;
header.msg_type = L2_MSG_TYPE_CONN_MGMT;
header.rx_seq_nr = 0; // unused
header.tx_seq_nr = 0; // unused
header.tx_request = 1;
uint8_t payload[1] = {CONN_MGMT_TYPE_BEACON};
return layer2_encode_packet(&header, payload, 1, buf, buf_len);
}
result_t digipeater_init(digipeater_ctx_t *ctx, const ham64_t *my_addr, digipeater_data_callback_t data_cb)
{
ctx->my_addr = *my_addr;
@ -239,31 +258,11 @@ result_t digipeater_fill_packet_queues_from_tundev(digipeater_ctx_t *ctx, int tu
size_t digipeater_encode_next_packet(digipeater_ctx_t *ctx, uint8_t *buf, size_t buf_len, bool *end_burst)
{
uint64_t now = get_hires_time();
size_t packet_size = 0;
*end_burst = false;
if(now > ctx->next_beacon_time) {
// build a beacon packet
layer2_packet_header_t header;
ham64_t broadcast = {{0xFFFF, 0, 0, 0}, 1};
header.dst_addr = broadcast;
header.src_addr = ctx->my_addr;
header.msg_type = L2_MSG_TYPE_CONN_MGMT;
header.rx_seq_nr = 0; // unused
header.tx_seq_nr = 0; // unused
header.tx_request = 1;
uint8_t payload[1] = {CONN_MGMT_TYPE_BEACON};
packet_size = layer2_encode_packet(&header, payload, 1, buf, buf_len);
ctx->state = DIGIPEATER_STATE_BEACON;
*end_burst = true;
return packet_size;
}
// send packets from the one-shot queue
const packet_queue_entry_t *queue_entry = packet_queue_get(&ctx->oneshot_queue, 0);
if(queue_entry) {
@ -275,18 +274,27 @@ size_t digipeater_encode_next_packet(digipeater_ctx_t *ctx, uint8_t *buf, size_t
}
}
// pull packets from the current connection
switch(ctx->state) {
case DIGIPEATER_STATE_BEACON:
packet_size = encode_beacon_packet(ctx, buf, buf_len);
*end_burst = true;
break;
connection_list_entry_t *head = connection_list_get_head(&ctx->conn_list);
if(!head) {
return 0;
}
case DIGIPEATER_STATE_CONN: {
// pull packets from the current connection
connection_list_entry_t *head = connection_list_get_head(&ctx->conn_list);
if(!head) {
return 0;
}
connection_ctx_t *conn = &head->connection;
if(connection_can_transmit(conn)) {
packet_size = connection_encode_next_packet(conn, buf, buf_len, end_burst);
connection_ctx_t *conn = &head->connection;
if(connection_can_transmit(conn)) {
packet_size = connection_encode_next_packet(conn, buf, buf_len, end_burst);
ctx->state = DIGIPEATER_STATE_CONN;
ctx->state = DIGIPEATER_STATE_CONN;
}
}
break;
}
return packet_size;
@ -301,6 +309,10 @@ bool digipeater_can_transmit(digipeater_ctx_t *ctx)
return true;
}
if(packet_queue_get_used_space(&ctx->oneshot_queue) != 0) {
return true;
}
connection_list_entry_t *head = connection_list_get_head(&ctx->conn_list);
if(head) {
return connection_can_transmit(&head->connection);
@ -320,12 +332,17 @@ result_t digipeater_end_interval(digipeater_ctx_t *ctx)
{
uint64_t now = get_hires_time();
// TODO: adjust the time based on connection activity; right now this results
// in round-robin scheduling
connection_list_reschedule_head(&ctx->conn_list, now + HRTIME_MS(MIN_INTERVAL_TIME_MS));
if(now >= ctx->next_beacon_time) {
ctx->next_beacon_time += HRTIME_MS(BEACON_INTERVAL_MS);
ctx->state = DIGIPEATER_STATE_BEACON;
} else {
// TODO: adjust the time based on connection activity; right now this results
// in round-robin scheduling
connection_list_reschedule_head(&ctx->conn_list, now + HRTIME_MS(MIN_INTERVAL_TIME_MS));
ctx->state = DIGIPEATER_STATE_CONN;
ctx->interval_end_time = now + HRTIME_MS(MIN_INTERVAL_TIME_MS);
ctx->state = DIGIPEATER_STATE_CONN;
ctx->interval_end_time = now + HRTIME_MS(MIN_INTERVAL_TIME_MS);
}
return OK;
}

View file

@ -23,6 +23,7 @@ typedef enum {
} digipeater_state_t;
typedef enum {
// FIXME: rename to Cycle
DIGIPEATER_EVT_INTERVAL_END, //!< The current interval has ended and new packets should be transmitted.
} digipeater_evt_t;