minor change for pin-cir.c
[gnuk/gnuk.git] / src / pin-cir.c
1 /*
2  * pin-cir.c -- PIN input device support (Consumer Infra-Red)
3  *
4  * Copyright (C) 2010, 2011 Free Software Initiative of Japan
5  * Author: NIIBE Yutaka <gniibe@fsij.org>
6  *
7  * This file is a part of Gnuk, a GnuPG USB Token implementation.
8  *
9  * Gnuk is free software: you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * Gnuk is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
17  * License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23
24 #include "config.h"
25 #include "ch.h"
26 #include "hal.h"
27 #include "board.h"
28 #include "gnuk.h"
29
30 #ifdef DEBUG
31 #define DEBUG_CIR 1
32 #endif
33
34 uint8_t pin_input_buffer[MAX_PIN_CHARS];
35 uint8_t pin_input_len;
36
37 /*
38  * Supported/tested TV controllers:
39  *
40  *   Controller of Toshiba REGZA
41  *   Controller of Sony BRAVIA
42  *   Controller of Sharp AQUOS
43  *   Dell Wireless Travel Remote MR425
44  *
45  * The code supports RC-5 protocol in fact, but I don't have any
46  * controller at hand which I can test with, so I don't have any data
47  * for controller of RC-5.
48  *
49  * Current code assumes following mapping:
50  *
51  *  --------------------------------------
52  *    Protocol          Controller
53  *  --------------------------------------
54  *     RC-6               Dell MR425
55  *     NEC                Toshiba REGZA
56  *     Sharp              Sharp AQUOS
57  *     Sony               Sony BRAVIA
58  *  --------------------------------------
59  *
60  * In future, when I will have other controllers, this mapping will be
61  * (should be) configurable, at compile time at least, preferably at
62  * runtime.
63  */
64
65 /*
66  * Philips RC-5 Protocol: 14-bit (MSB first)
67  *
68  * Philips RC-6 Protocol: (START + 1 + MODE + TR + 32-bit / 16-bit) (MSB first)
69  *                                     3-bit      (mode 6 / mode 0)
70  *      Example: Controller of DELL (mode 6)
71  *
72  * NEC Protocol: (START + 32-bit + STOP) + (START + STOP) x N  (LSB first)
73  *      32-bit: 8-bit command inverted + 8-bit command + 16-bit address
74  *      Example: Controller of Toshiba REGZA
75  *      Example: Controller of Ceiling Light by NEC
76  *
77  * Sony Protocol: (START + 12-bit) or (START + 15-bit)  (LSB first)
78  *      12-bit: 5-bit address + 7-bit command
79  *      Example: Controller of Sony BRAVIA
80  *
81  * Sharp Protocol: (START + 48-bit + STOP) x N  (LSB first)
82  *      48-bit: 32-bit address + 12-bit command + 4-bit parity
83  *      Example: Controller of Sharp AQUOS
84  *      Example: Controller of Ceiling Light by Mitsubishi
85  *
86  * Unsupported:
87  *
88  * Unknown Protocol 2: (START + 112-bit + STOP)  (LSB first)
89  *      Example: Controller of Mitsubishi air conditioner
90  *
91  * Unknown Protocol 3: (START + 128-bit + STOP)  (LSB first)
92  *      Example: Controller of Fujitsu air conditioner
93  *
94  * Unknown Protocol 4: (START + 152-bit + STOP)  (LSB first)
95  *      Example: Controller of Sanyo air conditioner
96  *
97  */
98
99 /*
100  * The implementation note of CIR signal decoding (on STM32).
101  *
102  * (1) Use EXTI interrupt to detect the first edge of signal.
103  * (2) Use Timer (with PWM input mode) to measure timings of square wave.
104  *
105  */
106
107 /*
108  * Timer settings.
109  *
110  * See THE reference manual (RM0008) section 15.3.6 PWM input mode.
111  *
112  * 72MHz
113  * Prescaler = 72
114  *
115  * 1us
116  *
117  * TIMx_CR1
118  *  CKD  = 00 (tDTS = tCK_INT)
119  *  ARPE = 1  (buffered)
120  *  CMS  = 00 (up counter)
121  *  DIR  = 0  (up counter)
122  *  OPM  = 0  (up counter)
123  *  URS  = 1  (update request source: overflow only)
124  *  UDIS = 0  (UEV (update event) enabled)
125  *  CEN  = 1  (counter enable)
126  *
127  * TIMx_CR2
128  *  TI1S = 1 (TI1 is XOR of ch1, ch2, ch3)
129  *  MMS  = 000 (TRGO at Reset)
130  *  CCDS = 0 (DMA on capture)
131  *  RSVD = 000
132  *
133  * TIMx_SMCR
134  *  ETP  = 0
135  *  ECE  = 0
136  *  ETPS = 00
137  *  ETF  = 0000
138  *  MSM  = 0
139  *  TS   = 101 (TI1FP1 selected)
140  *  RSVD = 0
141  *  SMS  = 100 (Reset-mode)
142  *
143  * TIMx_DIER
144  *
145  * TIMx_SR
146  *
147  * TIMx_EGR
148  *
149  * TIMx_CCMR1
150  *  CC1S = 01 (TI1 selected)
151  *  CC2S = 10 (TI1 selected)
152  *  IC1F = 1001 (fSAMPLING=fDTS/8, N=8)
153  *  IC2F = 1001 (fSAMPLING=fDTS/8, N=8)
154  *
155  * TIMx_CCMR2
156  *
157  * TIMx_CCER
158  *  CC2P = 1 (polarity = falling edge: TI1FP1)
159  *  CC2E = 1
160  *  CC1P = 0 (polarity = rising edge: TI1FP1)
161  *  CC1E = 1
162  *
163  * TIMx_CNT
164  * TIMx_PSC = 71
165  * TIMx_ARR = 18000
166  *
167  * TIMx_CCR1  period
168  * TIMx_CCR2  duty
169  *
170  * TIMx_DCR
171  * TIMx_DMAR
172  */
173
174 #if defined(DEBUG_CIR)
175 static uint16_t intr_ext;
176 static uint16_t intr_trg;
177 static uint16_t intr_ovf;
178
179 #define MAX_CIRINPUT_BIT 512
180 static uint16_t cirinput[MAX_CIRINPUT_BIT];
181 static uint16_t *cirinput_p;
182 #endif
183
184 static uint32_t cir_data;
185 static uint16_t cir_data_more;
186 static uint8_t cir_proto;
187 #define CIR_PROTO_RC5   1
188 #define CIR_PROTO_RC6   2
189 #define CIR_PROTO_OTHER 3
190 #define CIR_PROTO_SONY  4
191 #define CIR_PROTO_NEC   5
192 #define CIR_PROTO_SHARP 6
193
194
195 /* CIR_DATA_ZERO: Used for zero-bit handling of RC-5/RC-6 */
196 static uint8_t cir_data_zero;
197
198 static uint8_t cir_seq;
199
200 static systime_t cir_input_last;
201 #define CIR_PERIOD_INHIBIT_CHATTER 200 /* mili second */
202
203 static void
204 cir_init (void)
205 {
206   cir_data = 0;
207   cir_seq = 0;
208   /* Don't touch cir_proto here */
209   cir_ext_enable ();
210 }
211
212
213 #define CH_RETURN    0x0d
214 #define CH_BACKSPACE 0x08
215
216 struct codetable {
217   uint16_t cir_code;
218   uint8_t  char_code;
219 };
220
221 /* NOTE: no way to input '0' */
222 static const struct codetable
223 cir_codetable_dell_mr425[] = {
224   {0x10, '7' },          /* Speaker Louder       */
225   {0x11, '8' },          /* Speaker Quieter      */
226   {0x0d, '9' },          /* Speaker Mute         */
227   {0xce, 'a' },          /* Black triangle UP    */
228   {0xcf, 'b' },          /* Black triangle DOWN  */
229   {0x58, 'c' },          /* White triangle UP    */
230   {0x5a, 'd' },          /* White triangle LEFT  */
231   {0x5c, CH_RETURN },    /* Check                */
232   {0x5b, 'e' },          /* White triangle RIGHT */
233   {0xa4, CH_BACKSPACE }, /* Back                 */
234   {0x59, 'f' },          /* White triangle DOWN  */
235   {0x2f, '1' },          /* Rewind               */
236   {0x2c, '2' },          /* Play / Pause         */
237   {0x2e, '3' },          /* Forward              */
238   {0x21, '4' },          /* Skip backward        */
239   {0x31, '5' },          /* Stop                 */
240   {0x20, '6' },          /* Skip forward         */
241
242   {0, 0} /* <<END>>   */
243 };
244
245 #define CIR_ADDR_SHARP_AQUOS 0x028f
246 static const struct codetable
247 cir_codetable_aquos[] = {
248   { 0x0116, ' ' }, /* Power */
249   { 0x025e, '0' }, /* d */
250   { 0x024e, '1' }, /* 1 */
251   { 0x024f, '2' }, /* 2 */
252   { 0x0250, '3' }, /* 3 */
253   { 0x0251, '4' }, /* 4 */
254   { 0x0252, '5' }, /* 5 */
255   { 0x0253, '6' }, /* 6 */
256   { 0x0254, '7' }, /* 7 */
257   { 0x0255, '8' }, /* 8 */
258   { 0x0256, '9' }, /* 9 */
259   { 0x0257, 'a' }, /* 10/0 */
260   { 0x0258, 'b' }, /* 11 */
261   { 0x0259, 'c' }, /* 12 */
262   { 0x0111, 'd' }, /* Ch ^ */
263   { 0x0112, 'e' }, /* Ch v */
264   { 0x0114, 'f' }, /* Vol + */
265   { 0x0115, 'g' }, /* Vol - */
266   { 0x0117, 'h' }, /* Mute */
267   { 0x0280, 'i' }, /* BLUE */
268   { 0x0281, 'j' }, /* RED */
269   { 0x0282, 'k' }, /* GREEN */
270   { 0x0283, 'l' }, /* YELLOW */
271   { 0x011b, 'm' }, /* DISPLAY CONTROL (gamen hyouji) */
272   { 0x01d5, 'n' }, /* DISPLAY SIZE */
273   { 0x0157, 'o' }, /* UP */
274   { 0x01d7, 'p' }, /* LEFT */
275   { 0x01d8, 'q' }, /* RIGHT */
276   { 0x0120, 'r' }, /* DOWN */
277   { 0x0152, CH_RETURN }, /* Commit (kettei) */
278   { 0x01e4, CH_BACKSPACE }, /* Back (modoru) */
279   { 0x01f5, 's' }, /* Quit (shuuryou) */
280   { 0x0b03, 't' }, /* Rewind (hayamodoshi) */
281   { 0x0b01, 'u' }, /* Play (saisei) */
282   { 0x0b04, 'v' }, /* Forward (hayaokuri) */
283   { 0x0b02, 'w' }, /* Stop (teishi) */
284   { 0x028a, 'x' }, /* BS */
285   { 0x028b, 'y' }, /* CS */
286   { 0x025f, 'z' }, /* Program information (bangumi jouhou) */
287   { 0x0260, '\\' }, /* Program table (bangumi hyou) */
288   { 0x0118, '|' }, /* Sound channel (onsei kirikae) */
289   { 0x028e, '[' }, /* Ground Analog (chijou A) */
290   { 0x0289, ']' }, /* Ground Digital (chijou D) */
291
292   { 0x0b07, '\"' }, /* Feature select (kinou sentaku) */
293   { 0x026b, '.' }, /* TV/Radio/Data (terebi/rajio/data) */
294   { 0x025a, ',' }, /* 3 code input (3 keta nyuuryoku) */
295   { 0x0267, ':' }, /* subtitle (jimaku) */
296   { 0x0159, ';' }, /* hold (seishi) */
297
298   { 0x01c4, 'A' }, /* Menu */
299   { 0x011a, 'B' }, /* Off timer */
300   { 0x0121, 'C' }, /* CATV */
301   { 0x0b05, 'D' }, /* Record */
302   { 0x0b06, 'E' }, /* Recording stop */
303   { 0x0113, 'F' }, /* Inputs (nyuuryoku kirikae) */
304   { 0x0275, 'G' }, /* other programs (ura bangumi) */
305   { 0x0266, 'H' }, /* signal control (eizou kirikae) */
306   { 0x01e7, 'I' }, /* AV position */
307   { 0x027f, 'J' }, /* i.LINK */
308   { 0x0b00, 'K' }, /* Recorder power */
309   { 0x028f, 'L' }, /* as you like it (okonomi senkyoku) */
310
311   {0, 0} /* <<END>>   */
312 };
313
314 #define CIR_ADDR_TOSHIBA_REGZA 0xbf40
315 static const struct codetable
316 cir_codetable_regza[] = {
317   { 0x12, ' ' }, /* Power */
318   { 0x14, '0' }, /* d (data) */
319   { 0x01, '1' }, /* 1 */
320   { 0x02, '2' }, /* 2 */
321   { 0x03, '3' }, /* 3 */
322   { 0x04, '4' }, /* 4 */
323   { 0x05, '5' }, /* 5 */
324   { 0x06, '6' }, /* 6 */
325   { 0x07, '7' }, /* 7 */
326   { 0x08, '8' }, /* 8 */
327   { 0x09, '9' }, /* 9 */
328   { 0x0a, 'a' }, /* 10 */
329   { 0x0b, 'b' }, /* 11 */
330   { 0x0c, 'c' }, /* 12 */
331   { 0x1b, 'd' }, /* Ch ^ */
332   { 0x1f, 'e' }, /* Ch v */
333   { 0x1a, 'f' }, /* Vol + */
334   { 0x1e, 'g' }, /* Vol - */
335   { 0x10, 'h' }, /* Mute */
336   { 0x73, 'i' }, /* BLUE */
337   { 0x74, 'j' }, /* RED */
338   { 0x75, 'k' }, /* GREEN */
339   { 0x76, 'l' }, /* YELLOW */
340   { 0x1c, 'm' }, /* Display control */
341   { 0x2b, 'n' }, /* Display size */
342   { 0x3e, 'o' }, /* UP */
343   { 0x5f, 'p' }, /* LEFT */
344   { 0x5b, 'q' }, /* RIGHT */
345   { 0x3f, 'r' }, /* DOWN */
346   { 0x3d, CH_RETURN }, /* Commit (kettei) */
347   { 0x3b, CH_BACKSPACE }, /* Back (modoru) */
348   { 0x3c, 's' }, /* Quit (shuuryou) */
349   { 0x2c, 't' }, /* << (Rewind) */
350   { 0x2d, 'u' }, /* >/|| (Play/Stop) */
351   { 0x2e, 'v' }, /* >> (Forward) */
352   { 0x2b, 'w' }, /* Stop (teishi) */
353   { 0x7c, 'x' }, /* BS */
354   { 0x7d, 'y' }, /* CS */
355   { 0x71, 'z' }, /* Program information (bangumi setsumei) */
356   { 0x77, '\\' }, /* Mini program table (mini bangumihyou) */
357   { 0x13, '|' }, /* Sound (onta kirikae) */
358   { 0x7a, '[' }, /* Ground Digital (chideji) */
359   { 0x7b, ']' }, /* Ground Analog (chiana) */
360
361   { 0xd0, '\"' }, /* Settings Menu (settei menu) */
362   { 0x6d, '.' }, /* Radio/Data (rajio/data) */
363   { 0x60, ',' }, /* CH 10-key input (search) */
364   { 0x52, ':' }, /* subtitle (jimaku) */
365   { 0x50, ';' }, /* hold (seishi) */
366
367   { 0x3a, 'A' }, /* Input- (nyuuryokukirikae-) */
368   { 0x0f, 'B' }, /* Input+ (nyuuryokukirikae+) */
369   { 0x29, 'C' }, /* Two screens (nigamen) */
370   { 0x25, 'D' }, /* Broadband */
371   { 0x27, 'E' }, /* |<< Skip backward */
372   { 0x26, 'F' }, /* >>| Skip forward  */
373   { 0x61, '!' }, /* 1 NHK1 */
374   { 0x62, '@' }, /* 2 NHK2 */
375   { 0x63, '#' }, /* 3 NHKh */
376   { 0x64, '$' }, /* 4 BS Nihon TV */
377   { 0x65, '%' }, /* 5 BS Asahi */
378   { 0x66, '^' }, /* 6 BS-i */
379   { 0x67, '&' }, /* 7 BSJ */
380   { 0x68, '*' }, /* 8 BS Fuji */
381   { 0x69, '(' }, /* 9 WOW */
382   { 0x6a, ')' }, /* 10 Star */
383   { 0x6b, '-' }, /* 11 BS11 */
384   { 0x6c, '+' }, /* 12 TwellV */
385   { 0x27, '=' }, /* Quick (Delete) */
386   { 0x34, '<' }, /* REGZA link */
387   { 0x6e, '>' }, /* Program Table */
388   { 0x20, '/' }, /* ^^ */
389   { 0x22, '\'' }, /* << */
390   { 0x23, '?' }, /* >> */
391   { 0x21, '_' }, /* vv */
392
393   {0, 0} /* <<END>>   */
394 };
395
396 static const struct codetable
397 cir_codetable_bravia[] = {
398   { 0x15, ' ' }, /* Power */
399   { 0x95, '0' }, /* d (16-bit: 0x4b) */
400   { 0x00, '1' }, /* 1 */
401   { 0x01, '2' }, /* 2 */
402   { 0x02, '3' }, /* 3 */
403   { 0x03, '4' }, /* 4 */
404   { 0x04, '5' }, /* 5 */
405   { 0x05, '6' }, /* 6 */
406   { 0x06, '7' }, /* 7 */
407   { 0x07, '8' }, /* 8 */
408   { 0x08, '9' }, /* 9 */
409   { 0x09, 'a' }, /* 10 */
410   { 0x0a, 'b' }, /* 11 */
411   { 0x0b, 'c' }, /* 12 */
412   { 0x10, 'd' }, /* CH+ */
413   { 0x11, 'd' }, /* CH- */
414   { 0x12, 'f' }, /* Vol+ */
415   { 0x13, 'g' }, /* Vol- */
416   { 0x14, 'h' }, /* Mute */
417   { 0xa4, 'i' }, /* BLUE (16-bit: 0x4b) */
418   { 0xa5, 'j' }, /* RED (16-bit: 0x4b) */
419   { 0xa6, 'k' }, /* GREEN (16-bit: 0x4b) */
420   { 0xa7, 'l' }, /* YELLOW (16-bit: 0x4b) */
421   { 0x3a, 'm' }, /* DISPLAY control (gamen hyouji) */
422   { 0x3d, 'n' }, /* Display Wide (waido kirikae) */
423   { 0x74, 'o' }, /* UP */
424   { 0x75, 'p' }, /* DOWN */
425   { 0x33, 'q' }, /* RIGHT */
426   { 0x34, 'r' }, /* LEFT */
427   { 0x65, CH_RETURN }, /* Commit (kettei) */
428   { 0xa3, CH_BACKSPACE }, /* Back (modoru) (16-bit: 0x4b) */
429   { 0xac, 's' }, /* BS (16-bit: 0x4b) */
430   { 0xab, 't' }, /* CS (16-bit: 0x4b) */
431   { 0x5b, 'u' }, /* Program table (bangumi hyou) (16-bit: 0x52) */
432   { 0x17, 'v' }, /* Sound channel (onsei kirikae) */
433   { 0xa8, 'w' }, /* subtitle (jimaku) (16-bit: 0x4b) */
434   { 0x5c, 'x' }, /* hold (memo) */
435   { 0xb6, 'y' }, /* Tool (16-bit: 0x4b) */
436   { 0x8c, 'z' }, /* 10 key input (10ki-) (16-bit: 0x4b) */
437   { 0x60, '!' }, /* Menu */
438   { 0xae, '@' }, /* Analog (16-bit: 0x4b) */
439   { 0xb2, '#' }, /* Digital (16-bit: 0x4b) */
440   { 0x25, '$' }, /* Input (nyuuryoku kirikae) */
441
442   {0, 0} /* <<END>>   */,
443 };
444
445 static int
446 ch_is_backspace (int ch)
447 {
448   return ch == CH_BACKSPACE;
449 }
450
451 static int
452 ch_is_enter (int ch)
453 {
454   return ch == CH_RETURN;
455 }
456
457 /* liner search is good enough for this small amount of data */
458 static uint8_t
459 find_char_codetable (uint32_t cir_code, const struct codetable *ctp)
460 {
461   while (ctp->cir_code != 0x0000 || ctp->char_code != 0x00)
462     if (ctp->cir_code == cir_code)
463       return ctp->char_code;
464     else
465       ctp++;
466
467   /* Not found */
468   return cir_code & 0xff;
469 }
470
471 static int
472 hex (int x)
473 {
474   if (x < 10)
475     return x + '0';
476   else
477     return (x - 10) + 'a';
478 }
479
480 static int
481 cir_getchar (systime_t timeout)
482 {
483   uint16_t cir_addr;
484   eventmask_t m;
485 #if defined(DEBUG_CIR)
486   uint16_t *p;
487 #endif
488
489 #if defined(DEBUG_CIR)
490   cirinput_p = cirinput;
491 #endif
492
493   chEvtClear (ALL_EVENTS);
494   cir_init ();
495
496   m = chEvtWaitOneTimeout (ALL_EVENTS, timeout);
497   if (m == 0)
498     return -1;
499
500 #if defined(DEBUG_CIR)
501   DEBUG_INFO ("****\r\n");
502   DEBUG_SHORT (intr_ext);
503   DEBUG_SHORT (intr_trg);
504   DEBUG_SHORT (intr_ovf);
505   DEBUG_INFO ("----\r\n");
506   for (p = cirinput; p < cirinput_p; p++)
507     DEBUG_SHORT (*p);
508   DEBUG_INFO ("====\r\n");
509
510   cirinput_p = cirinput;
511
512   DEBUG_INFO ("**** CIR data:");
513   DEBUG_WORD (cir_data);
514   if (cir_seq > 48)
515     DEBUG_SHORT (cir_data_more);
516   DEBUG_BYTE (cir_seq);
517 #endif
518
519   switch (cir_proto)
520     {
521     case CIR_PROTO_RC5:
522       cir_data &= 0x003f;
523       goto err;
524     case CIR_PROTO_RC6:
525       cir_addr = cir_data >> 8; /* in case of cir_seq == 16.  32??? */
526       cir_data &= 0x00ff;
527       return find_char_codetable (cir_data, cir_codetable_dell_mr425);
528     case CIR_PROTO_NEC:
529       cir_addr = cir_data&0xffff;
530       if (cir_addr == CIR_ADDR_TOSHIBA_REGZA)
531         {
532           cir_data = (cir_data >> 16) & 0x00ff;
533           return find_char_codetable (cir_data, cir_codetable_regza);
534         }
535       else
536         goto err;
537     case CIR_PROTO_SHARP:
538       cir_addr = cir_data&0x0fff;
539       if (cir_addr == CIR_ADDR_SHARP_AQUOS)
540         {
541           cir_data = (cir_data>>16)&0x0fff;
542           return find_char_codetable (cir_data, cir_codetable_aquos);
543         }
544       else
545         goto err;
546     case CIR_PROTO_SONY:
547       /* Remove ADDRESS bits and filter COMMAND bits */
548       if (cir_seq == 1 + 12)
549         {
550           cir_addr = cir_data >> 7;
551           cir_data = cir_data & 0x007f;
552           /* ADDRESS = 0x01 (5-bit) */
553         }
554       else
555         {
556           cir_addr = cir_data >> 8;
557           cir_data = cir_data & 0x00ff;
558           /* ADDRESS = 0x4b or 0x52 (7-bit) */
559         }
560       return find_char_codetable (cir_data, cir_codetable_bravia);
561     err:
562     default:
563       /* encode debug information */
564       pin_input_len = 16;
565       pin_input_buffer[0] = hex (cir_proto >> 4);
566       pin_input_buffer[1] = hex (cir_proto & 0x0f);
567       pin_input_buffer[2] = ':';
568       pin_input_buffer[3] = hex ((cir_data >> 28) & 0x0f);
569       pin_input_buffer[4] = hex ((cir_data >> 24) & 0x0f);
570       pin_input_buffer[5] = hex ((cir_data >> 20) & 0x0f);
571       pin_input_buffer[6] = hex ((cir_data >> 16) & 0x0f);
572       pin_input_buffer[7] = hex ((cir_data >> 12) & 0x0f);
573       pin_input_buffer[8] = hex ((cir_data >> 8) & 0x0f);
574       pin_input_buffer[9] = hex ((cir_data >> 4) & 0x0f);
575       pin_input_buffer[10] = hex (cir_data & 0x0f);
576       pin_input_buffer[11] = ':';
577       pin_input_buffer[12] = hex ((cir_data_more >> 12) & 0x0f);
578       pin_input_buffer[13] = hex ((cir_data_more >> 8) & 0x0f);
579       pin_input_buffer[14] = hex ((cir_data_more >> 4) & 0x0f);
580       pin_input_buffer[15] = hex (cir_data_more & 0x0f);
581       return CH_RETURN;
582     }
583 }
584
585 /*
586  * RC-5 protocol doesn't have a start bit, while any other protocols
587  * have the one.
588  */
589 #define CIR_BIT_START_RC5_DETECT 1600 /* RC-5: 889us, Sony start: 2400us */
590
591 #define CIR_BIT_START_RC5_LENGTH (889 + 889/2)
592 #define CIR_BIT_PERIOD_RC6 444
593 #define CIR_BIT_PERIOD 1500
594 #define CIR_BIT_SIRC_PERIOD_ON 1000
595
596 static Thread *pin_thread;
597
598 /* 
599  * Let user input PIN string.
600  * Return length of the string.
601  * The string itself is in PIN_INPUT_BUFFER.
602  */
603 int
604 pinpad_getline (int msg_code, systime_t timeout)
605 {
606   (void)msg_code;
607
608   pin_thread = chThdSelf ();
609
610   DEBUG_INFO (">>>\r\n");
611
612   pin_input_len = 0;
613   while (1)
614     {
615       int ch;
616
617       ch = cir_getchar (timeout);
618       if (ch < 0)
619         return 0;               /* timeout */
620
621       if (ch_is_backspace (ch))
622         {
623           led_blink (2);
624           if (pin_input_len > 0)
625             pin_input_len--;
626         }
627       else if (ch_is_enter (ch))
628         break;
629       else if (pin_input_len < MAX_PIN_CHARS)
630         {
631           led_blink (0);
632           pin_input_buffer[pin_input_len++] = ch;
633         }
634     }
635
636   cir_ext_disable ();
637
638   return pin_input_len;
639 }
640
641 /**
642  * @brief  Interrupt handler of EXTI.
643  * @note   This handler will be invoked at the beginning of signal.
644  *         Setup timer to measure period and duty using PWM input mode.
645  */
646 void
647 cir_ext_interrupt (void)
648 {
649   cir_ext_disable ();
650
651 #if defined(DEBUG_CIR)
652   intr_ext++;
653   if (cirinput_p - cirinput < MAX_CIRINPUT_BIT)
654     {
655       *cirinput_p++ = 0x0000;
656       *cirinput_p++ = (uint16_t)chTimeNow ();
657     }
658 #endif
659
660   TIMx->EGR = TIM_EGR_UG;       /* Generate UEV to load PSC and ARR */
661   /* Enable Timer */
662   TIMx->SR &= ~(TIM_SR_UIF
663                 | TIM_SR_CC1IF | TIM_SR_CC2IF
664                 | TIM_SR_TIF
665                 | TIM_SR_CC1OF | TIM_SR_CC2OF);
666   TIMx->DIER = TIM_DIER_UIE /*overflow*/ | TIM_DIER_TIE /*trigger*/;
667   TIMx->CR1 |= TIM_CR1_CEN;
668 }
669
670 #define CIR_PERIOD_ON_RC5_OR_RC6 (((cir_proto == CIR_PROTO_RC5) ? 2 : 1) \
671                                   * CIR_BIT_PERIOD_RC6 * 3 / 2)
672
673 /**
674  * @brief  Interrupt handler of timer.
675  * @note   Timer is PWM input mode, this handler will be invoked on each cycle
676  */
677 void
678 cir_timer_interrupt (void)
679 {
680   uint16_t period, on, off;
681
682   period = TIMx->CCR1;
683   on = TIMx->CCR2;
684   off = period - on;
685
686   if ((TIMx->SR & TIM_SR_TIF))
687     {
688       if (cir_seq == 0)
689         {
690           if (on >= CIR_BIT_START_RC5_DETECT)
691             {
692               cir_proto = CIR_PROTO_OTHER;
693               cir_data_zero = 0;
694             }
695           else
696             {
697               cir_proto = CIR_PROTO_RC5;
698               cir_data = 1;
699               if (on >= CIR_BIT_START_RC5_LENGTH)
700                 {
701                   cir_data <<= 1;
702                   cir_seq++;
703                   if (off >= CIR_BIT_START_RC5_LENGTH)
704                     cir_data_zero = 0;
705                   else
706                     cir_data_zero = 1;
707                 }
708               else
709                 cir_data_zero = 0;
710             }
711         }
712       else if (cir_proto == CIR_PROTO_OTHER)
713         {
714           if (cir_seq == 1 + 16)
715             cir_data_more = (uint16_t)(cir_data >> 16);
716
717           cir_data >>= 1;
718           cir_data |= (period >= CIR_BIT_PERIOD) ? 0x80000000 : 0;
719
720           /* Detection of RC-6 protocol */
721           if (cir_data_zero && on > CIR_BIT_PERIOD_RC6*3/2)
722             /* TR-bit 0 is detected */
723             {
724               cir_proto = CIR_PROTO_RC6;
725               cir_seq = 0;
726               cir_data = 0;     /* ignore MODE bits */
727               if (on > CIR_BIT_PERIOD_RC6*5/2)
728                 {
729                   cir_data = 1;
730                   if (off > CIR_BIT_PERIOD_RC6*3/2)
731                     cir_data_zero = 1;
732                   else
733                     cir_data_zero = 0;
734                 }
735               else              /* Off must be short */
736                 {
737                   cir_data_zero = 1;
738                 }
739             }
740           else if ((!cir_data_zero
741                && on > CIR_BIT_PERIOD_RC6*3/2 && off > CIR_BIT_PERIOD_RC6*3/2))
742             /* TR-bit 1 is detected */
743             {
744               cir_proto = CIR_PROTO_RC6;
745               cir_seq = 0;
746               cir_data = 0;     /* ignore MODE bits */
747               cir_data_zero = 0;
748             }
749           else
750             {
751               /* Check if it looks like TR-bit of RC6 protocol */
752               if (off <= CIR_BIT_PERIOD_RC6*3/2)
753                 cir_data_zero = 0;
754               else
755                 cir_data_zero = 1;
756             }
757         }
758       else if (cir_proto == CIR_PROTO_RC5 || cir_proto == CIR_PROTO_RC6)
759         {
760           if (cir_data_zero)
761             {
762               cir_data <<= 1;
763
764               if (on > CIR_PERIOD_ON_RC5_OR_RC6)
765                 {
766                   cir_data <<= 1;
767                   cir_data |= 1;
768                   cir_seq++;
769                   if (off > CIR_PERIOD_ON_RC5_OR_RC6)
770                     cir_data_zero = 1;
771                   else
772                     cir_data_zero = 0;
773                 }
774               else              /* Off must be short */
775                 cir_data_zero = 1;
776             }
777           else
778             {
779               cir_data <<= 1;
780               cir_data |= 1;
781
782               /* On must be short */
783               if (off > CIR_PERIOD_ON_RC5_OR_RC6)
784                 cir_data_zero = 1;
785               else
786                 cir_data_zero = 0;
787             }
788         }
789
790       cir_seq++;
791
792 #if defined(DEBUG_CIR)
793       if (cirinput_p - cirinput < MAX_CIRINPUT_BIT)
794         {
795           *cirinput_p++ = on;
796           *cirinput_p++ = off;
797         }
798       intr_trg++;
799 #endif
800
801       TIMx->EGR = TIM_EGR_UG;   /* Generate UEV */
802       TIMx->SR &= ~TIM_SR_TIF;
803     }
804   else
805     /* overflow occurred */
806     {
807       systime_t now = chTimeNow ();
808
809       TIMx->SR &= ~TIM_SR_UIF;
810
811       if (on > 0)
812         {
813           uint8_t ignore_input = 0;
814
815           /* Disable the timer */
816           TIMx->CR1 &= ~TIM_CR1_CEN;
817           TIMx->DIER = 0;
818
819           if (cir_seq == 12 || cir_seq == 15)
820             {
821 #if defined(DEBUG_CIR)
822               if (cirinput_p - cirinput < MAX_CIRINPUT_BIT)
823                 {
824                   *cirinput_p++ = on;
825                   *cirinput_p++ = 0xffff;
826                 }
827 #endif
828               cir_proto = CIR_PROTO_SONY;
829               cir_data >>= 1;
830               cir_data |= (on >= CIR_BIT_SIRC_PERIOD_ON) ? 0x80000000 : 0;
831               cir_data >>= (32 - cir_seq);
832               cir_seq++;
833             }
834           else
835             {
836               if (cir_proto == CIR_PROTO_RC5 || cir_proto == CIR_PROTO_RC6)
837                 {
838                   cir_data <<= 1;
839                   cir_seq++;
840                   if (cir_data_zero)
841                     {
842                       if (on > CIR_PERIOD_ON_RC5_OR_RC6)
843                         {
844                           cir_data <<= 1;
845                           cir_data |= 1;
846                           cir_seq++;
847                         }
848                     }
849                   else
850                     cir_data |= 1;
851                 }
852               /* Or else, it must be the stop bit, just ignore */
853             }
854
855           if (now - cir_input_last < CIR_PERIOD_INHIBIT_CHATTER)
856             {
857               cir_input_last = now;
858               ignore_input = 1;
859             }
860           else if (cir_proto == CIR_PROTO_SONY)
861             {
862               if (cir_seq != 1 + 12 && cir_seq != 1 + 15)
863                 ignore_input = 1;
864             }
865           else if (cir_proto == CIR_PROTO_OTHER)
866             {
867               if (cir_seq == 1 + 32)
868                 {
869                   if (((cir_data >> 16) & 0xff) == ((cir_data >> 24) ^ 0xff))
870                     cir_proto = CIR_PROTO_NEC;
871                   else
872                     ignore_input = 1;
873                 }
874               else if (cir_seq == 1 + 48)
875                 {
876                   if ((cir_data >> 28) ==
877                       (((cir_data_more >> 12) & 0x0f)
878                        ^ ((cir_data_more >> 8) & 0x0f)
879                        ^ ((cir_data_more >> 4) & 0x0f)
880                        ^ (cir_data_more & 0x0f)
881                        ^ ((cir_data >> 24) & 0x0f)
882                        ^ ((cir_data >> 20) & 0x0f) ^ ((cir_data >> 16) & 0x0f)
883                        ^ ((cir_data >> 12) & 0x0f) ^ ((cir_data >> 8) & 0x0f)
884                        ^ ((cir_data >> 4) & 0x0f) ^ (cir_data & 0x0f)))
885                     cir_proto = CIR_PROTO_SHARP;
886                   else
887                     ignore_input = 1;
888                 }
889               else
890                 ignore_input = 1;
891             }
892           else if (cir_proto == CIR_PROTO_RC6)
893             {
894               if (cir_seq != 16 && cir_seq != 32)
895                 ignore_input = 1;
896             }
897           else if (cir_proto == CIR_PROTO_RC5)
898             {
899               if (cir_seq != 14)
900                 ignore_input = 1;
901             }
902           else
903             ignore_input = 1;
904
905           if (ignore_input)
906             /* Ignore data received and enable CIR again */
907             cir_init ();
908           else
909             {
910               cir_input_last = now;
911               /* Notify thread */
912               if (pin_thread)
913                 chEvtSignalI (pin_thread, (eventmask_t)1);
914             }
915
916 #if defined(DEBUG_CIR)
917           if (cirinput_p - cirinput < MAX_CIRINPUT_BIT)
918             {
919               *cirinput_p++ = 0xffff;
920               *cirinput_p++ = (uint16_t)chTimeNow ();
921             }
922           intr_ovf++;
923 #endif
924         }
925     }
926 }