#include "transport.h" #include "link.h" #include #include #include //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); }