diff options
author | Jakob Odersky <jodersky@gmail.com> | 2013-02-25 19:39:53 +0100 |
---|---|---|
committer | Jakob Odersky <jodersky@gmail.com> | 2013-02-25 19:39:53 +0100 |
commit | e15a7e1267a6f733d734c5d3b59f3acc28bb4b29 (patch) | |
tree | 9d9c513492939c4467c0932a25291a63d787a7ca /arduino/ace_old/transport.c | |
download | ace-e15a7e1267a6f733d734c5d3b59f3acc28bb4b29.tar.gz ace-e15a7e1267a6f733d734c5d3b59f3acc28bb4b29.tar.bz2 ace-e15a7e1267a6f733d734c5d3b59f3acc28bb4b29.zip |
initial commit
Diffstat (limited to 'arduino/ace_old/transport.c')
-rw-r--r-- | arduino/ace_old/transport.c | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/arduino/ace_old/transport.c b/arduino/ace_old/transport.c new file mode 100644 index 0000000..986165e --- /dev/null +++ b/arduino/ace_old/transport.c @@ -0,0 +1,166 @@ +#include "transport.h" +#include "link.h" + +#include <stdlib.h> +#include <stdbool.h> +#include <avr/interrupt.h> + +//ms +#define EXTRA_TIME 200 +#define MAX_RESENDS 5 +#define MAX_SEQ 255 + +#define next_seq(k) if (k < MAX_SEQ) k = k + 1; else k = 0 + +#define DATA 0x05 +#define ACK 0x06 + + +static void start_sending(message* msg, bool resend); +static void stop_sending(); + + +typedef enum { + RECEIVED_PACKET, + TIMEOUT +} event_kind; + +typedef struct { + event_kind kind; + packet* payload; +} event; + +static void disassemble_packet(packet* p, uint8_t* seq, uint8_t* command, uint8_t** msg, uint16_t* message_length) { + if (seq != NULL) *seq = p->data[0]; + if (command != NULL) *command = p->data[1]; + if (msg != NULL) *msg = &(p->data[2]); + if (message_length != NULL) *message_length = p->length - 2; +} + +static void assemble_packet(packet* p, uint8_t seq, uint8_t command, uint8_t* msg, uint16_t message_length) { + p->data[0] = seq; + p->data[1] = command; + int i; + for (i = 0; i < message_length; ++i) { + p->data[i+2] = msg[i]; + } + p->length = message_length + 2; +} + +static packet* ack(uint8_t seq) { + static uint8_t ack_buffer[] = {0, ACK}; + static packet ack_packet = {ack_buffer, 2}; + ack_buffer[0] = seq; + return &ack_packet; +} + +static volatile bool awaiting_ack = false; +static volatile uint8_t last_sent_seq = 0; +static volatile uint8_t resends = 0; +static volatile uint8_t last_sent_buffer[MAX_PACKET_SIZE]; +static volatile packet last_sent = {last_sent_buffer, 0}; + +static void process_event(event* e) { + static uint8_t last_received_seq = 0; + + switch(e->kind) { + case RECEIVED_PACKET: { + uint8_t seq; + uint8_t cmd; + static message msg; + disassemble_packet(e->payload, &seq, &cmd, &msg.data, &msg.length); + + if (!awaiting_ack) { + if (cmd == DATA) { + if (last_received_seq != seq) { + last_received_seq = seq; + from_transport_layer(RECEIVED, &msg); + } + to_link_layer(ack(seq)); + } + //ignore case in which an ack is received even though none is awaited + + } else { //waiting for an ack + stop_sending(); + disassemble_packet(&last_sent, NULL, NULL, &msg.data, &msg.length); + if (cmd == ACK && seq == last_sent_seq) { + from_transport_layer(SEND_SUCCESS, &msg); + } else { + from_transport_layer(BAD_ACK, &msg); + } + } + } break; + case TIMEOUT: + if (resends > MAX_RESENDS) { + message msg; + disassemble_packet(&last_sent, NULL, NULL, &msg.data, &msg.length); + stop_sending(); + from_transport_layer(NO_ACK, &msg); + } else { + start_sending(NULL, true); + } + break; + } +} + +static void start_sending(message* msg, bool resend) { + if (resend) { + resends = resends + 1; + } else { + next_seq(last_sent_seq); + assemble_packet(&last_sent, last_sent_seq, DATA, msg->data, msg->length); + resends = 0; + TIMSK1 |= (1 << OCIE1A); + } + + awaiting_ack = true; + to_link_layer(&last_sent); +} + +static void stop_sending() { + TIMSK1 &= ~(1 << OCIE1A); + awaiting_ack = false; +} + +static volatile uint32_t ticks; +static volatile uint32_t max_ticks; + +void init_transport_layer(uint32_t timeout_millis) { + cli(); + TCCR1A = 0; // set entire TCCR1A register to 0 + TCCR1B = 0; // same for TCCR1B + // turn on CTC mode: + TCCR1B |= (1 << WGM12); + // set CS31 for 64 prescaler + TCCR1B |= (1 << CS11); + // set compare match register to desired timer count: + OCR1A = F_CPU / 1000 / 64; // should be 250 for F_CPU=16Mhz and f = 1000Hz + sei(); + + //the timer should now interrupt every ms + max_ticks = timeout_millis; +} + +ISR(TIMER1_COMPA_vect) { + static event e = {TIMEOUT, NULL}; + + ticks = ticks + 1; + if (ticks > max_ticks) { + process_event(&e); + ticks = 0; + } +} + +void from_link_layer(packet* r) { + static event e = {RECEIVED_PACKET, NULL}; + e.payload = r; + process_event(&e); +} + +void to_transport_layer(message* s) { + if (!awaiting_ack) + start_sending(s, false); + else + from_transport_layer(BUSY, s); +} + |