aboutsummaryrefslogtreecommitdiff
path: root/arduino/ace_old/transport.c
diff options
context:
space:
mode:
Diffstat (limited to 'arduino/ace_old/transport.c')
-rw-r--r--arduino/ace_old/transport.c166
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);
+}
+