]> git.armaanb.net Git - atreides.git/blobdiff - firmware/atreus.c
Add C firmware.
[atreides.git] / firmware / atreus.c
diff --git a/firmware/atreus.c b/firmware/atreus.c
new file mode 100644 (file)
index 0000000..4e2bb75
--- /dev/null
@@ -0,0 +1,131 @@
+#include <stdlib.h>
+#include <avr/io.h>
+#include <util/delay.h>
+#include "usb_keyboard.h"
+
+#define ROW_COUNT 4
+#define COL_COUNT 11
+
+#define FN_PRESSED (~PINB & 128)
+
+#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n))
+
+void reset(void);
+
+\f
+
+// Outputs
+// |------------+----+----+----+----|
+// | row number |  0 |  1 |  2 |  3 |
+// |------------+----+----+----+----|
+// | pin number | D0 | D1 | D2 | D3 |
+// |------------+----+----+----+----|
+
+// Inputs
+// |---------------+----+----+----+----+----+----+----+----+----+----+----|
+// | column number |  0 |  1 |  2 |  3 |  4 |  5 |  6 |  7 |  8 |  9 | 10 |
+// |---------------+----+----+----+----+----+----+----+----+----+----+----|
+// | pin number    | B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 | F4 | F5 | F6 |
+// |---------------+----+----+----+----+----+----+----+----+----+----+----|
+
+\f
+
+// numbers under 100: normal keys
+// numbers between 100 and 200: shifted keys
+// numbers over 200: function invocations
+
+int base_layout[ROW_COUNT][COL_COUNT] = \
+  { {20, 26, 8,   21,  23,  0,  28, 24, 12, 18, 19},      \
+    {4,  22, 7,   9,   10,  0,  11, 13, 14, 15, 51},      \
+    {29, 27, 6,   25,  5,  101, 17, 16, 54, 55, 56},      \
+    {41, 43, 108, 102, 42, 104, 44, 0,  52, 47, 40} };
+
+int fn_layout[ROW_COUNT][COL_COUNT] = \
+  { {108+30, 108+31, 108+45, 108+46, 108 + 49, 0, 75, 36, 37, 38, 108+37}, \
+    {108+32, 108+33, 108+38, 108+39, 53, 0, 78, 33, 34, 35, 108+46},    \
+    {108 + 34, 108 + 35, 45, 46, 108+53, 101, 49, 30, 31, 32, 108+47},  \
+    {255, 108 + 73, 108, 102, 0, 104, 0, 0, 55, 39, 48} };
+
+int *current_row;
+
+int pressed_count = 0;
+
+\f
+
+void press(int keycode) {
+  if(!keycode || pressed_count >= 6) return;
+  if(keycode == 255 || keycode == 5) {
+    reset(); // TODO: make a table of codes -> functions
+  } else if(keycode > 108) {
+    keyboard_modifier_keys |= KEY_SHIFT;
+    keyboard_keys[pressed_count++] = (keycode - 108);
+  } else if(keycode > 100) {
+    keyboard_modifier_keys |= (keycode - 100);
+  } else {
+    keyboard_keys[pressed_count++] = keycode;
+  };
+};
+
+void activate_row(int row) {
+  PORTD = (char)(~(1 << row)) | 32; // leave the LED on
+};
+
+void scan_row(int row) {
+  int cols = (~(PINB + ((PINF >> 4) << 8))) & 2047;
+  for(int col = 0; col < 8; col++) {
+    if(cols & 1) {
+      press(current_row[col]);
+    };
+    cols = cols >> 1;
+  };
+};
+
+\f
+
+void init() {
+  CPU_PRESCALE(0);
+  DDRD = 255;
+  DDRB = 0;
+  DDRF = 0;
+  PORTB = 255;
+  PORTF = 255;
+  usb_init();
+  while (!usb_configured()) /* wait */ ;
+  _delay_ms(1000);
+};
+
+void clear_keys() {
+  keyboard_modifier_keys = 0;
+  pressed_count = 0;
+  for(int i = 0; i < 6; i++) {
+    keyboard_keys[i] = 0;
+  };
+};
+
+int main() {
+  init();
+  while(1) {
+    // 4th row is still active from last scan
+    current_row = FN_PRESSED ? fn_layout : base_layout;
+    for(int i = 0; i < ROW_COUNT; i++) {
+      activate_row(i);
+      scan_row(i);
+      current_row += COL_COUNT;
+      _delay_us(50);
+    };
+    usb_keyboard_send();
+    clear_keys();
+  };
+};
+
+void reset(void) {
+  UDCON = 1;
+  USBCON = (1<<FRZCLK);
+  UCSR1B = 0;
+  _delay_ms(5);
+  EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0;
+  TIMSK0 = 0; TIMSK1 = 0; TIMSK3 = 0; TIMSK4 = 0; UCSR1B = 0; TWCR = 0;
+  DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; TWCR = 0;
+  PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0;
+  asm volatile("jmp 0x7E00");
+};