]> git.cryptolib.org Git - labortage2013badge.git/blob - firmware/main.c
some minor fixes
[labortage2013badge.git] / firmware / main.c
1 /* Name: main.c
2  * Project: labortage-2013-badge
3  * Author: bg (bg@das-labor.org)
4  * Creation Date: 2013-10-16
5  * Tabsize: 4
6  * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH, (c) Daniel Otte
7  * License: GNU GPL v3
8  * This Revision: $Id: main.c 692 2008-11-07 15:07:40Z cs $
9  */
10
11 /*
12 This example should run on most AVRs with only little changes. No special
13 hardware resources except INT0 are used. You may have to change usbconfig.h for
14 different I/O pins for USB. Please note that USB D+ must be the INT0 pin, or
15 at least be connected to INT0 as well.
16 */
17
18 #define BUTTON_PIN 5
19 #define DEBOUNCE_DELAY 50
20 #define SIMPLE_COUNTER 1
21 #define NO_CHECK 1
22 #define ALLOW_SECRET_READ 0
23
24 #include <stdint.h>
25 #include <string.h>
26 #include <stdbool.h>
27
28 #include <avr/io.h>
29 #include <avr/wdt.h>
30 #include <avr/eeprom.h>
31 #include <avr/interrupt.h>  /* for sei() */
32 #include <util/delay.h>     /* for _delay_ms() */
33
34 #include <avr/pgmspace.h>   /* required by usbdrv.h */
35 #include "usbdrv.h"
36 #include "requests.h"       /* The custom request numbers we use */
37 #include "hotp.h"
38 #include "special_functions.h"
39 #if !SIMPLE_COUNTER
40 #include "percnt2.h"
41 #endif
42 #include "usb_keyboard_codes.h"
43
44 /* ------------------------------------------------------------------------- */
45 /* ----------------------------- USB interface ----------------------------- */
46 /* ------------------------------------------------------------------------- */
47
48 #define STATE_WAIT 0
49 #define STATE_SEND_KEY 1
50 #define STATE_RELEASE_KEY 2
51 #define STATE_NEXT 3
52
53 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
54
55 PROGMEM const char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = {
56     0x05, 0x01,                    /* USAGE_PAGE (Generic Desktop) */
57     0x09, 0x06,                    /* USAGE (Keyboard) */
58     0xa1, 0x01,                    /* COLLECTION (Application) */
59     0x75, 0x01,                    /*   REPORT_SIZE (1) */
60     0x95, 0x08,                    /*   REPORT_COUNT (8) */
61     0x05, 0x07,                    /*   USAGE_PAGE (Keyboard)(Key Codes) */
62     0x19, 0xe0,                    /*   USAGE_MINIMUM (Keyboard LeftControl)(224) */
63     0x29, 0xe7,                    /*   USAGE_MAXIMUM (Keyboard Right GUI)(231) */
64     0x15, 0x00,                    /*   LOGICAL_MINIMUM (0) */
65     0x25, 0x01,                    /*   LOGICAL_MAXIMUM (1) */
66     0x81, 0x02,                    /*   INPUT (Data,Var,Abs) ; Modifier byte */
67     0x95, 0x01,                    /*   REPORT_COUNT (1) */
68     0x75, 0x08,                    /*   REPORT_SIZE (8) */
69     0x81, 0x03,                    /*   INPUT (Cnst,Var,Abs) ; Reserved byte */
70     0x95, 0x05,                    /*   REPORT_COUNT (5) */
71     0x75, 0x01,                    /*   REPORT_SIZE (1) */
72     0x05, 0x08,                    /*   USAGE_PAGE (LEDs) */
73     0x19, 0x01,                    /*   USAGE_MINIMUM (Num Lock) */
74     0x29, 0x05,                    /*   USAGE_MAXIMUM (Kana) */
75     0x91, 0x02,                    /*   OUTPUT (Data,Var,Abs) ; LED report */
76     0x95, 0x01,                    /*   REPORT_COUNT (1) */
77     0x75, 0x03,                    /*   REPORT_SIZE (3) */
78     0x91, 0x03,                    /*   OUTPUT (Cnst,Var,Abs) ; LED report padding */
79     0x95, 0x06,                    /*   REPORT_COUNT (6) */
80     0x75, 0x08,                    /*   REPORT_SIZE (8) */
81     0x15, 0x00,                    /*   LOGICAL_MINIMUM (0) */
82     0x25, 0x65,                    /*   LOGICAL_MAXIMUM (101) */
83     0x05, 0x07,                    /*   USAGE_PAGE (Keyboard)(Key Codes) */
84     0x19, 0x00,                    /*   USAGE_MINIMUM (Reserved (no event indicated))(0) */
85     0x29, 0x65,                    /*   USAGE_MAXIMUM (Keyboard Application)(101) */
86     0x81, 0x00,                    /*   INPUT (Data,Ary,Abs) */
87     0xc0                           /* END_COLLECTION */
88 };
89
90 static uint16_t secret_length_ee EEMEM = 0;
91 static uint8_t  secret_ee[32] EEMEM;
92 static uint8_t  reset_counter_ee EEMEM = 0;
93 static uint8_t  digits_ee EEMEM = 8;
94
95 #if SIMPLE_COUNTER
96 static uint32_t counter_ee EEMEM = 0;
97 #endif
98
99 static uint8_t dbg_buffer[8];
100 static uint8_t secret[32];
101 static uint16_t secret_length_b;
102 static char token[10];
103
104 #define UNI_BUFFER_SIZE 16
105
106 static union __attribute__((packed)) {
107         uint8_t  w8[UNI_BUFFER_SIZE];
108         uint16_t w16[UNI_BUFFER_SIZE/2];
109         uint32_t w32[UNI_BUFFER_SIZE/4];
110         void*    ptr[UNI_BUFFER_SIZE/sizeof(void*)];
111 } uni_buffer;
112
113 static uint8_t current_command;
114
115 typedef struct __attribute__((packed)) {
116     uint8_t modifier;
117     uint8_t reserved;
118     uint8_t keycode[6];
119 } keyboard_report_t;
120
121 static keyboard_report_t keyboard_report; /* report sent to the host */
122 static uchar idleRate;  /* in 4 ms units */
123 static uchar key_state = STATE_WAIT;
124 volatile static uchar LED_state = 0xff;
125 /* ------------------------------------------------------------------------- */
126
127 static
128 void memory_clean(void) {
129     memset(secret, 0, 32);
130     secret_length_b = 0;
131 }
132
133 static
134 uint8_t secret_set(void){
135 #if !NO_CHECK
136     uint8_t r;
137     union {
138         uint8_t w8[32];
139         uint16_t w16[16];
140     } read_back;
141 #endif
142     const uint8_t length_B = (secret_length_b + 7) / 8;
143
144     eeprom_busy_wait();
145     eeprom_write_block(secret, secret_ee, length_B);
146 #if !NO_CHECK
147     eeprom_busy_wait();
148     eeprom_read_block(read_back.w8, secret_ee, length_B);
149     r = memcmp(secret, read_back.w8, length_B);
150     memory_clean();
151     memset(read_back.w8, 0, 32);
152     if (r) {
153         return 1;
154     }
155 #endif
156     eeprom_busy_wait();
157     eeprom_write_word(&secret_length_ee, secret_length_b);
158 #if !NO_CHECK
159     eeprom_busy_wait();
160     r = eeprom_read_word(&secret_length_ee) == secret_length_b;
161     memory_clean();
162     *read_back.w16 = 0;
163     if (!r) {
164         return 1;
165     }
166 #else
167     memory_clean();
168 #endif
169
170     return 0;
171 }
172
173 static
174 void counter_inc(void){
175 #if SIMPLE_COUNTER
176     uint32_t t;
177     eeprom_busy_wait();
178     t = eeprom_read_dword(&counter_ee);
179     eeprom_busy_wait();
180     eeprom_write_dword(&counter_ee, t + 1);
181 #else
182     percnt_inc(0);
183 #endif
184 }
185
186 static
187 void counter_reset(void) {
188     uint8_t reset_counter;
189     eeprom_busy_wait();
190     reset_counter = eeprom_read_byte(&reset_counter_ee);
191 #if SIMPLE_COUNTER
192     eeprom_busy_wait();
193     eeprom_write_dword(&counter_ee, 0);
194 #else
195     percnt_reset(0);
196 #endif
197     eeprom_busy_wait();
198     eeprom_write_byte(&reset_counter_ee, reset_counter + 1);
199 }
200
201 static
202 void counter_init(void) {
203 #if !SIMPLE_COUNTER
204     eeprom_busy_wait();
205     if (eeprom_read_byte(&reset_counter_ee) == 0) {
206         counter_reset();
207     }
208     percnt_init(0);
209 #endif
210 }
211
212 static
213 void token_generate(void) {
214     uint16_t s_length_b;
215     uint8_t digits;
216     counter_inc();
217     eeprom_busy_wait();
218     eeprom_read_block(secret, secret_ee, 32);
219     eeprom_busy_wait();
220     s_length_b = eeprom_read_word(&secret_length_ee);
221     if (s_length_b > 256) {
222         s_length_b = 256;
223     }
224     eeprom_busy_wait();
225     digits = eeprom_read_byte(&digits_ee);
226 #if SIMPLE_COUNTER
227     eeprom_busy_wait();
228     hotp(token, secret, s_length_b, eeprom_read_dword(&counter_ee) - 1, digits);
229 #else
230     hotp(token, secret, s_length_b, percnt_get(0) - 1, digits);
231 #endif
232     memory_clean();
233 }
234
235
236 static
237 void buildReport(uchar send_key) {
238     keyboard_report.modifier = 0;
239     switch (send_key) {
240     case '1' ... '9':
241         keyboard_report.keycode[0] = KEY_1 + (send_key-'1');
242         break;
243     case '0':
244         keyboard_report.keycode[0] = KEY_0;
245         break;
246     default:
247         keyboard_report.keycode[0] = 0;
248     }
249 }
250
251 static
252 int8_t button_get_debounced(volatile int8_t debounce_count) {
253     uint8_t v;
254     v = PINB & _BV(BUTTON_PIN);
255     while (debounce_count-- && (v == (PINB & _BV(BUTTON_PIN)))) {
256         ;
257     }
258     if (debounce_count != -1) {
259         return -1;
260     }
261     return v ? 0 : 1;
262 }
263
264 usbMsgLen_t usbFunctionSetup(uchar data[8])
265 {
266         usbRequest_t    *rq = (usbRequest_t *)data;
267         if ((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS) {    /* class request type */
268             switch(rq->bRequest) {
269         case USBRQ_HID_GET_REPORT: /* send "no keys pressed" if asked here */
270             /* wValue: ReportType (highbyte), ReportID (lowbyte) */
271             usbMsgPtr = (void *)&keyboard_report; /* we only have this one */
272             keyboard_report.modifier = 0;
273             keyboard_report.keycode[0] = 0;
274             return sizeof(keyboard_report);
275         case USBRQ_HID_SET_REPORT: /* if wLength == 1, should be LED state */
276             if (rq->wLength.word == 1) {
277                 current_command = LED_WRITE;
278                 return USB_NO_MSG;
279             }
280             return 0;
281         case USBRQ_HID_GET_IDLE: /* send idle rate to PC as required by spec */
282             usbMsgPtr = &idleRate;
283             return 1;
284         case USBRQ_HID_SET_IDLE: /* save idle rate as required by spec */
285             idleRate = rq->wValue.bytes[1];
286             return 0;
287         }
288     }
289     if ((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_VENDOR) {
290                 current_command = rq->bRequest;
291         usbMsgPtr = uni_buffer.w8;
292         switch(rq->bRequest)
293                 {
294         case CUSTOM_RQ_SET_SECRET:
295             secret_length_b = rq->wValue.word;
296             if (secret_length_b > 256) {
297                 secret_length_b = 256;
298             }
299             uni_buffer.w8[0] = 0;
300             return USB_NO_MSG;
301         case CUSTOM_RQ_INC_COUNTER:
302             counter_inc();
303             return 0;
304         case CUSTOM_RQ_GET_COUNTER:
305 #if SIMPLE_COUNTER
306             eeprom_busy_wait();
307             uni_buffer.w32[0] = eeprom_read_dword(&counter_ee);
308 #else
309             uni_buffer.w32[0] = percnt_get(0);
310 #endif
311             return 4;
312         case CUSTOM_RQ_RESET_COUNTER:
313             counter_reset();
314             return 0;
315         case CUSTOM_RQ_GET_RESET_COUNTER:
316             eeprom_busy_wait();
317             uni_buffer.w8[0] = eeprom_read_byte(&reset_counter_ee);
318             return 1;
319         case CUSTOM_RQ_SET_DIGITS:
320             if (rq->wValue.bytes[0] < 6) {
321                 rq->wValue.bytes[0] = 6;
322             }
323             if (rq->wValue.bytes[0] > 9) {
324                 rq->wValue.bytes[0] = 9;
325             }
326             eeprom_busy_wait();
327             eeprom_write_byte(&digits_ee, rq->wValue.bytes[0]);
328             return 0;
329         case CUSTOM_RQ_GET_DIGITS:
330             eeprom_busy_wait();
331             uni_buffer.w8[0] = eeprom_read_byte(&digits_ee);
332             return 1;
333         case CUSTOM_RQ_GET_TOKEN:
334             token_generate();
335             usbMsgPtr = (usbMsgPtr_t)token;
336             return strlen(token);
337         case CUSTOM_RQ_PRESS_BUTTON:
338             key_state = STATE_SEND_KEY;
339             return 0;
340         case CUSTOM_RQ_CLR_DBG:
341             memset(dbg_buffer, 0, sizeof(dbg_buffer));
342             return 0;
343                 case CUSTOM_RQ_SET_DBG:
344                         return USB_NO_MSG;
345                 case CUSTOM_RQ_GET_DBG:
346                         usbMsgPtr = dbg_buffer;
347                         return MIN(8, rq->wLength.word);
348                 case CUSTOM_RQ_RESET:
349                         soft_reset((uint8_t)(rq->wValue.word));
350                         break;
351                 case CUSTOM_RQ_READ_BUTTON:
352                         uni_buffer.w8[0] = button_get_debounced(DEBOUNCE_DELAY);
353                         return 1;
354 #if ALLOW_SECRET_READ
355                 case CUSTOM_RQ_GET_SECRET:
356             uni_buffer.w8[0] = 0;
357                     return USB_NO_MSG;
358 #else
359 #endif
360         default:
361             return 0;
362                 }
363     }
364
365     return 0;   /* default for not implemented requests: return no data back to host */
366 }
367
368
369 uchar usbFunctionWrite(uchar *data, uchar len)
370 {
371         switch(current_command){
372
373         case LED_WRITE:
374             if (data[0] != LED_state)
375                 LED_state = data[0];
376             return 1; /* Data read, not expecting more */
377         case CUSTOM_RQ_SET_SECRET:
378         {
379             if (uni_buffer.w8[0] < (secret_length_b + 7) / 8) {
380                 memcpy(&secret[uni_buffer.w8[0]], data, len);
381                 uni_buffer.w8[0] += len;
382             }
383             if (uni_buffer.w8[0] >= (secret_length_b + 7) / 8) {
384                 secret_set();
385                 return 1;
386             }
387             return 0;
388         }
389         case CUSTOM_RQ_SET_DBG:
390                 if(len > sizeof(dbg_buffer)){
391                         len = sizeof(dbg_buffer);
392                 }
393                 memcpy(dbg_buffer, data, len);
394         }
395         return 1;
396 }
397
398 uchar usbFunctionRead(uchar *data, uchar len){
399 #if ALLOW_SECRET_READ || 1
400     uchar r;
401     uint8_t s_length_B;
402     switch(current_command){
403     case CUSTOM_RQ_GET_SECRET:
404         eeprom_busy_wait();
405         s_length_B = (eeprom_read_word(&secret_length_ee) + 7) / 8;
406         r = MIN(len, s_length_B - uni_buffer.w8[0]);
407         eeprom_busy_wait();
408         eeprom_read_block(data, secret_ee + uni_buffer.w8[0], r);
409         uni_buffer.w8[0] += r;
410         return r;
411     }
412 #endif
413     return 0;
414 }
415
416 static void calibrateOscillator(void)
417 {
418 uchar       step = 128;
419 uchar       trialValue = 0, optimumValue;
420 int         x, optimumDev, targetValue = (unsigned)(1499 * (double)F_CPU / 10.5e6 + 0.5);
421  
422     /* do a binary search: */
423     do {
424         OSCCAL = trialValue + step;
425         x = usbMeasureFrameLength();    /* proportional to current real frequency */
426         if(x < targetValue)             /* frequency still too low */
427             trialValue += step;
428         step >>= 1;
429     } while(step > 0);
430     /* We have a precision of +/- 1 for optimum OSCCAL here */
431     /* now do a neighborhood search for optimum value */
432     optimumValue = trialValue;
433     optimumDev = x; /* this is certainly far away from optimum */
434     for (OSCCAL = trialValue - 1; OSCCAL <= trialValue + 1; OSCCAL++){
435         x = usbMeasureFrameLength() - targetValue;
436         if (x < 0)
437             x = -x;
438         if (x < optimumDev) {
439             optimumDev = x;
440             optimumValue = OSCCAL;
441         }
442     }
443     OSCCAL = optimumValue;
444 }
445  
446
447 void usbEventResetReady(void)
448 {
449     cli();  /* usbMeasureFrameLength() counts CPU cycles, so disable interrupts. */
450     calibrateOscillator();
451     sei();
452 }
453
454 /* ------------------------------------------------------------------------- */
455
456 int main(void)
457 {
458         size_t idx = 0;
459         int8_t i = 0, last_stable_button_state = 0;
460
461     wdt_enable(WDTO_1S);
462     /* Even if you don't use the watchdog, turn it off here. On newer devices,
463      * the status of the watchdog (on/off, period) is PRESERVED OVER RESET!
464      */
465     /* RESET status: all port bits are inputs without pull-up.
466      * That's the way we need D+ and D-. Therefore we don't need any
467      * additional hardware initialization.
468      */
469
470     counter_init();
471     usbInit();
472     usbDeviceDisconnect();  /* enforce re-enumeration, do this while interrupts are disabled! */
473     while(--i){             /* fake USB disconnect for ~512 ms */
474         wdt_reset();
475         _delay_ms(2);
476     }
477     usbDeviceConnect();
478         
479     sei();
480     DDRB &= ~_BV(BUTTON_PIN); /* make button pin input */
481     PORTB |= _BV(BUTTON_PIN); /* turn on pull-up resistor */
482
483     for(;;){                /* main event loop */
484         wdt_reset();
485         usbPoll();
486
487         i = button_get_debounced(DEBOUNCE_DELAY);
488         if (i != -1) {
489             if (last_stable_button_state == 0 && i == 1) {
490                 token_generate();
491                 key_state = STATE_SEND_KEY;
492             }
493             last_stable_button_state = i;
494         }
495
496         if(usbInterruptIsReady() && key_state != STATE_WAIT){
497             switch(key_state) {
498             case STATE_SEND_KEY:
499                 buildReport(token[idx]);
500                 key_state = STATE_RELEASE_KEY; /* release next */
501                 break;
502             case STATE_RELEASE_KEY:
503                 buildReport(0);
504                 ++idx;
505                 if (token[idx] == '\0') {
506                     idx = 0;
507                     key_state = STATE_WAIT;
508                 } else {
509                     key_state = STATE_SEND_KEY;
510                 }
511                 break;
512             default:
513                 key_state = STATE_WAIT; /* should not happen */
514             }
515                         /* start sending */
516             usbSetInterrupt((void *)&keyboard_report, sizeof(keyboard_report));
517
518         }
519
520     }
521     return 0;
522 }
523
524 /* ------------------------------------------------------------------------- */