1
0
mirror of git://projects.qi-hardware.com/ben-wpan.git synced 2024-11-22 19:20:41 +02:00

tools/dirtpan/: rewritten for simultaneous reception and transmission

Note that the PHY is still half-duplex, but we don't need to insist
on the entire packet reception/transmission to finish before letting
the peer have its say.
This commit is contained in:
Werner Almesberger 2011-05-12 16:26:38 -03:00
parent 707af5f4da
commit 7e2c576f7b

View File

@ -11,6 +11,7 @@
*/
#include <stdarg.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
@ -58,18 +59,12 @@ enum packet_type {
#define T_ACK_MS 50
static enum state {
s_idle,
s_tx,
s_rx,
} state = s_idle;
static int tun, net;
static uint8_t packet[MAX_PACKET+1];
static void *pos;
static int left;
static int my_seq = 0, peer_seq;
static uint8_t rx_packet[MAX_PACKET], tx_packet[MAX_PACKET+1];
static void *rx_pos, *tx_pos;
static int rx_left, tx_left;
static int txing = 0, rxing = 0;
static int rx_seq, tx_seq = 0;
static int retries;
static int debug = 0;
@ -79,23 +74,8 @@ static int debug = 0;
static void debug_label(const char *label)
{
const char *t;
switch (state) {
case s_idle:
t = "--";
break;
case s_tx:
t = "tx";
break;
case s_rx:
t = "rx";
break;
default:
t = "???";
break;
}
fprintf(stderr, "%s(%s)", label, t);
fprintf(stderr, "%s(%c%c)",
label, txing ? 'T' : '-', rxing ? 'R' : '-');
}
@ -163,36 +143,73 @@ static void debug_timeout(const char *label)
/* ----- Timers ------------------------------------------------------------ */
static struct timeval t0;
static struct timeval t_reass, t_ack;
static void start_timer(void)
static void start_timer(struct timeval *t, int ms)
{
gettimeofday(&t0, NULL);
assert(!t->tv_sec && !t->tv_usec);
gettimeofday(t, NULL);
t->tv_usec += 1000*ms;
while (t->tv_usec >= 1000000) {
t->tv_sec++;
t->tv_usec -= 1000000;
}
}
static struct timeval *timeout(int ms)
static void stop_timer(struct timeval *t)
{
static struct timeval t;
assert(t->tv_sec || t->tv_usec);
t->tv_sec = 0;
t->tv_usec = 0;
}
gettimeofday(&t, NULL);
t.tv_sec -= t0.tv_sec;
t.tv_usec -= t0.tv_usec;
t.tv_usec += 1000*ms;
while (t.tv_usec < 0) {
t.tv_sec--;
t.tv_usec += 1000000;
static const struct timeval *next_timer(int n, ...)
{
va_list ap;
const struct timeval *next = NULL;
const struct timeval *t;
va_start(ap, n);
while (n--) {
t = va_arg(ap, const struct timeval *);
if (!t->tv_sec && !t->tv_usec)
continue;
if (next) {
if (next->tv_sec < t->tv_sec)
continue;
if (next->tv_sec == t->tv_sec &&
next->tv_usec < t->tv_usec)
continue;
}
next = t;
}
while (t.tv_usec >= 1000000) {
t.tv_sec++;
t.tv_usec -= 1000000;
}
if (t.tv_sec < 0)
t.tv_sec = t.tv_usec = 0;
va_end(ap);
return next;
}
return &t;
static struct timeval *timer_delta(const struct timeval *t)
{
static struct timeval d;
if (!t)
return NULL;
gettimeofday(&d, NULL);
d.tv_sec = t->tv_sec-d.tv_sec;
d.tv_usec = t->tv_usec-d.tv_usec;
while (d.tv_usec < 0) {
d.tv_sec--;
d.tv_usec += 1000000;
}
if (d.tv_sec < 0)
d.tv_sec = d.tv_usec = 0;
return &d;
}
@ -201,7 +218,7 @@ static struct timeval *timeout(int ms)
static inline int send_size(void)
{
return left > MAX_FRAG ? MAX_FRAG : left;
return tx_left > MAX_FRAG ? MAX_FRAG : tx_left;
}
@ -228,11 +245,11 @@ static void send_frame(void *buf, int size)
static void send_more(void)
{
uint8_t *p = pos-1;
uint8_t *p = tx_pos-1;
*p = (pos == packet+1 ? pt_first : pt_next) | (my_seq ? SEQ : 0);
*p = (tx_pos == tx_packet+1 ? pt_first : pt_next) | (tx_seq ? SEQ : 0);
send_frame(p, send_size()+1);
start_timer();
start_timer(&t_ack, T_ACK_MS);
}
@ -261,75 +278,67 @@ static void rx_pck(void *buf, int size)
type = ctrl & PT_MASK;
seq = !!(ctrl & SEQ);
if (type == pt_first || type == pt_next)
switch (type) {
case pt_first:
send_ack(seq);
switch (state) {
case s_tx:
if (type == pt_first) {
/*
* @@@ Not optimal - we break the tie but lose a
* perfectly good frame.
*/
state = s_idle;
if (rxing) {
stop_timer(&t_reass);
rxing = 0;
}
break;
case pt_next:
send_ack(seq);
if (!rxing)
return;
if (seq == rx_seq)
return; /* retransmission */
break;
case pt_ack:
if (!txing)
return;
if (seq != tx_seq)
return;
stop_timer(&t_ack);
tx_pos += send_size();
tx_left -= send_size();
if (!tx_left) {
txing = 0;
return;
}
if (type != pt_ack)
return;
if (seq != my_seq)
return;
pos += send_size();
left -= send_size();
if (!left) {
state = s_idle;
return;
}
my_seq = !my_seq;
tx_seq = !tx_seq;
retries = 0;
send_more();
return;
case s_rx:
if (type == pt_first) {
start_timer();
state = s_idle;
break;
}
if (type != pt_next)
return;
if (seq == peer_seq)
return; /* retransmission */
goto recv_more;
case s_idle:
if (type == pt_first)
break;
if (type == pt_next)
return;
return;
default:
abort();
}
if (size < 5)
return;
left = p[3] << 8 | p[4];
if (left > MAX_PACKET+1)
return;
state = s_rx;
pos = packet;
if (!rxing) {
if (size < 5)
return;
rx_left = p[3] << 8 | p[4];
if (rx_left > MAX_PACKET)
return;
start_timer(&t_reass, T_REASS_MS);
rxing = 1;
rx_pos = rx_packet;
}
recv_more:
if (left < size-1) {
state = s_idle;
if (rx_left < size-1) {
stop_timer(&t_reass);
rxing = 0;
return;
}
memcpy(pos, buf+1, size-1);
pos += size-1;
left -= size-1;
peer_seq = seq;
memcpy(rx_pos, buf+1, size-1);
rx_pos += size-1;
rx_left -= size-1;
rx_seq = seq;
if (!left) {
debug_ip("<-", packet, pos-(void *) packet);
write_buf(tun, packet, pos-(void *) packet);
state = s_idle;
if (!rx_left) {
debug_ip("<-", rx_packet, rx_pos-(void *) rx_packet);
write_buf(tun, rx_packet, rx_pos-(void *) rx_packet);
stop_timer(&t_reass);
rxing = 0;
}
}
@ -339,17 +348,17 @@ static void tx_pck(void *buf, int size)
const uint8_t *p = buf;
debug_ip(">-", buf, size);
assert(state == s_idle);
state = s_tx;
pos = packet+1;
left = p[2] << 8 | p[3];
assert(left <= MAX_PACKET);
assert(left == size);
assert(!txing);
txing = 1;
tx_pos = tx_packet+1;
tx_left = p[2] << 8 | p[3];
assert(tx_left <= MAX_PACKET);
assert(tx_left == size);
/*
* We could avoid the memcpy by reading directly into "packet"
* @@@ We could avoid the memcpy by reading directly into "tx_packet"
*/
memcpy(pos, buf, size);
my_seq = !my_seq;
memcpy(tx_pos, buf, size);
tx_seq = !tx_seq;
retries = 0;
send_more();
}
@ -358,8 +367,10 @@ static void tx_pck(void *buf, int size)
static void ack_timeout(void)
{
debug_timeout("ACK-TO");
assert(txing);
stop_timer(&t_ack);
if (++retries == MAX_TRIES)
state = s_idle;
txing = 0;
else
send_more();
}
@ -368,7 +379,9 @@ static void ack_timeout(void)
static void reass_timeout(void)
{
debug_timeout("REASS-TO");
state = s_idle;
assert(rxing);
stop_timer(&t_reass);
rxing = 0;
}
@ -378,43 +391,32 @@ static void reass_timeout(void)
static void event(void)
{
uint8_t buf[MAX_PACKET];
struct timeval *to;
const struct timeval *to;
fd_set rset;
int res;
ssize_t got;
FD_ZERO(&rset);
FD_SET(net, &rset);
switch (state) {
case s_idle:
/* only accept more work if we're idle */
if (!txing && !rxing)
FD_SET(tun, &rset);
to = NULL;
break;
case s_rx:
to = timeout(T_REASS_MS);
break;
case s_tx:
to = timeout(T_ACK_MS);
break;
default:
abort();
}
res = select(net > tun ? net+1 : tun+1, &rset, NULL, NULL, to);
to = next_timer(2, &t_reass, &t_ack);
res = select(net > tun ? net+1 : tun+1, &rset, NULL, NULL,
timer_delta(to));
if (res < 0) {
perror("select");
return;
}
if (!res) {
switch (state) {
case s_rx:
assert(to);
if (to == &t_reass)
reass_timeout();
break;
case s_tx:
else
ack_timeout();
break;
default:
abort();
}
}
if (FD_ISSET(tun, &rset)) {
got = read(tun, buf, sizeof(buf));