summaryrefslogtreecommitdiff
path: root/tuer-rfid
diff options
context:
space:
mode:
authorChristian Pointner <equinox@spreadspace.org>2013-08-08 22:39:50 +0000
committerChristian Pointner <equinox@spreadspace.org>2013-08-08 22:39:50 +0000
commit2c997f95cb167e9023c1a44abaeda4ea80bbc7d3 (patch)
tree66cd2988de8f233b80c8e9b83b597484c3a33607 /tuer-rfid
parentadded support for teenstep (diff)
moved usb-i2c-sl018 to tuer-rfid
git-svn-id: https://svn.spreadspace.org/avr/trunk@216 aa12f405-d877-488e-9caf-2d797e2a1cc7
Diffstat (limited to 'tuer-rfid')
-rw-r--r--tuer-rfid/Makefile59
-rw-r--r--tuer-rfid/ajar.c76
-rw-r--r--tuer-rfid/ajar.h34
-rw-r--r--tuer-rfid/eventqueue.c61
-rw-r--r--tuer-rfid/eventqueue.h34
-rw-r--r--tuer-rfid/heartbeat.c74
-rw-r--r--tuer-rfid/heartbeat.h30
-rw-r--r--tuer-rfid/keystore.c111
-rw-r--r--tuer-rfid/keystore.h33
-rw-r--r--tuer-rfid/ledmatrix.c218
-rw-r--r--tuer-rfid/ledmatrix.h34
-rw-r--r--tuer-rfid/limits.c103
-rw-r--r--tuer-rfid/limits.h33
-rw-r--r--tuer-rfid/manual.c58
-rw-r--r--tuer-rfid/manual.h30
-rw-r--r--tuer-rfid/sl018.c245
-rw-r--r--tuer-rfid/sl018.h40
-rw-r--r--tuer-rfid/statemachine.c185
-rw-r--r--tuer-rfid/statemachine.dot45
-rw-r--r--tuer-rfid/statemachine.h30
-rw-r--r--tuer-rfid/stepper.c116
-rw-r--r--tuer-rfid/stepper.h32
-rw-r--r--tuer-rfid/tuer-rfid.c153
-rw-r--r--tuer-rfid/update-keys.c138
24 files changed, 1972 insertions, 0 deletions
diff --git a/tuer-rfid/Makefile b/tuer-rfid/Makefile
new file mode 100644
index 0000000..697806b
--- /dev/null
+++ b/tuer-rfid/Makefile
@@ -0,0 +1,59 @@
+##
+## spreadspace avr utils
+##
+##
+## Copyright (C) 2013 Christian Pointner <equinox@spreadspace.org>
+## Othmar Gsenger <otti@wirdorange.org>
+##
+## This file is part of spreadspace avr utils.
+##
+## spreadspace avr utils is free software: you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## any later version.
+##
+## spreadspace avr utils is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+##
+
+NAME := tuer-rfid
+BOARD_TYPE := teensy2
+OBJ := $(NAME).o heartbeat.o stepper.o ledmatrix.o sl018.o keystore.o statemachine.o eventqueue.o limits.o manual.o ajar.o
+LIBS := util led lufa-descriptor-usbserial anyio
+EXTERNAL_LIBS := lufa
+
+LUFA_PATH := ../contrib/LUFA-120219
+LUFA_OPTS = -D USB_DEVICE_ONLY
+LUFA_OPTS += -D DEVICE_STATE_AS_GPIOR=0
+LUFA_OPTS += -D ORDERED_EP_CONFIG
+LUFA_OPTS += -D FIXED_CONTROL_ENDPOINT_SIZE=8
+LUFA_OPTS += -D FIXED_NUM_CONFIGURATIONS=1
+LUFA_OPTS += -D USE_FLASH_DESCRIPTORS
+LUFA_OPTS += -D USE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)"
+LUFA_OPTS += -D INTERRUPT_CONTROL_ENDPOINT
+
+LUFA_OPTS += -D USB_MANUFACTURER="L\"equinox\""
+LUFA_OPTS += -D USB_PRODUCT="L\"$(NAME)\""
+
+LUFA_COMPONENTS := USB USBCLASS TWI SERIAL
+
+CLEAN_TARGETS += clean-pdf clean-update-keys
+
+include ../include.mk
+
+update-keys: update-keys.c
+ gcc -o $@ $<
+
+clean-update-keys:
+ rm -f update-keys
+
+pdf: statemachine.dot
+ dot -Tpdf statemachine.dot -o statemachine.pdf
+
+clean-pdf:
+ rm -f statemachine.pdf
diff --git a/tuer-rfid/ajar.c b/tuer-rfid/ajar.c
new file mode 100644
index 0000000..dc7dc01
--- /dev/null
+++ b/tuer-rfid/ajar.c
@@ -0,0 +1,76 @@
+/*
+ * spreadspace avr utils
+ *
+ *
+ * Copyright (C) 2013 Christian Pointner <equinox@spreadspace.org>
+ * Othmar Gsenger <otti@wirdorange.org>
+ *
+ * This file is part of spreadspace avr utils.
+ *
+ * spreadspace avr utils is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * spreadspace avr utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <avr/io.h>
+#include <stdio.h>
+#include "ajar.h"
+
+#define AJAR_PIN PIND
+#define AJAR_PORT PORTD
+#define AJAR_DDR DDRD
+#define AJAR_BIT 4
+
+#define AJAR_LP_MAX 255
+
+void ajar_init(void)
+{
+ AJAR_DDR = AJAR_DDR & ~(1<<AJAR_BIT);
+ AJAR_PORT |= (1<<AJAR_BIT);
+}
+
+ajar_t ajar_get(void)
+{
+ static uint8_t last_state = (1<<AJAR_BIT);
+ static uint8_t lp_cnt = 0;
+
+ uint8_t state = AJAR_PIN & (1<<AJAR_BIT);
+ if(state != last_state)
+ lp_cnt++;
+ else
+ lp_cnt += lp_cnt ? -1 : 0;
+
+ if(lp_cnt >= AJAR_LP_MAX) {
+ last_state = state;
+ lp_cnt = 0;
+ }
+
+ if(last_state)
+ return ajar;
+ return shut;
+}
+
+const char* ajar_to_string(ajar_t a)
+{
+ return a == ajar ? "ajar" : "shut";
+}
+
+void ajar_task(void)
+{
+ static ajar_t last_state = shut;
+
+ ajar_t state = ajar_get();
+ if(last_state != state)
+ printf("Info(ajar): door is now %s\n\r", ajar_to_string(state));
+
+ last_state = state;
+}
diff --git a/tuer-rfid/ajar.h b/tuer-rfid/ajar.h
new file mode 100644
index 0000000..d05e2e6
--- /dev/null
+++ b/tuer-rfid/ajar.h
@@ -0,0 +1,34 @@
+/*
+ * spreadspace avr utils
+ *
+ *
+ * Copyright (C) 2013 Christian Pointner <equinox@spreadspace.org>
+ * Othmar Gsenger <otti@wirdorange.org>
+ *
+ * This file is part of spreadspace avr utils.
+ *
+ * spreadspace avr utils is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * spreadspace avr utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef R3TUER_ajar_h_INCLUDED
+#define R3TUER_ajar_h_INCLUDED
+
+typedef enum { ajar, shut } ajar_t;
+
+void ajar_init(void);
+ajar_t ajar_get(void);
+const char* ajar_to_string(ajar_t a);
+void ajar_task(void);
+
+#endif
diff --git a/tuer-rfid/eventqueue.c b/tuer-rfid/eventqueue.c
new file mode 100644
index 0000000..add5164
--- /dev/null
+++ b/tuer-rfid/eventqueue.c
@@ -0,0 +1,61 @@
+/*
+ * spreadspace avr utils
+ *
+ *
+ * Copyright (C) 2013 Christian Pointner <equinox@spreadspace.org>
+ * Othmar Gsenger <otti@wirdorange.org>
+ *
+ * This file is part of spreadspace avr utils.
+ *
+ * spreadspace avr utils is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * spreadspace avr utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "eventqueue.h"
+#include <LUFA/Drivers/Misc/RingBuffer.h>
+
+static RingBuffer_t event_queue;
+static uint8_t event_queue_data[16];
+
+void eventqueue_init(void)
+{
+ RingBuffer_InitBuffer(&event_queue, event_queue_data, sizeof(event_queue_data));
+}
+
+event_t eventqueue_pop(void)
+{
+ if (RingBuffer_IsEmpty(&event_queue))
+ return none;
+ return RingBuffer_Remove(&event_queue);
+}
+
+void eventqueue_push(event_t event)
+{
+ RingBuffer_Insert(&event_queue,event);
+}
+
+const char* event_to_string(event_t event)
+{
+ switch(event) {
+ case none: return "none";
+ case cmd_open: return "cmd_open";
+ case cmd_close: return "cmd_close";
+ case cmd_toggle: return "cmd_toggle";
+ case btn_toggle: return "btn_toggle";
+ case card: return "card";
+ case open_fin: return "open_fin";
+ case close_fin: return "close_fin";
+ case move_timeout: return "move_timeout";
+ }
+ return "invalid"; // gcc - shut the fuck up!!!
+}
diff --git a/tuer-rfid/eventqueue.h b/tuer-rfid/eventqueue.h
new file mode 100644
index 0000000..a7bd689
--- /dev/null
+++ b/tuer-rfid/eventqueue.h
@@ -0,0 +1,34 @@
+/*
+ * spreadspace avr utils
+ *
+ *
+ * Copyright (C) 2013 Christian Pointner <equinox@spreadspace.org>
+ * Othmar Gsenger <otti@wirdorange.org>
+ *
+ * This file is part of spreadspace avr utils.
+ *
+ * spreadspace avr utils is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * spreadspace avr utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef R3TUER_eventqueue_h_INCLUDED
+#define R3TUER_eventqueue_h_INCLUDED
+
+typedef enum { none, cmd_open, cmd_close, cmd_toggle, btn_toggle, card, close_fin, open_fin, move_timeout } event_t;
+
+void eventqueue_init(void);
+event_t eventqueue_pop(void);
+void eventqueue_push(event_t);
+const char* event_to_string(event_t event);
+
+#endif
diff --git a/tuer-rfid/heartbeat.c b/tuer-rfid/heartbeat.c
new file mode 100644
index 0000000..7700706
--- /dev/null
+++ b/tuer-rfid/heartbeat.c
@@ -0,0 +1,74 @@
+/*
+ * spreadspace avr utils
+ *
+ *
+ * Copyright (C) 2013 Christian Pointner <equinox@spreadspace.org>
+ * Othmar Gsenger <otti@wirdorange.org>
+ *
+ * This file is part of spreadspace avr utils.
+ *
+ * spreadspace avr utils is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * spreadspace avr utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <avr/sfr_defs.h>
+#include <avr/interrupt.h>
+
+#include "led.h"
+#include "heartbeat.h"
+
+#define HEARTBEAT_DURATION 10 // *10 ms, duration of heartbeat pulse
+#define HEARTBEAT_DELAY 200 // *10 ms, 1/heartbeat-frequency
+uint8_t heartbeat_cnt = 0;
+uint8_t heartbeat_flag;
+
+#define FASTBEAT_PORT PORTD
+#define FASTBEAT_DDR DDRD
+#define FASTBEAT_BIT 5
+
+// while running this gets called every ~10ms
+ISR(TIMER0_COMPA_vect)
+{
+ heartbeat_cnt++;
+ if(heartbeat_cnt == HEARTBEAT_DURATION)
+ heartbeat_flag = 0;
+ else if(heartbeat_cnt >= HEARTBEAT_DELAY) {
+ heartbeat_flag = 1;
+ heartbeat_cnt = 0;
+ }
+}
+
+void heartbeat_init(void)
+{
+ led_off();
+ heartbeat_cnt = 0;
+ heartbeat_flag = 1;
+
+ TCCR0A = 1<<WGM01; // OC0A and OC0B as normal output, WGM = 2 (CTC)
+ TCCR0B = 1<<CS02 | 1<<CS00; // Prescaler 1:1024
+ OCR0A = 155; // (1+155)*1024 = 159744 -> ~10 ms @ 16 MHz
+ TCNT2 = 0;
+ TIMSK0 = 1<<OCIE0A;
+
+ FASTBEAT_DDR |= 1<<FASTBEAT_BIT;
+}
+
+void heartbeat_task(void)
+{
+ FASTBEAT_PORT ^= 1<<FASTBEAT_BIT;
+
+ if(heartbeat_flag)
+ led_on();
+ else
+ led_off();
+}
diff --git a/tuer-rfid/heartbeat.h b/tuer-rfid/heartbeat.h
new file mode 100644
index 0000000..148f823
--- /dev/null
+++ b/tuer-rfid/heartbeat.h
@@ -0,0 +1,30 @@
+/*
+ * spreadspace avr utils
+ *
+ *
+ * Copyright (C) 2013 Christian Pointner <equinox@spreadspace.org>
+ * Othmar Gsenger <otti@wirdorange.org>
+ *
+ * This file is part of spreadspace avr utils.
+ *
+ * spreadspace avr utils is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * spreadspace avr utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef R3TUER_heatbeat_h_INCLUDED
+#define R3TUER_heatbeat_h_INCLUDED
+
+void heartbeat_init(void);
+void heartbeat_task(void);
+
+#endif
diff --git a/tuer-rfid/keystore.c b/tuer-rfid/keystore.c
new file mode 100644
index 0000000..645f25a
--- /dev/null
+++ b/tuer-rfid/keystore.c
@@ -0,0 +1,111 @@
+/*
+ * spreadspace avr utils
+ *
+ *
+ * Copyright (C) 2013 Christian Pointner <equinox@spreadspace.org>
+ * Othmar Gsenger <otti@wirdorange.org>
+ *
+ * This file is part of spreadspace avr utils.
+ *
+ * spreadspace avr utils is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * spreadspace avr utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "keystore.h"
+#include <avr/eeprom.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "led.h"
+#include "anyio.h"
+
+#define EEPROM_SIZE 1024
+typedef uint8_t keyslot_t[8];
+keyslot_t EEMEM keystore[EEPROM_SIZE/sizeof(keyslot_t)];
+
+
+void keystore_flash_from_stdio(void)
+{
+ keyslot_t ks;
+ uint8_t byte_pos=0;
+ printf("Info(keystore): flashing\n\r");
+ fflush(stdout);
+ for(uint8_t ks_pos=0;ks_pos<EEPROM_SIZE/sizeof(ks);) {
+ anyio_task();
+
+ int16_t bytes_received = anyio_bytes_received();
+ while(bytes_received > 0) {
+ ks[byte_pos++]=fgetc(stdin);
+ bytes_received--;
+ if (byte_pos == sizeof(ks)) {
+ byte_pos=0;
+ eeprom_update_block(&ks,&keystore[ks_pos],sizeof(ks));
+ ks_pos++;
+ fputc('.', stdout);
+ fflush(stdout);
+ led_toggle();
+ }
+ }
+ }
+ printf("\n\r");
+ fputc(0, stdout);
+ led_off();
+}
+
+void keystore_dump_to_stdio(void)
+{
+ keyslot_t ks;
+ for(uint8_t ks_pos=0;ks_pos<EEPROM_SIZE/sizeof(ks);ks_pos++) {
+ eeprom_read_block(&ks,&keystore[ks_pos],sizeof(ks));
+ for (uint8_t i=0; i< sizeof(ks); i++)
+ printf("%02X",ks[i]);
+ printf("\n\r");
+ }
+}
+
+/* this generates a Fletcher8 checksum */
+/* code from: http://stackoverflow.com/questions/13491700/8-bit-fletcher-checksum-of-16-byte-data */
+uint8_t generate_csum(uint8_t* data)
+{
+ uint16_t sum1 = 0xf, sum2 = 0xf, len = sizeof(keyslot_t) - 1;
+ do { sum2 += ( sum1 += *data++ ); } while (--len);
+ return sum2<<4 | sum1;
+}
+
+uint8_t compare_keyslots(const keyslot_t a, const keyslot_t b)
+{
+ uint8_t tmp=0;
+ // constant time compare
+ for(uint8_t i=0; i<sizeof(keyslot_t); ++i)
+ tmp |= a[i] ^ b[i];
+ return tmp;
+}
+
+uint8_t keystore_check_card(const uint8_t * uid, uint8_t uid_len)
+{
+ keyslot_t card, ks;
+ memset(card, 0, sizeof(card));
+ for (uint8_t pos=0; pos<uid_len; pos++)
+ card[pos]=uid[uid_len-pos-1];
+ card[sizeof(keyslot_t)-1]=generate_csum(card);
+ uint8_t valid=0;
+ for(uint8_t ks_pos=0;ks_pos<(EEPROM_SIZE/sizeof(ks));ks_pos++) {
+ eeprom_read_block(&ks,&keystore[ks_pos],sizeof(ks));
+ if(!compare_keyslots(card, ks)) {
+ valid=1;
+ // break; // this would break security (not constant time)
+ }
+ }
+ return valid;
+}
+
diff --git a/tuer-rfid/keystore.h b/tuer-rfid/keystore.h
new file mode 100644
index 0000000..243ab5c
--- /dev/null
+++ b/tuer-rfid/keystore.h
@@ -0,0 +1,33 @@
+/*
+ * spreadspace avr utils
+ *
+ *
+ * Copyright (C) 2013 Christian Pointner <equinox@spreadspace.org>
+ * Othmar Gsenger <otti@wirdorange.org>
+ *
+ * This file is part of spreadspace avr utils.
+ *
+ * spreadspace avr utils is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * spreadspace avr utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef R3TUER_keystore_h_INCLUDED
+#define R3TUER_keystore_h_INCLUDED
+
+#include <stdint.h>
+
+void keystore_flash_from_stdio(void);
+void keystore_dump_to_stdio(void);
+uint8_t keystore_check_card(const uint8_t * uid, uint8_t uid_len);
+
+#endif
diff --git a/tuer-rfid/ledmatrix.c b/tuer-rfid/ledmatrix.c
new file mode 100644
index 0000000..c319b6d
--- /dev/null
+++ b/tuer-rfid/ledmatrix.c
@@ -0,0 +1,218 @@
+/*
+ * spreadspace avr utils
+ *
+ *
+ * Copyright (C) 2013 Christian Pointner <equinox@spreadspace.org>
+ * Othmar Gsenger <otti@wirdorange.org>
+ *
+ * This file is part of spreadspace avr utils.
+ *
+ * spreadspace avr utils is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * spreadspace avr utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <avr/sfr_defs.h>
+#include <avr/interrupt.h>
+
+#include "ledmatrix.h"
+
+#define LEDMATRIX_PORT PORTB
+#define LEDMATRIX_DDR DDRB
+#define LEDMATRIX_RED 6
+#define LEDMATRIX_GREEN 7
+#define LEDMATRIX_NUM_LEDS 6
+#define LEDMATRIX_MASK 0x3F
+#define BLINK_DELAY 3
+
+ledmatrix_mode_t mode = off;
+uint8_t moving_cnt = 0;
+uint8_t wait_cnt = 0;
+
+void ledmatrix_start_timer(void)
+{
+ TCCR3A = 0; // prescaler 1:1024, WGM = 4 (CTC)
+ TCCR3B = 1<<WGM32 | 1<<CS32 | 1<<CS30; //
+ OCR3A = 1561; // (1+1561)*1024 = 1599488 -> ~100 ms @ 16 MHz
+ TCNT3 = 0;
+ TIMSK3 = 1<<OCIE3A;
+}
+
+void ledmatrix_stop_timer(void)
+{
+ TCCR3B = 0;
+ TIMSK3 = 0;
+}
+
+void ledmatrix_off_init(void)
+{
+ LEDMATRIX_PORT = LEDMATRIX_MASK;
+ LEDMATRIX_PORT |= 1<<LEDMATRIX_RED | 1<<LEDMATRIX_GREEN;
+}
+
+
+void ledmatrix_red_init(void)
+{
+ LEDMATRIX_PORT = LEDMATRIX_MASK | 1<<LEDMATRIX_GREEN;
+ LEDMATRIX_PORT &= ~(1<<LEDMATRIX_RED);
+}
+
+
+void ledmatrix_red_moving_init(void)
+{
+ moving_cnt = 0;
+ LEDMATRIX_PORT = (1<<LEDMATRIX_GREEN) | (LEDMATRIX_MASK & (1<<moving_cnt));
+ ledmatrix_start_timer();
+}
+
+void ledmatrix_red_moving_handle(void)
+{
+ moving_cnt++;
+ if(moving_cnt >= LEDMATRIX_NUM_LEDS)
+ moving_cnt = 0;
+ LEDMATRIX_PORT = (1<<LEDMATRIX_GREEN) | (LEDMATRIX_MASK & (1<<moving_cnt));
+}
+
+
+void ledmatrix_red_blink_init(void)
+{
+ wait_cnt = 0;
+ ledmatrix_red_init();
+ ledmatrix_start_timer();
+}
+
+void ledmatrix_red_blink_handle(void)
+{
+ if(++wait_cnt >= BLINK_DELAY) {
+ LEDMATRIX_PORT ^= 1<<LEDMATRIX_RED;
+ wait_cnt = 0;
+ }
+}
+
+
+void ledmatrix_green_init(void)
+{
+ LEDMATRIX_PORT = LEDMATRIX_MASK | 1<<LEDMATRIX_RED;
+ LEDMATRIX_PORT &= ~(1<<LEDMATRIX_GREEN);
+}
+
+
+void ledmatrix_green_moving_init(void)
+{
+ moving_cnt = 0;
+ LEDMATRIX_PORT = (1<<LEDMATRIX_RED) | (LEDMATRIX_MASK & (1<<(LEDMATRIX_NUM_LEDS - moving_cnt - 1)));
+ ledmatrix_start_timer();
+}
+
+void ledmatrix_green_moving_handle(void)
+{
+ moving_cnt++;
+ if(moving_cnt >= LEDMATRIX_NUM_LEDS)
+ moving_cnt = 0;
+ LEDMATRIX_PORT = (1<<LEDMATRIX_RED) | (LEDMATRIX_MASK & (1<<(LEDMATRIX_NUM_LEDS - moving_cnt - 1)));
+}
+
+
+void ledmatrix_green_blink_init(void)
+{
+ wait_cnt = 0;
+ ledmatrix_green_init();
+ ledmatrix_start_timer();
+}
+
+void ledmatrix_green_blink_handle(void)
+{
+ if(++wait_cnt >= BLINK_DELAY) {
+ LEDMATRIX_PORT ^= 1<<LEDMATRIX_GREEN;
+ wait_cnt = 0;
+ }
+}
+
+
+void ledmatrix_rg_moving_init(void)
+{
+ moving_cnt = 0;
+ LEDMATRIX_PORT = (1<<LEDMATRIX_GREEN) | (LEDMATRIX_MASK & (1<<moving_cnt));
+ ledmatrix_start_timer();
+}
+
+void ledmatrix_rg_moving_handle(void)
+{
+ moving_cnt++;
+ if(moving_cnt >= 2*LEDMATRIX_NUM_LEDS)
+ moving_cnt = 0;
+
+ if(moving_cnt >= LEDMATRIX_NUM_LEDS) {
+ uint8_t offset = moving_cnt - LEDMATRIX_NUM_LEDS;
+ LEDMATRIX_PORT = (1<<LEDMATRIX_RED) | (LEDMATRIX_MASK & (1<<(LEDMATRIX_NUM_LEDS - offset - 1)));
+ } else {
+ LEDMATRIX_PORT = (1<<LEDMATRIX_GREEN) | (LEDMATRIX_MASK & (1<<moving_cnt));
+ }
+}
+
+
+void ledmatrix_rg_blink_init(void)
+{
+ wait_cnt = 0;
+ ledmatrix_red_init();
+ ledmatrix_start_timer();
+}
+
+void ledmatrix_rg_blink_handle(void)
+{
+ if(++wait_cnt >= BLINK_DELAY) {
+ LEDMATRIX_PORT ^= ~(LEDMATRIX_MASK);
+ wait_cnt = 0;
+ }
+}
+
+
+void ledmatrix_init(void)
+{
+ LEDMATRIX_DDR = 0xFF;
+ LEDMATRIX_PORT = 0xFF;
+}
+
+void ledmatrix_set(ledmatrix_mode_t m)
+{
+ if(m == mode)
+ return;
+
+ mode = m;
+ ledmatrix_stop_timer();
+ switch(mode)
+ {
+ case off: ledmatrix_off_init(); break;
+ case red: ledmatrix_red_init(); break;
+ case red_moving: ledmatrix_red_moving_init(); break;
+ case red_blink: ledmatrix_red_blink_init(); break;
+ case green: ledmatrix_green_init(); break;
+ case green_moving: ledmatrix_green_moving_init(); break;
+ case green_blink: ledmatrix_green_blink_init(); break;
+ case rg_moving: ledmatrix_rg_moving_init(); break;
+ case rg_blink: ledmatrix_rg_blink_init(); break;
+ }
+}
+
+ISR(TIMER3_COMPA_vect)
+{
+ switch(mode)
+ {
+ case red_moving: ledmatrix_red_moving_handle(); break;
+ case red_blink: ledmatrix_red_blink_handle(); break;
+ case green_moving: ledmatrix_green_moving_handle(); break;
+ case green_blink: ledmatrix_green_blink_handle(); break;
+ case rg_moving: ledmatrix_rg_moving_handle(); break;
+ case rg_blink: ledmatrix_rg_blink_handle(); break;
+ default: break;
+ }
+}
diff --git a/tuer-rfid/ledmatrix.h b/tuer-rfid/ledmatrix.h
new file mode 100644
index 0000000..4ecbd8f
--- /dev/null
+++ b/tuer-rfid/ledmatrix.h
@@ -0,0 +1,34 @@
+/*
+ * spreadspace avr utils
+ *
+ *
+ * Copyright (C) 2013 Christian Pointner <equinox@spreadspace.org>
+ * Othmar Gsenger <otti@wirdorange.org>
+ *
+ * This file is part of spreadspace avr utils.
+ *
+ * spreadspace avr utils is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * spreadspace avr utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef R3TUER_ledmatrix_h_INCLUDED
+#define R3TUER_ledmatrix_h_INCLUDED
+
+typedef enum { off, red, red_moving, red_blink,
+ green, green_moving, green_blink,
+ rg_moving, rg_blink } ledmatrix_mode_t;
+
+void ledmatrix_init(void);
+void ledmatrix_set(ledmatrix_mode_t mode);
+
+#endif
diff --git a/tuer-rfid/limits.c b/tuer-rfid/limits.c
new file mode 100644
index 0000000..027a3b5
--- /dev/null
+++ b/tuer-rfid/limits.c
@@ -0,0 +1,103 @@
+/*
+ * spreadspace avr utils
+ *
+ *
+ * Copyright (C) 2013 Christian Pointner <equinox@spreadspace.org>
+ * Othmar Gsenger <otti@wirdorange.org>
+ *
+ * This file is part of spreadspace avr utils.
+ *
+ * spreadspace avr utils is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * spreadspace avr utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <avr/io.h>
+#include "limits.h"
+
+#define LIMITS_PIN PINC
+#define LIMITS_PORT PORTC
+#define LIMITS_DDR DDRC
+#define LIMITS_OPEN 6
+#define LIMITS_CLOSE 7
+
+#define LIMITS_LP_MAX 255
+
+void limits_init(void)
+{
+ LIMITS_DDR = LIMITS_DDR & ~(1<<LIMITS_OPEN | 1<<LIMITS_CLOSE);
+ LIMITS_PORT |= (1<<LIMITS_OPEN | 1<<LIMITS_CLOSE);
+}
+
+uint8_t limits_get_close(uint8_t pin)
+{
+ static uint8_t last_state = 1<<LIMITS_CLOSE;
+ static uint8_t lp_cnt = 0;
+
+ uint8_t state = pin & (1<<LIMITS_CLOSE);
+ if(state != last_state)
+ lp_cnt++;
+ else
+ lp_cnt += lp_cnt ? -1 : 0;
+
+ if(lp_cnt >= LIMITS_LP_MAX) {
+ last_state = state;
+ lp_cnt = 0;
+ }
+
+ return last_state;
+}
+
+uint8_t limits_get_open(uint8_t pin)
+{
+ static uint8_t last_state = 1<<LIMITS_OPEN;
+ static uint8_t lp_cnt = 0;
+
+ uint8_t state = pin & (1<<LIMITS_OPEN);
+ if(state != last_state)
+ lp_cnt++;
+ else
+ lp_cnt += lp_cnt ? -1 : 0;
+
+ if(lp_cnt >= LIMITS_LP_MAX) {
+ last_state = state;
+ lp_cnt = 0;
+ }
+
+ return last_state;
+}
+
+limits_t limits_get(void)
+{
+ uint8_t tmp = LIMITS_PIN & (1<<LIMITS_OPEN | 1<<LIMITS_CLOSE);
+ if(!limits_get_open(tmp)) {
+ if(limits_get_close(tmp))
+ return open;
+ else
+ return both;
+ }
+ else if(!limits_get_close(tmp))
+ return close;
+
+ return moving;
+}
+
+const char* limits_to_string(limits_t limits)
+{
+ switch(limits) {
+ case moving: return "...";
+ case open: return "opened";
+ case close: return "closed";
+ case both: return "error";
+ }
+ return "invalid"; // gcc - shut the fuck up!!!
+}
diff --git a/tuer-rfid/limits.h b/tuer-rfid/limits.h
new file mode 100644
index 0000000..f1363ab
--- /dev/null
+++ b/tuer-rfid/limits.h
@@ -0,0 +1,33 @@
+/*
+ * spreadspace avr utils
+ *
+ *
+ * Copyright (C) 2013 Christian Pointner <equinox@spreadspace.org>
+ * Othmar Gsenger <otti@wirdorange.org>
+ *
+ * This file is part of spreadspace avr utils.
+ *
+ * spreadspace avr utils is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * spreadspace avr utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef R3TUER_limits_h_INCLUDED
+#define R3TUER_limits_h_INCLUDED
+
+typedef enum { moving, open, close, both } limits_t;
+
+void limits_init(void);
+limits_t limits_get(void);
+const char* limits_to_string(limits_t limits);
+
+#endif
diff --git a/tuer-rfid/manual.c b/tuer-rfid/manual.c
new file mode 100644
index 0000000..1423939
--- /dev/null
+++ b/tuer-rfid/manual.c
@@ -0,0 +1,58 @@
+/*
+ * spreadspace avr utils
+ *
+ *
+ * Copyright (C) 2013 Christian Pointner <equinox@spreadspace.org>
+ * Othmar Gsenger <otti@wirdorange.org>
+ *
+ * This file is part of spreadspace avr utils.
+ *
+ * spreadspace avr utils is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * spreadspace avr utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <avr/io.h>
+#include "manual.h"
+#include "eventqueue.h"
+
+#define MANUAL_PIN PINF
+#define MANUAL_PORT PORTF
+#define MANUAL_DDR DDRF
+#define MANUAL_BIT 0
+
+#define MANUAL_LP_MAX 255
+
+void manual_init(void)
+{
+ MANUAL_DDR = MANUAL_DDR & ~(1<<MANUAL_BIT);
+ MANUAL_PORT |= (1<<MANUAL_BIT);
+}
+
+void manual_task(void)
+{
+ static uint8_t last_state = (1<<MANUAL_BIT);
+ static uint8_t lp_cnt = 0;
+
+ uint8_t state = MANUAL_PIN & (1<<MANUAL_BIT);
+ if(state != last_state)
+ lp_cnt++;
+ else
+ lp_cnt += lp_cnt ? -1 : 0;
+
+ if(lp_cnt >= MANUAL_LP_MAX) {
+ if(!state)
+ eventqueue_push(btn_toggle);
+ last_state = state;
+ lp_cnt = 0;
+ }
+}
diff --git a/tuer-rfid/manual.h b/tuer-rfid/manual.h
new file mode 100644
index 0000000..5143af0
--- /dev/null
+++ b/tuer-rfid/manual.h
@@ -0,0 +1,30 @@
+/*
+ * spreadspace avr utils
+ *
+ *
+ * Copyright (C) 2013 Christian Pointner <equinox@spreadspace.org>
+ * Othmar Gsenger <otti@wirdorange.org>
+ *
+ * This file is part of spreadspace avr utils.
+ *
+ * spreadspace avr utils is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * spreadspace avr utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef R3TUER_manual_h_INCLUDED
+#define R3TUER_manual_h_INCLUDED
+
+void manual_init(void);
+void manual_task(void);
+
+#endif
diff --git a/tuer-rfid/sl018.c b/tuer-rfid/sl018.c
new file mode 100644
index 0000000..9916e36
--- /dev/null
+++ b/tuer-rfid/sl018.c
@@ -0,0 +1,245 @@
+/*
+ * spreadspace avr utils
+ *
+ *
+ * Copyright (C) 2013 Christian Pointner <equinox@spreadspace.org>
+ * Othmar Gsenger <otti@wirdorange.org>
+ *
+ * This file is part of spreadspace avr utils.
+ *
+ * spreadspace avr utils is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * spreadspace avr utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sl018.h"
+#include "LUFA/Drivers/Peripheral/TWI.h"
+#include <stdio.h>
+#include <util/delay.h>
+
+#define SL018_TWI_ADDR 0xA0
+#define SL018_TAG_STA_PIN PIND
+#define SL018_TAG_STA_BIT 7
+#define CARD_PRESENT (!((SL018_TAG_STA_PIN >> SL018_TAG_STA_BIT) & 1))
+#define MAX_UID_LEN 7
+
+
+const char* SL018_cmd_tostring(const uint8_t cmd)
+{
+ switch(cmd) {
+ case 0x01: return "Select Mifare card";
+ case 0x02: return "Login to a sector";
+ case 0x03: return "Read a data block";
+ case 0x04: return "Write a data block";
+ case 0x05: return "Read a value block";
+ case 0x06: return "Initialize a value block";
+ case 0x07: return "Write master key";
+ case 0x08: return "Increment value";
+ case 0x09: return "Decrement value";
+ case 0x0A: return "Copy value";
+ case 0x10: return "Read a data page";
+ case 0x11: return "Write a data page";
+ case 0x40: return "Control the red led";
+ case 0xF0: return "Get firmware version";
+ case 0xFF: return "Reset";
+ default: return "unknown";
+ }
+}
+
+const char* SL018_status_tostring(const uint8_t status)
+{
+ switch(status) {
+ case 0x0: return "Operation succeed";
+ case 0x1: return "No tag";
+ case 0x2: return "Login succeed";
+ case 0x3: return "Login fail";
+ case 0x4: return "Read fail";
+ case 0x5: return "Write fail";
+ case 0x6: return "Unable to read after write";
+ case 0xA: return "Collision occur";
+ case 0xC: return "Load key fail";
+ case 0xD: return "Not authenticate";
+ case 0xE: return "Not a value block";
+ default: return "unknown";
+ }
+}
+
+const char* SL018_tagtype_tostring(const uint8_t type)
+{
+ switch(type) {
+ case 0x1: return "Mifare 1k, 4 byte UID";
+ case 0x2: return "Mifare 1k, 7 byte UID";
+ case 0x3: return "Mifare Ultralight or NATG203, 7 byte UID";
+ case 0x4: return "Mifare 4k, 4 byte UID";
+ case 0x5: return "Mifare 4k, 7 byte UID";
+ case 0x6: return "Mifare DesFire, 7 byte UID";
+ default: return "unknown";
+ }
+}
+
+uint8_t SL018_tagtype_to_uidlen(const uint8_t type)
+{
+ switch(type) {
+ case 0x1:
+ case 0x4: return 4;
+ case 0x2:
+ case 0x3:
+ case 0x5:
+ case 0x6: return 7;
+ default: return 0;
+ }
+}
+
+const uint8_t SL018_CMD_ComSelectCard[] = {1,0x01};
+const uint8_t SL018_CMD_ComRedLedOn[] = {2,0x40,1};
+const uint8_t SL018_CMD_ComRedLedOff[] = {2,0x40,0};
+const uint8_t SL018_CMD_ComGetFirmwareVersion[] = {1,0xF0};
+const uint8_t SL018_CMD_ComReset[] = {1,0xFF};
+
+uint8_t twi_recv_buf[256];
+typedef struct __attribute__((__packed__))
+{
+ uint8_t len;
+ uint8_t command;
+ uint8_t status;
+ uint8_t data[sizeof(twi_recv_buf)-3];
+} sl018_message_t;
+
+sl018_message_t* twi_recv_msg = (sl018_message_t *)&twi_recv_buf;
+
+
+uint8_t sl018_cmd_raw(const uint8_t* twi_send_buf, bool wait_for_answer)
+{
+ uint8_t pos = 0;
+
+ if (TWI_StartTransmission(SL018_TWI_ADDR | TWI_ADDRESS_WRITE,10) == TWI_ERROR_NoError) {
+ for(pos=0; pos<=twi_send_buf[0]; pos++) {
+ if( ! TWI_SendByte(twi_send_buf[pos])) {
+ TWI_StopTransmission();
+ return 1;
+ }
+ }
+ TWI_StopTransmission();
+ } else
+ return 1;
+
+ if(!wait_for_answer) return 0;
+
+ memset(twi_recv_buf, 0, sizeof(twi_recv_buf));
+ _delay_ms(50);
+
+ if (TWI_StartTransmission(SL018_TWI_ADDR | TWI_ADDRESS_READ,10) == TWI_ERROR_NoError) {
+ TWI_ReceiveByte(twi_recv_buf, 0);
+ for(pos=1; pos<=twi_recv_buf[0]; pos++) {
+ if (! TWI_ReceiveByte(&twi_recv_buf[pos], (pos == twi_recv_buf[0]) ? 1:0 ) ) {
+ TWI_StopTransmission();
+ return 1;
+ }
+ }
+ TWI_StopTransmission();
+ } else
+ return 1;
+
+ return 0;
+}
+
+uint8_t sl018_reset(void)
+{
+ if(sl018_cmd_raw(SL018_CMD_ComReset, 0)) {
+ printf("Error(i2c): bus error\n\r");
+ return 1;
+ }
+ return 0;
+}
+
+uint8_t sl018_cmd(const uint8_t* twi_send_buf)
+{
+ if(sl018_cmd_raw(twi_send_buf, 1)) {
+ printf("Error(i2c): bus error\n\r");
+ return 1;
+ } else {
+ if(twi_recv_msg->len < 2) {
+ printf("Error(SL018): short message received\n\r");
+ return 1;
+ }
+ if(twi_recv_msg->status) {
+ printf("Error(SL018): '%s','%s'\n\r",SL018_cmd_tostring(twi_recv_msg->command),SL018_status_tostring(twi_recv_msg->status));
+ return 1;
+ }
+ sl018_message_t * twi_send_msg = (sl018_message_t *)twi_send_buf;
+ if(twi_send_msg->command != twi_recv_msg->command) {
+ printf("Error(SL018): mismatch of sent and received command code: %02X,%02X\n\r",twi_send_msg->command,twi_recv_msg->command);
+ }
+ }
+ return 0;
+}
+
+void sl018_read_card_uid(uid_t * uid)
+{
+ uid->length=0;
+ uid->buffer=NULL;
+ printf( "Info(card): ");
+ if(!sl018_cmd(SL018_CMD_ComSelectCard))
+ {
+ uint8_t uid_len = twi_recv_msg->len - sizeof(twi_recv_msg->command) - sizeof(twi_recv_msg->status) - 1;
+ if(uid_len == 255 || uid_len > MAX_UID_LEN) {
+ printf(" received UID length (%d) is to big for keystore \n\r", uid_len);
+ return;
+ }
+ uint8_t type = twi_recv_msg->data[uid_len];
+ uint8_t expected_uid_len = SL018_tagtype_to_uidlen(type);
+ if(expected_uid_len != uid_len) {
+ printf(" Invalid uid length (%d) for tag type: %s\n\r", uid_len, SL018_tagtype_tostring(type));
+ return;
+ }
+
+ for (uint8_t pos=0; pos<uid_len; pos++)
+ printf("%02X",twi_recv_msg->data[uid_len-pos-1]);
+ printf( ", %s\n\r", SL018_tagtype_tostring(type));
+
+ if (0 < type && type < 7) {
+ uid->length= uid_len;
+ uid->buffer=twi_recv_msg->data;
+ } else {
+ printf("Info(card): Ignoring unknown card type %02x\n\r",type);
+ }
+ }
+}
+
+void sl018_set_led(uint8_t on)
+{
+ if(on)
+ sl018_cmd(SL018_CMD_ComRedLedOn);
+ else
+ sl018_cmd(SL018_CMD_ComRedLedOff);
+}
+
+uint8_t sl018_check_for_new_card(void)
+{
+ static uint8_t card_status = 0;
+ if(CARD_PRESENT != card_status) {
+ card_status = CARD_PRESENT;
+ if(card_status)
+ return 1;
+ }
+ return 0;
+}
+
+unsigned char * sl018_get_firmware_version(void)
+{
+ if(!sl018_cmd(SL018_CMD_ComGetFirmwareVersion)) {
+ twi_recv_msg->data[sizeof(twi_recv_msg->data) - 1] = 0;
+ return twi_recv_msg->data;
+ } else {
+ return NULL;
+ }
+}
diff --git a/tuer-rfid/sl018.h b/tuer-rfid/sl018.h
new file mode 100644
index 0000000..d3f3068
--- /dev/null
+++ b/tuer-rfid/sl018.h
@@ -0,0 +1,40 @@
+/*
+ * spreadspace avr utils
+ *
+ *
+ * Copyright (C) 2013 Christian Pointner <equinox@spreadspace.org>
+ * Othmar Gsenger <otti@wirdorange.org>
+ *
+ * This file is part of spreadspace avr utils.
+ *
+ * spreadspace avr utils is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * spreadspace avr utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef R3TUER_sl018_h_INCLUDED
+#define R3TUER_sl018_h_INCLUDED
+
+#include <stdint.h>
+
+typedef struct {
+ uint8_t length;
+ unsigned char * buffer;
+} uid_t;
+
+void sl018_set_led(uint8_t on);
+uint8_t sl018_check_for_new_card(void);
+void sl018_read_card_uid(uid_t * uid);
+uint8_t sl018_reset(void);
+unsigned char * sl018_get_firmware_version(void);
+
+#endif
diff --git a/tuer-rfid/statemachine.c b/tuer-rfid/statemachine.c
new file mode 100644
index 0000000..b83fbec
--- /dev/null
+++ b/tuer-rfid/statemachine.c
@@ -0,0 +1,185 @@
+/*
+ * spreadspace avr utils
+ *
+ *
+ * Copyright (C) 2013 Christian Pointner <equinox@spreadspace.org>
+ * Othmar Gsenger <otti@wirdorange.org>
+ *
+ * This file is part of spreadspace avr utils.
+ *
+ * spreadspace avr utils is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * spreadspace avr utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "statemachine.h"
+#include "stepper.h"
+#include "eventqueue.h"
+#include "limits.h"
+#include "ledmatrix.h"
+#include <stdio.h>
+
+typedef enum {reset, closed, closing, opened, opening, timeout_after_open, timeout_after_close, error, manual_movement} state_t;
+state_t state = reset;
+
+const char* state_to_string(state_t s)
+{
+ switch(s) {
+ case reset: return "reset";
+ case error: return "error";
+ case closing: return "closing";
+ case opening: return "opening";
+ case manual_movement: return "manual movement";
+ case timeout_after_open: return "timeout after open";
+ case timeout_after_close: return "timeout after close";
+ case closed: return "closed";
+ case opened: return "opened";
+ }
+ return "invalid"; // gcc - shut the fuck up!!!
+}
+
+void change_state(state_t new_state)
+{
+ if (new_state == state)
+ return;
+ printf("State: %s\n\r", state_to_string(new_state));
+ switch(new_state) {
+ case reset:
+ break;
+ case closed: ledmatrix_set(red); break;
+ case closing:
+ ledmatrix_set(red_moving);
+ stepper_start(dir_close);
+ break;
+ case opened: ledmatrix_set(green); break;
+ case opening:
+ ledmatrix_set(green_moving);
+ stepper_start(dir_open);
+ break;
+ case timeout_after_open: ledmatrix_set(green_blink); break;
+ case timeout_after_close: ledmatrix_set(red_blink); break;
+ case error: ledmatrix_set(rg_blink); break;
+ case manual_movement: ledmatrix_set(rg_moving); break;
+ break;
+ }
+ state = new_state;
+}
+
+void statemachine_task_limits(void)
+{
+ limits_t limits = limits_get();
+ if (limits == both)
+ return change_state(error);
+
+ switch(state) {
+ case reset:
+ switch(limits) {
+ case open:
+ return change_state(opened);
+ case close:
+ return change_state(closed);
+ default:
+ return change_state(closing);
+ }
+ case error:
+ case closed:
+ case opened:
+ switch(limits) {
+ case open:
+ return change_state(opened);
+ case close:
+ return change_state(closed);
+ default:
+ return change_state(manual_movement);
+ }
+ case manual_movement:
+ case timeout_after_open:
+ case timeout_after_close:
+ switch(limits) {
+ case open:
+ return change_state(opened);
+ case close:
+ return change_state(closed);
+ default:
+ return;
+ }
+ case closing:
+ break;
+ case opening:
+ break;
+ }
+}
+
+void statemachine_task_event(void)
+{
+ event_t event = eventqueue_pop();
+ if(event == none)
+ return;
+
+ switch(state) {
+ case closing:
+ case opening:
+ switch(event) {
+ case open_fin:
+ return change_state(opened);
+ case close_fin:
+ return change_state(closed);
+ case move_timeout:
+ return change_state(state==opening?timeout_after_open:timeout_after_close);
+ default:
+ printf("Error(state): event %s not allowed in state %s\n\r", event_to_string(event), state_to_string(state));
+ return;
+ }
+ case reset:
+ case error:
+ printf("Error(state): Not accepting commands in state %s\n\r", state_to_string(state));
+ break; // Not accepting commands
+ case manual_movement:
+ case timeout_after_open:
+ case timeout_after_close:
+ case closed:
+ case opened:
+ switch(event) {
+ case none:
+ return;
+ case cmd_open:
+ return change_state(opening);
+ case cmd_close:
+ return change_state(closing);
+ case cmd_toggle:
+ case btn_toggle:
+ case card:
+ return change_state(
+ (state==closed || state == timeout_after_close) ?
+ opening:
+ closing);
+ case open_fin:
+ case close_fin:
+ case move_timeout:
+ printf("Error(state): event %s not allowed in state %s\n\r", event_to_string(event), state_to_string(state));
+ return;
+ }
+ }
+
+}
+
+void statemachine_task(void)
+{
+ statemachine_task_limits();
+ statemachine_task_event();
+}
+
+const char* statemachine_get_state_as_string(void)
+{
+ return state_to_string(state);
+}
diff --git a/tuer-rfid/statemachine.dot b/tuer-rfid/statemachine.dot
new file mode 100644
index 0000000..d581de8
--- /dev/null
+++ b/tuer-rfid/statemachine.dot
@@ -0,0 +1,45 @@
+digraph G {
+ reset [shape=box];
+ toggle [shape=diamond];
+ btn_toggle [shape=diamond];
+ cmd_toggle [shape=diamond];
+ card [shape=diamond];
+ card ->toggle;
+ btn_toggle ->toggle;
+ cmd_toggle ->toggle;
+ all_states [shape=box];
+ opened [shape=box];
+ closed [shape=box];
+ opening [shape=box];
+ closing [shape=box];
+ timeout_after_open [shape=box];
+ timeout_after_close [shape=box];
+ manual_movement [shape=box];
+ error [shape=box];
+ reset -> closed [label="limit_closed"];
+ reset -> closing [label="limit_none"];
+ reset -> opened [label="limit_opened"];
+ error -> closed [label="limit_closed"];
+ error -> opened [label="limit_opened"];
+ error -> manual_movement [label="limit_none"];
+ manual_movement -> opening [label="cmd_open"];
+ manual_movement -> closing [label="cmd_close"];
+ manual_movement -> closing [label="toggle"];
+ opened -> closing [label="cmd_close"];
+ opened -> closing [label="toggle"];
+ closed -> opening [label="cmd_open"];
+ closed -> opening [label="toggle"];
+ opening -> opened [label="open_fin"];
+ closing -> closed [label="close_fin"];
+ closing -> timeout_after_close [label="timeout"];
+ opening -> timeout_after_open [label="timeout"];
+ timeout_after_open -> closing [label="cmd_close"];
+ timeout_after_open -> closing [label="toggle"];
+ timeout_after_open -> opened [label="limit_open"];
+ timeout_after_open -> closed [label="limit_close"];
+ timeout_after_close -> opening [label="cmd_open"];
+ timeout_after_close -> opening [label="toggle"];
+ timeout_after_close -> opened [label="limit_open"];
+ timeout_after_close -> closed [label="limit_close"];
+ all_states -> error [label="limit_both"];
+}
diff --git a/tuer-rfid/statemachine.h b/tuer-rfid/statemachine.h
new file mode 100644
index 0000000..90b478c
--- /dev/null
+++ b/tuer-rfid/statemachine.h
@@ -0,0 +1,30 @@
+/*
+ * spreadspace avr utils
+ *
+ *
+ * Copyright (C) 2013 Christian Pointner <equinox@spreadspace.org>
+ * Othmar Gsenger <otti@wirdorange.org>
+ *
+ * This file is part of spreadspace avr utils.
+ *
+ * spreadspace avr utils is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * spreadspace avr utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef R3TUER_statemachine_h_INCLUDED
+#define R3TUER_statemachine_h_INCLUDED
+
+void statemachine_task(void);
+const char* statemachine_get_state_as_string(void);
+
+#endif
diff --git a/tuer-rfid/stepper.c b/tuer-rfid/stepper.c
new file mode 100644
index 0000000..d26815a
--- /dev/null
+++ b/tuer-rfid/stepper.c
@@ -0,0 +1,116 @@
+/*
+ * spreadspace avr utils
+ *
+ *
+ * Copyright (C) 2013 Christian Pointner <equinox@spreadspace.org>
+ * Othmar Gsenger <otti@wirdorange.org>
+ *
+ * This file is part of spreadspace avr utils.
+ *
+ * spreadspace avr utils is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * spreadspace avr utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <avr/sfr_defs.h>
+#include <avr/interrupt.h>
+
+#include "stepper.h"
+#include "limits.h"
+#include "eventqueue.h"
+
+uint8_t step_table [] =
+{
+ 10, // 1010
+ 9, // 1001
+ 5, // 0101
+ 6, // 0110
+};
+
+#define STEPPER_PORT PORTF
+#define STEPPER_DDR DDRF
+#define STEPPER_FIRST_BIT 4
+#define STEPPER_ENABLE_BIT 1
+#define LENGTH_STEP_TABLE (sizeof(step_table)/sizeof(uint8_t))
+#define STEPPER_OUTPUT_BITMASK (~(0xF << STEPPER_FIRST_BIT ))
+
+volatile uint16_t step_cnt = 0;
+#define STEP_CNT_STOP (LENGTH_STEP_TABLE*400)
+#define STEP_CNT_OFF (STEP_CNT_STOP + 125)
+stepper_direction_t step_direction = dir_open;
+
+inline void stepper_stop(void)
+{
+ STEPPER_PORT &= ~(0xF << STEPPER_FIRST_BIT | 1<<STEPPER_ENABLE_BIT);
+ TCCR1B = 0; // no clock source
+ TIMSK1 = 0; // disable timer interrupt
+}
+
+static inline uint8_t stepper_handle(void)
+{
+ static uint8_t step_idx = 0;
+
+ limits_t l = limits_get();
+ if((step_direction == dir_open && l == open) ||
+ (step_direction == dir_close && l == close) || l == both)
+ step_cnt = STEP_CNT_STOP + 1;
+
+ if(step_cnt < STEP_CNT_STOP) {
+ step_idx += (step_direction == dir_open) ? 1 : -1;
+ step_idx %= LENGTH_STEP_TABLE;
+ } else if(step_cnt == STEP_CNT_STOP) {
+ eventqueue_push(move_timeout);
+ return 0;
+ }
+
+ uint8_t stepper_output = step_table[step_idx];
+ stepper_output <<= STEPPER_FIRST_BIT;
+ STEPPER_PORT = (STEPPER_PORT & STEPPER_OUTPUT_BITMASK ) | stepper_output;
+
+ step_cnt++;
+ if(step_cnt >= STEP_CNT_OFF) {
+ if(step_direction == dir_open)
+ eventqueue_push(open_fin);
+ else
+ eventqueue_push(close_fin);
+
+ return 0;
+ }
+
+ return 1;
+}
+
+void stepper_init(void)
+{
+ STEPPER_PORT &= ~(0xF << STEPPER_FIRST_BIT | 1<<STEPPER_ENABLE_BIT);
+ STEPPER_DDR |= (0xF << STEPPER_FIRST_BIT) | (1<<STEPPER_ENABLE_BIT);
+}
+
+uint8_t stepper_start(stepper_direction_t direction)
+{
+ step_cnt = 0;
+ step_direction = direction;
+ STEPPER_PORT |= 1<<STEPPER_ENABLE_BIT;
+ TCCR1A = 0; // prescaler 1:256, WGM = 4 (CTC)
+ TCCR1B = 1<<WGM12 | 1<<CS12; //
+ OCR1A = 124; // (1+124)*256 = 32000 -> 2 ms @ 16 MHz
+ TCNT1 = 0;
+ TIMSK1 = 1<<OCIE1A;
+
+ return 1;
+}
+
+ISR(TIMER1_COMPA_vect)
+{
+ if(!stepper_handle())
+ stepper_stop();
+}
diff --git a/tuer-rfid/stepper.h b/tuer-rfid/stepper.h
new file mode 100644
index 0000000..df8d38d
--- /dev/null
+++ b/tuer-rfid/stepper.h
@@ -0,0 +1,32 @@
+/*
+ * spreadspace avr utils
+ *
+ *
+ * Copyright (C) 2013 Christian Pointner <equinox@spreadspace.org>
+ * Othmar Gsenger <otti@wirdorange.org>
+ *
+ * This file is part of spreadspace avr utils.
+ *
+ * spreadspace avr utils is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * spreadspace avr utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef R3TUER_stepper_h_INCLUDED
+#define R3TUER_stepper_h_INCLUDED
+#include <stdint.h>
+typedef enum { dir_open = 0, dir_close = 1 } stepper_direction_t;
+
+void stepper_init(void);
+uint8_t stepper_start(stepper_direction_t direction);
+
+#endif
diff --git a/tuer-rfid/tuer-rfid.c b/tuer-rfid/tuer-rfid.c
new file mode 100644
index 0000000..f3cf21b
--- /dev/null
+++ b/tuer-rfid/tuer-rfid.c
@@ -0,0 +1,153 @@
+/*
+ * spreadspace avr utils
+ *
+ *
+ * Copyright (C) 2013 Christian Pointner <equinox@spreadspace.org>
+ * Othmar Gsenger <otti@wirdorange.org>
+ *
+ * This file is part of spreadspace avr utils.
+ *
+ * spreadspace avr utils is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * spreadspace avr utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <avr/io.h>
+#include <avr/wdt.h>
+#include <avr/interrupt.h>
+#include <avr/power.h>
+#include "LUFA/Drivers/Peripheral/TWI.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "util.h"
+#include "led.h"
+#include "anyio.h"
+
+#include "heartbeat.h"
+#include "stepper.h"
+#include "ledmatrix.h"
+#include "sl018.h"
+#include "keystore.h"
+#include "statemachine.h"
+#include "eventqueue.h"
+#include "limits.h"
+#include "manual.h"
+#include "ajar.h"
+
+void handle_cmd(uint8_t cmd)
+{
+ switch(cmd) {
+ case 'r':
+ reset2bootloader();
+ break;
+ case 'R':
+ if(!sl018_reset())
+ printf("ok\n\r");
+ break;
+ case 'f': {
+ unsigned char * firmware_str = sl018_get_firmware_version();
+ if(firmware_str)
+ printf("%s\n\r",firmware_str);
+
+ break;
+ }
+ case 'e': //flash eeprom
+ keystore_flash_from_stdio();
+ break;
+ case 'd': //dump eeprom - this breaks security!
+ keystore_dump_to_stdio();
+ break;
+ case 'o':
+ eventqueue_push(cmd_open);
+ break;
+ case 'c':
+ eventqueue_push(cmd_close);
+ break;
+ case 't':
+ eventqueue_push(cmd_toggle);
+ break;
+ case 's':
+ printf("Status: %s, %s, %s\n\r", limits_to_string(limits_get()), statemachine_get_state_as_string(), ajar_to_string(ajar_get()));
+ break;
+ /* case '0': ledmatrix_set(off); break; */
+ /* case '1': ledmatrix_set(red); break; */
+ /* case '2': ledmatrix_set(red_moving); break; */
+ /* case '3': ledmatrix_set(red_blink); break; */
+ /* case '4': ledmatrix_set(green); break; */
+ /* case '5': ledmatrix_set(green_moving); break; */
+ /* case '6': ledmatrix_set(green_blink); break; */
+ /* case '7': ledmatrix_set(rg_moving); break; */
+ /* case '8': ledmatrix_set(rg_blink); break; */
+ default: printf("Error(cmd): unknown command %02X '%c'\n\r", cmd, cmd); return;
+ }
+}
+
+void handle_card(void)
+{
+ uid_t uid;
+ sl018_read_card_uid(&uid);
+ if (uid.length)
+ {
+ printf("Info(card): card(");
+ for (uint8_t pos=0; pos<uid.length; pos++)
+ printf("%02X",uid.buffer[uid.length-pos-1]);
+ printf(") ");
+
+ if(keystore_check_card(uid.buffer,uid.length)) {
+ printf("found - opening/closing door\n\r");
+ eventqueue_push(card);
+ } else {
+ printf("not found - ignoring\n\r");
+ }
+ }
+}
+
+int main(void)
+{
+ MCUSR &= ~(1 << WDRF);
+ wdt_disable();
+
+ cpu_init();
+ led_init();
+ anyio_init(115200, false);
+ TWI_Init(TWI_BIT_PRESCALE_1, TWI_BITLENGTH_FROM_FREQ(1, 200000));
+
+ heartbeat_init();
+ stepper_init();
+ ledmatrix_init();
+ eventqueue_init();
+ limits_init();
+ manual_init();
+ ajar_init();
+ sei();
+
+ sl018_reset();
+
+ for(;;) {
+ statemachine_task();
+
+ anyio_task();
+ manual_task();
+ ajar_task();
+
+ int16_t bytes_received = anyio_bytes_received();
+ if(bytes_received > 0)
+ handle_cmd(fgetc(stdin));
+
+ if (sl018_check_for_new_card())
+ handle_card();
+
+ heartbeat_task();
+ }
+}
diff --git a/tuer-rfid/update-keys.c b/tuer-rfid/update-keys.c
new file mode 100644
index 0000000..d4dfd06
--- /dev/null
+++ b/tuer-rfid/update-keys.c
@@ -0,0 +1,138 @@
+/*
+ * spreadspace avr utils
+ *
+ *
+ * Copyright (C) 2013 Christian Pointner <equinox@spreadspace.org>
+ *
+ * This file is part of spreadspace avr utils.
+ *
+ * spreadspace avr utils is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * spreadspace avr utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdint.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <termios.h>
+
+#define EEPROM_SIZE 1024
+typedef uint8_t keyslot_t[8];
+
+/* this generates a Fletcher8 checksum */
+/* code from: http://stackoverflow.com/questions/13491700/8-bit-fletcher-checksum-of-16-byte-data */
+uint8_t generate_csum(keyslot_t data)
+{
+ uint16_t sum1 = 0xf, sum2 = 0xf, len = sizeof(keyslot_t)-1;
+ do { sum2 += ( sum1 += *data++ ); } while (--len);
+ return sum2<<4 | sum1;
+}
+
+int send_key(keyslot_t key, FILE* dev)
+{
+ fwrite(key, sizeof(keyslot_t), 1, dev);
+ fflush(dev);
+ char tmp;
+ while(fread(&tmp, 1, 1, dev)) {
+ fwrite(&tmp, 1, 1, stdout);
+ if(tmp == 0) return 1;
+ if(tmp == '.') return 0;
+ }
+ return 0;
+}
+
+int main(int argc, char* argv[])
+{
+ if(argc<2) {
+ fprintf(stderr, "Usage: update-keys <device>\n");
+ return -1;
+ }
+
+ FILE* dev;
+ dev = fopen(argv[1], "r+");
+ if(!dev) {
+ fprintf(stderr, "fopen failed!\n");
+ return -2;
+ }
+
+ int fd = fileno(dev);
+ struct termios t;
+ tcgetattr(fd, &t);
+ t.c_lflag &= ~(ICANON | ECHO);
+ t.c_iflag &= ~(ICRNL | INLCR | IXON | IXOFF);
+ cfmakeraw(&t);
+ tcflush(fd, TCIOFLUSH);
+ tcsetattr(fd, TCSANOW, &t);
+
+ fprintf(dev, "e");
+
+ char* line = NULL;
+ size_t len = 0;
+ int line_num = 0;
+ keyslot_t key;
+ int key_num = 0;
+
+ for(;;) {
+ ssize_t ret = getline(&line, &len, stdin);
+ if(ret <= 0) break;
+ line_num++;
+
+ int i;
+ for(i=0; i<len; ++i) {
+ if(!isxdigit(line[i])) {
+ line[i] = 0;
+ break;
+ }
+ }
+ if(i & 1 || i == 0 || i > (sizeof(keyslot_t)-1)*2) {
+ fprintf(stderr, "ignoring invalid key (odd number of digits or empty string or too long) at line %d\n", line_num);
+ continue;
+ }
+ uint8_t tmp[3];
+ int j;
+ tmp[2] = 0;
+ for(j = 0; j<(i/2); ++j) {
+ tmp[0] = line[j*2];
+ tmp[1] = line[j*2 + 1];
+ key[j] = (char)strtoul(tmp, NULL, 16);
+ }
+ for(j=i/2; j < sizeof(keyslot_t)-1; ++j) {
+ key[j] = 0;
+ }
+ key[sizeof(keyslot_t)-1] = generate_csum(key);
+ if(send_key(key, dev)) {
+ fprintf(stderr, "send_key failed at keyslot %d\n", key_num);
+ return 1;
+ }
+
+ key_num++;
+ if(key_num > EEPROM_SIZE/sizeof(keyslot_t)) {
+ fprintf(stderr, "reached maximum number of key slots (%d), will ignore remaining keys\n", EEPROM_SIZE/sizeof(keyslot_t));
+ break;
+ }
+ }
+ printf("\nread %d keys from STDIN - filling rest of keystore with invalid keys\n", key_num);
+
+ int i;
+ for(i=0; i<=sizeof(keyslot_t)-1; ++i) key[i] = 0xFF;
+ for(i=key_num; i < EEPROM_SIZE/sizeof(keyslot_t); ++i) {
+ if(send_key(key, dev)) {
+ fprintf(stderr, "send_key failed at keyslot %d\n", key_num);
+ return 1;
+ }
+ key_num++;
+ }
+
+ printf("\nwrite of %d keys finished\n", key_num);
+
+ return 0;
+}