aboutsummaryrefslogtreecommitdiff
path: root/arduino/ace/ace.c
diff options
context:
space:
mode:
Diffstat (limited to 'arduino/ace/ace.c')
-rw-r--r--arduino/ace/ace.c116
1 files changed, 116 insertions, 0 deletions
diff --git a/arduino/ace/ace.c b/arduino/ace/ace.c
new file mode 100644
index 0000000..ea05e1c
--- /dev/null
+++ b/arduino/ace/ace.c
@@ -0,0 +1,116 @@
+#include "ace.h"
+
+#include <avr/interrupt.h>
+
+
+typedef struct {
+ uint8_t buffer[SERIAL_BUFFER_SIZE];
+ volatile uint16_t head;
+ volatile uint16_t tail;
+} ring_buffer;
+
+static ring_buffer tx_buffer0 = {{0}, 0, 0};
+static framer framer0;
+static arq arq0;
+static uint32_t max_ticks0;
+static uint32_t ticks0;
+
+//initialize UART
+static void init_s0(uint32_t baud) {
+ UCSR0A |= (1 << U2X0); //enable double speed transmission
+ uint16_t baud_setting = (F_CPU / 4 / baud - 1) / 2;
+ UBRR0H = baud_setting >> 8;
+ UBRR0L = baud_setting;
+ UCSR0B |= (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0); // defaults to 8-bit, no parity, 1 stop bit
+ UCSR0B &= ~(1 << UDRIE0) | (1 << TXEN0) | (1 << RXCIE0);
+}
+
+static void send_to_s0(uint8_t byte) {
+ uint16_t i = (tx_buffer0.head + 1) % SERIAL_BUFFER_SIZE;
+ // If the output buffer is full, there's nothing for it other than to
+ // wait for the interrupt handler to empty it a bit
+ if (i == tx_buffer0.tail) return;
+ //while (i == tx_buffer0.tail) {};
+ tx_buffer0.buffer[tx_buffer0.head] = byte;
+ tx_buffer0.head = i;
+ //enable data register empty interrupt
+ UCSR0B |= (1 << UDRIE0);
+}
+
+static void send_to_framer0(int16_t size, const uint8_t* const data) {
+ send_frame(&framer0, size, data);
+}
+
+static void receive_from_framer0(int16_t size, uint8_t* data) {
+ receive_frame(&arq0, size, data);
+}
+
+//called when byte is received
+ISR(USART0_RX_vect) {
+ uint8_t c = UDR0;
+ receive_byte(&framer0, c);
+}
+
+//called when data register is empty
+ISR(USART0_UDRE_vect) {
+ if (tx_buffer0.head == tx_buffer0.tail) {
+ UCSR0B &= ~(1 << UDRIE0); //buffer empty, disable interruot
+ } else {
+ uint8_t c = tx_buffer0.buffer[tx_buffer0.tail];
+ tx_buffer0.tail = (tx_buffer0.tail + 1) % SERIAL_BUFFER_SIZE;
+ UDR0 = c; //write next byte
+ }
+}
+
+//initialize timer
+static void init_t0(uint32_t ticks) {
+ cli();
+ TCCR1A = 0;
+ TCCR1B = 0;
+ TCCR1B |= (1 << WGM12); // turn on CTC mode:
+ TCCR1B |= (1 << CS11); // set CS31 for 64 prescaler
+ // 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_ticks0 = ticks;
+ ticks0 = 0;
+}
+
+inline static void start_t0() {
+ TIMSK1 |= (1 << OCIE1A);
+}
+
+inline static void stop_t0() {
+ TIMSK1 &= ~(1 << OCIE1A);
+}
+
+ISR(TIMER1_COMPA_vect) {
+ ticks0 += 1;
+ if (ticks0 > max_ticks0) {
+ timeout(&arq0);
+ ticks0 = 0;
+ }
+}
+
+void init_ace0(uint32_t baud, uint32_t extra_time) {
+ init_s0(baud);
+ init_framer(&framer0);
+ init_arq(&arq0);
+
+ framer0.sender = send_to_s0;
+ arq0.sender = send_to_framer0;
+
+ framer0.receiver = receive_from_framer0;
+ arq0.event_handler = ace_event0;
+
+ uint32_t bits = (MAX_FRAME_SIZE + 3) * 8 * 2;
+ uint32_t tx_time = bits * 1000 / baud; // transmission time in milliseconds
+ init_t0(tx_time + extra_time);
+ arq0.start_timer = start_t0;
+ arq0.stop_timer = stop_t0;
+}
+
+void ace_send0(uint8_t size, const uint8_t* const message) {
+ send_message(&arq0, size, message);
+}