Add network coding stats to html output

This commit is contained in:
Jeremy Lakeman 2013-11-04 14:13:12 +10:30
parent c1e90a7bce
commit 37e480c623
3 changed files with 86 additions and 23 deletions

View File

@ -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: ");

View File

@ -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

View File

@ -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