mirror of
https://github.com/servalproject/serval-dna.git
synced 2024-12-19 05:07:56 +00:00
Add network coding stats to html output
This commit is contained in:
parent
c1e90a7bce
commit
37e480c623
@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdarg.h>
|
||||
#include "strbuf.h"
|
||||
#include "network_coding.h"
|
||||
#include "dataformats.h"
|
||||
#include "log.h"
|
||||
@ -55,7 +56,11 @@ struct nc_half {
|
||||
// At the receiver, this should be 2*maximum window size to allow for older packets we can't decode yet
|
||||
uint8_t max_queue_size;
|
||||
uint8_t queue_size; // # of packets currently in the array
|
||||
int count_new; // number of un-sent degrees of freedom
|
||||
uint8_t count_new; // number of un-sent degrees of freedom
|
||||
|
||||
uint32_t packet_count; // total number of packets sent / received
|
||||
uint32_t uninteresting_count; // number of redundant packets received
|
||||
uint32_t ack_count; // number of received acks with no data payload
|
||||
};
|
||||
|
||||
struct nc{
|
||||
@ -63,6 +68,8 @@ struct nc{
|
||||
struct nc_half rx;
|
||||
};
|
||||
|
||||
static int _nc_dump_half(struct nc_half *n);
|
||||
|
||||
static void _nc_free_half(struct nc_half *n)
|
||||
{
|
||||
int i;
|
||||
@ -240,9 +247,18 @@ static int _nc_tx_combine_random_payloads(struct nc_half *n, struct nc_packet *p
|
||||
|
||||
int nc_tx_packet_urgency(struct nc *n)
|
||||
{
|
||||
// new data? send asap
|
||||
if (n->tx.count_new)
|
||||
return URGENCY_ASAP;
|
||||
// new data inside the tx window size? send asap
|
||||
if (n->tx.count_new){
|
||||
int i;
|
||||
for(i=0;i<n->tx.window_size;i++) {
|
||||
int index = (n->tx.window_start + i) & (n->tx.max_queue_size -1);
|
||||
// assume we might have gaps in the payload list if we are a retransmitter in the network path
|
||||
if (!n->tx.packets[index].payload)
|
||||
continue;
|
||||
if (n->tx.packets[index].flags & FLAG_NEW)
|
||||
return URGENCY_ASAP;
|
||||
}
|
||||
}
|
||||
// ack required? send soon
|
||||
if (n->rx.unseen != n->rx.last_ack)
|
||||
return URGENCY_ASAP;
|
||||
@ -259,8 +275,8 @@ int nc_tx_produce_packet(struct nc *n, uint8_t *datagram, uint32_t buffer_size)
|
||||
// TODO: Don't waste more bytes than we need to on the bitmap and sequence number
|
||||
if (buffer_size < n->tx.datagram_size+NC_HEADER_LEN)
|
||||
return -1;
|
||||
|
||||
uint8_t window_size = 32 - (n->rx.unseen - n->rx.deliver_next);
|
||||
|
||||
uint8_t window_size = n->rx.max_queue_size - (n->rx.unseen - n->rx.deliver_next);
|
||||
if (window_size > n->rx.max_queue_size)
|
||||
window_size = n->rx.max_queue_size;
|
||||
|
||||
@ -269,7 +285,7 @@ int nc_tx_produce_packet(struct nc *n, uint8_t *datagram, uint32_t buffer_size)
|
||||
n->rx.last_ack = n->rx.unseen;
|
||||
size_t len=2;
|
||||
|
||||
if (n->tx.queue_size){
|
||||
if (n->tx.queue_size && n->tx.window_size){
|
||||
// Produce linear combination
|
||||
struct nc_packet packet={
|
||||
.sequence = n->tx.window_start,
|
||||
@ -282,17 +298,27 @@ int nc_tx_produce_packet(struct nc *n, uint8_t *datagram, uint32_t buffer_size)
|
||||
if (_nc_tx_combine_random_payloads(&n->tx, &packet))
|
||||
return -1;
|
||||
// TODO assert actual_combination? (should never be zero)
|
||||
// Write out bitmap of actual combinations involved
|
||||
datagram[2] = packet.sequence;
|
||||
// Write out bitmap of actual combinations involved
|
||||
write_uint32(&datagram[3], packet.combination);
|
||||
len = packet.len + NC_HEADER_LEN;
|
||||
// truncate zero bytes from the end
|
||||
while(!datagram[len-1])
|
||||
len--;
|
||||
}
|
||||
|
||||
}else
|
||||
n->tx.ack_count++;
|
||||
|
||||
n->tx.packet_count++;
|
||||
return len;
|
||||
}
|
||||
|
||||
void nc_state_html(struct strbuf *b, struct nc *n)
|
||||
{
|
||||
strbuf_sprintf(b, "NC TX: %d (acks %d)<br>", n->tx.packet_count, n->tx.ack_count);
|
||||
strbuf_sprintf(b, "NC RX: %d (unint %d, acks %d)<br>", n->rx.packet_count, n->rx.uninteresting_count, n->rx.ack_count);
|
||||
}
|
||||
|
||||
static int _nc_dump_half(struct nc_half *n)
|
||||
{
|
||||
DEBUGF(" window start; %d", n->window_start);
|
||||
@ -302,6 +328,13 @@ static int _nc_dump_half(struct nc_half *n)
|
||||
DEBUGF(" queue size; %d", n->queue_size);
|
||||
DEBUGF(" max queue size; %d", n->max_queue_size);
|
||||
DEBUGF(" delivered; %d", n->deliver_next);
|
||||
if (n->packet_count)
|
||||
DEBUGF(" packets; %d", n->packet_count);
|
||||
if (n->uninteresting_count)
|
||||
DEBUGF(" uninteresting; %d", n->uninteresting_count);
|
||||
if (n->ack_count)
|
||||
DEBUGF(" acks; %d", n->ack_count);
|
||||
|
||||
int i;
|
||||
for (i=0;i<n->max_queue_size;i++){
|
||||
if (!n->packets[i].payload)
|
||||
@ -313,6 +346,14 @@ static int _nc_dump_half(struct nc_half *n)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nc_dump(struct nc *n)
|
||||
{
|
||||
DEBUGF("Network coding state");
|
||||
DEBUGF("TX");
|
||||
_nc_dump_half(&n->tx);
|
||||
DEBUGF("RX");
|
||||
_nc_dump_half(&n->rx);
|
||||
}
|
||||
|
||||
// note, the incoming packet buffer must be allocated from the heap
|
||||
// this function will take responsibility for releasing it
|
||||
@ -320,6 +361,12 @@ static int _nc_rx_combine_packet(struct nc_half *n, struct nc_packet *packet)
|
||||
{
|
||||
int i;
|
||||
|
||||
// ignore any packets with no information
|
||||
if (packet->combination == 0){
|
||||
free(packet->payload);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// First, reduce the combinations of the incoming packet based on other packets already seen
|
||||
for (i=0;i<n->max_queue_size;i++){
|
||||
if (!n->packets[i].payload || _compare_uint8(n->packets[i].sequence, packet->sequence) < 0)
|
||||
@ -404,14 +451,25 @@ static void _nc_rx_advance_window(struct nc_half *n, uint8_t new_window_start)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a network coded packet,
|
||||
* returns;
|
||||
* 0 - interesting packet, the caller should immediately attempt to decode packets
|
||||
* 1 - un-interesting
|
||||
* 2 - ack only
|
||||
*/
|
||||
int nc_rx_packet(struct nc *n, const uint8_t *payload, size_t len)
|
||||
{
|
||||
n->rx.packet_count++;
|
||||
|
||||
if (len>=2){
|
||||
_nc_ack(&n->tx, payload[0], payload[1]);
|
||||
}
|
||||
|
||||
if (len<NC_HEADER_LEN)
|
||||
return 1;
|
||||
if (len<NC_HEADER_LEN){
|
||||
n->rx.ack_count++;
|
||||
return 2;
|
||||
}
|
||||
|
||||
uint8_t new_window_start = payload[2];
|
||||
|
||||
@ -425,6 +483,9 @@ int nc_rx_packet(struct nc *n, const uint8_t *payload, size_t len)
|
||||
bcopy(&payload[NC_HEADER_LEN], packet.payload, len - NC_HEADER_LEN);
|
||||
|
||||
int r = _nc_rx_combine_packet(&n->rx, &packet);
|
||||
if (r==1)
|
||||
n->rx.uninteresting_count++;
|
||||
|
||||
_nc_rx_advance_window(&n->rx, new_window_start);
|
||||
|
||||
return r;
|
||||
@ -467,14 +528,6 @@ int nc_rx_next_delivered(struct nc *n, uint8_t *payload, int buffer_size)
|
||||
before current window.
|
||||
*/
|
||||
|
||||
static void _nc_dump(struct nc *n)
|
||||
{
|
||||
fprintf(stderr, "TX\n");
|
||||
_nc_dump_half(&n->tx);
|
||||
fprintf(stderr, "RX\n");
|
||||
_nc_dump_half(&n->rx);
|
||||
}
|
||||
|
||||
void FAIL(const char *fmt,...){
|
||||
va_list ap;
|
||||
fprintf(stderr, "FAIL: ");
|
||||
|
@ -17,5 +17,7 @@ int nc_tx_produce_packet(struct nc *n, uint8_t *datagram, uint32_t buffer_size);
|
||||
int nc_rx_packet(struct nc *n, const uint8_t *payload, size_t len);
|
||||
int nc_rx_next_delivered(struct nc *n, uint8_t *payload, int buffer_size);
|
||||
int nc_tx_packet_urgency(struct nc *n);
|
||||
void nc_dump(struct nc *n);
|
||||
void nc_state_html(struct strbuf *b, struct nc *nc);
|
||||
|
||||
#endif
|
16
radio_link.c
16
radio_link.c
@ -109,7 +109,9 @@ struct radio_link_state{
|
||||
// next firmware heartbeat
|
||||
time_ms_t next_heartbeat;
|
||||
|
||||
time_ms_t last_packet;
|
||||
time_ms_t last_tx_packet;
|
||||
time_ms_t last_rx_packet;
|
||||
time_ms_t last_decoded_packet;
|
||||
|
||||
// parsed rssi
|
||||
int radio_rssi;
|
||||
@ -171,6 +173,7 @@ void radio_link_state_html(struct strbuf *b, struct overlay_interface *interface
|
||||
struct radio_link_state *state = interface->radio_link_state;
|
||||
strbuf_sprintf(b, "RSSI: %ddB<br>", state->radio_rssi);
|
||||
strbuf_sprintf(b, "Remote RSSI: %ddB<br>", state->remote_rssi);
|
||||
nc_state_html(b, state->network_coding);
|
||||
}
|
||||
|
||||
static int encode_next_packet(struct radio_link_state *link_state)
|
||||
@ -356,15 +359,15 @@ int radio_link_tx(struct overlay_interface *interface)
|
||||
break;
|
||||
}
|
||||
|
||||
if (link_state->last_packet + delay > now){
|
||||
interface->alarm.alarm = link_state->last_packet + delay;
|
||||
if (link_state->last_tx_packet + delay > now){
|
||||
interface->alarm.alarm = link_state->last_tx_packet + delay;
|
||||
if (interface->alarm.alarm > next_tick)
|
||||
interface->alarm.alarm = next_tick;
|
||||
break;
|
||||
}
|
||||
|
||||
send_link_packet(interface);
|
||||
link_state->last_packet = now;
|
||||
link_state->last_tx_packet = now;
|
||||
}
|
||||
|
||||
watch(&interface->alarm);
|
||||
@ -418,6 +421,7 @@ static int radio_link_parse(struct overlay_interface *interface, struct radio_li
|
||||
if (tail == 0x555){
|
||||
if (config.debug.radio_link)
|
||||
DEBUGF("Decoded remote heartbeat request");
|
||||
state->last_rx_packet=gettime_ms();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@ -434,6 +438,7 @@ static int radio_link_parse(struct overlay_interface *interface, struct radio_li
|
||||
}
|
||||
*backtrack=errors;
|
||||
|
||||
state->last_rx_packet=gettime_ms();
|
||||
int rx = nc_rx_packet(state->network_coding, payload, packet_length);
|
||||
if (config.debug.radio_link)
|
||||
DEBUGF("RX returned %d", rx);
|
||||
@ -445,6 +450,7 @@ static int radio_link_parse(struct overlay_interface *interface, struct radio_li
|
||||
int len=nc_rx_next_delivered(state->network_coding, fragment, sizeof(fragment));
|
||||
if (len<=0)
|
||||
break;
|
||||
state->last_decoded_packet = gettime_ms();
|
||||
int fragment_len=fragment[0];
|
||||
if (fragment_len == PAYLOAD_FRAGMENT)
|
||||
fragment_len = len -1;
|
||||
@ -467,6 +473,8 @@ static int radio_link_parse(struct overlay_interface *interface, struct radio_li
|
||||
dump("Invalid packet?", state->dst, state->packet_length);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
state->packet_length=sizeof(state->dst);
|
||||
}
|
||||
|
||||
// reset the buffer for the next packet
|
||||
|
Loading…
Reference in New Issue
Block a user