75e84ef357b404341e324ca689960ccf37f61b58
[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
175 #if defined(DEBUG_CIR)
176 static uint16_t intr_ext;
177 static uint16_t intr_trg;
178 static uint16_t intr_ovf;
179
180 #define MAX_CIRINPUT_BIT 512
181 static uint16_t cirinput[MAX_CIRINPUT_BIT];
182 static uint16_t *cirinput_p;
183 #endif
184
185 static uint32_t cir_data;
186 static uint16_t cir_data_more;
187 static uint8_t cir_proto;
188 #define CIR_PROTO_RC5   1
189 #define CIR_PROTO_RC6   2
190 #define CIR_PROTO_OTHER 3
191 #define CIR_PROTO_SONY  4
192 #define CIR_PROTO_NEC   5
193 #define CIR_PROTO_SHARP 6
194
195
196 /* CIR_DATA_ZERO: Used for zero-bit handling of RC-5/RC-6 */
197 static uint8_t cir_data_zero;
198
199 static uint8_t cir_seq;
200
201 static systime_t cir_input_last;
202 #define CIR_PERIOD_INHIBIT_CHATTER 200 /* mili second */
203
204 static void
205 cir_init (void)
206 {
207   cir_data = 0;
208   cir_seq = 0;
209   /* Don't touch cir_proto here */
210   cir_ext_enable ();
211 }
212
213
214 #define CH_RETURN    0x0d
215 #define CH_BACKSPACE 0x08
216
217 struct codetable {
218   uint16_t cir_code;
219   uint8_t  char_code;
220 };
221
222 /* NOTE: no way to input '0' */
223 static const struct codetable
224 cir_codetable_dell_mr425[] = {
225   {0x10, '7' },          /* Speaker Louder       */
226   {0x11, '8' },          /* Speaker Quieter      */
227   {0x0d, '9' },          /* Speaker Mute         */
228   {0xce, 'a' },          /* Black triangle UP    */
229   {0xcf, 'b' },          /* Black triangle DOWN  */
230   {0x58, 'c' },          /* White triangle UP    */
231   {0x5a, 'd' },          /* White triangle LEFT  */
232   {0x5c, CH_RETURN },    /* Check                */
233   {0x5b, 'e' },          /* White triangle RIGHT */
234   {0xa4, CH_BACKSPACE }, /* Back                 */
235   {0x59, 'f' },          /* White triangle DOWN  */
236   {0x2f, '1' },          /* Rewind               */
237   {0x2c, '2' },          /* Play / Pause         */
238   {0x2e, '3' },          /* Forward              */
239   {0x21, '4' },          /* Skip backward        */
240   {0x31, '5' },          /* Stop                 */
241   {0x20, '6' },          /* Skip forward         */
242
243   {0, 0} /* <<END>>   */
244 };
245
246 #define CIR_ADDR_SHARP_AQUOS 0x028f
247 static const struct codetable
248 cir_codetable_aquos[] = {
249   { 0x0116, ' ' }, /* Power */
250   { 0x025e, '0' }, /* d */
251   { 0x024e, '1' }, /* 1 */
252   { 0x024f, '2' }, /* 2 */
253   { 0x0250, '3' }, /* 3 */
254   { 0x0251, '4' }, /* 4 */
255   { 0x0252, '5' }, /* 5 */
256   { 0x0253, '6' }, /* 6 */
257   { 0x0254, '7' }, /* 7 */
258   { 0x0255, '8' }, /* 8 */
259   { 0x0256, '9' }, /* 9 */
260   { 0x0257, 'a' }, /* 10/0 */
261   { 0x0258, 'b' }, /* 11 */
262   { 0x0259, 'c' }, /* 12 */
263   { 0x0111, 'd' }, /* Ch ^ */
264   { 0x0112, 'e' }, /* Ch v */
265   { 0x0114, 'f' }, /* Vol + */
266   { 0x0115, 'g' }, /* Vol - */
267   { 0x0117, 'h' }, /* Mute */
268   { 0x0280, 'i' }, /* BLUE */
269   { 0x0281, 'j' }, /* RED */
270   { 0x0282, 'k' }, /* GREEN */
271   { 0x0283, 'l' }, /* YELLOW */
272   { 0x011b, 'm' }, /* DISPLAY CONTROL (gamen hyouji)     */
273   { 0x01d5, 'n' }, /* DISPLAY SIZE */
274   { 0x0157, 'o' }, /* UP */
275   { 0x01d7, 'p' }, /* LEFT */
276   { 0x01d8, 'q' }, /* RIGHT */
277   { 0x0120, 'r' }, /* DOWN */
278   { 0x0152, CH_RETURN }, /* Commit (kettei) */
279   { 0x01e4, CH_BACKSPACE }, /* Back (modoru) */
280   { 0x01f5, 's' }, /* Quit (shuuryou) */
281   { 0x0b03, 't' }, /* Rewind (hayamodoshi) */
282   { 0x0b01, 'u' }, /* Play (saisei) */
283   { 0x0b04, 'v' }, /* Forward (hayaokuri) */
284   { 0x0b02, 'w' }, /* Stop (teishi) */
285   { 0x028a, 'x' }, /* BS */
286   { 0x028b, 'y' }, /* CS */
287   { 0x025f, 'z' }, /* Program information (bangumi jouhou) */
288   { 0x0260, '\\' }, /* Program table (bangumi hyou) */
289   { 0x0118, '|' }, /* Sound channel (onsei kirikae) */
290   { 0x028e, '[' }, /* Ground Analog (chijou A) */
291   { 0x0289, ']' }, /* Ground Digital (chijou D) */
292
293   { 0x0b07, '\"' }, /* Feature select (kinou sentaku) */
294   { 0x026b, '.' }, /* TV/Radio/Data (terebi/rajio/data) */
295   { 0x025a, ',' }, /* 3 code input (3 keta nyuuryoku) */
296   { 0x0267, ':' }, /* subtitle (jimaku) */
297   { 0x0159, ';' }, /* hold (seishi) */
298
299   { 0x01c4, 'A' }, /* Menu */
300   { 0x011a, 'B' }, /* Off timer */
301   { 0x0121, 'C' }, /* CATV */
302   { 0x0b05, 'D' }, /* Record */
303   { 0x0b06, 'E' }, /* Recording stop */
304   { 0x0113, 'F' }, /* Inputs (nyuuryoku kirikae) */
305   { 0x0275, 'G' }, /* other programs (ura bangumi) */
306   { 0x0266, 'H' }, /* signal control (eizou kirikae) */
307   { 0x01e7, 'I' }, /* AV position  */
308   { 0x027f, 'J' }, /* i.LINK */
309   { 0x0b00, 'K' }, /* Recorder power */
310   { 0x028f, 'L' }, /* as you like it (okonomi senkyoku) */
311
312   {0, 0} /* <<END>>   */
313 };
314
315 #define CIR_ADDR_TOSHIBA_REGZA 0xbf40
316 static const struct codetable
317 cir_codetable_regza[] = {
318   { 0x12, ' ' }, /* Power */
319   { 0x14, '0' }, /* d (data) */
320   { 0x01, '1' }, /* 1 */
321   { 0x02, '2' }, /* 2 */
322   { 0x03, '3' }, /* 3 */
323   { 0x04, '4' }, /* 4 */
324   { 0x05, '5' }, /* 5 */
325   { 0x06, '6' }, /* 6 */
326   { 0x07, '7' }, /* 7 */
327   { 0x08, '8' }, /* 8 */
328   { 0x09, '9' }, /* 9 */
329   { 0x0a, 'a' }, /* 10 */
330   { 0x0b, 'b' }, /* 11 */
331   { 0x0c, 'c' }, /* 12 */
332   { 0x1b, 'd' }, /* Ch ^ */
333   { 0x1f, 'e' }, /* Ch v */
334   { 0x1a, 'f' }, /* Vol + */
335   { 0x1e, 'g' }, /* Vol - */
336   { 0x10, 'h' }, /* Mute */
337   { 0x73, 'i' }, /* BLUE */
338   { 0x74, 'j' }, /* RED */
339   { 0x75, 'k' }, /* GREEN */
340   { 0x76, 'l' }, /* YELLOW */
341   { 0x1c, 'm' }, /* Display control */
342   { 0x2b, 'n' }, /* Display size */
343   { 0x3e, 'o' }, /* UP */
344   { 0x5f, 'p' }, /* LEFT */
345   { 0x5b, 'q' }, /* RIGHT */
346   { 0x3f, 'r' }, /* DOWN */
347   { 0x3d, CH_RETURN }, /* Commit (kettei) */
348   { 0x3b, CH_BACKSPACE }, /* Back (modoru) */
349   { 0x3c, 's' }, /* Quit (shuuryou) */
350   { 0x2c, 't' }, /* << (Rewind) */
351   { 0x2d, 'u' }, /* >/|| (Play/Stop) */
352   { 0x2e, 'v' }, /* >> (Forward) */
353   { 0x2b, 'w' }, /* Stop (teishi) */
354   { 0x7c, 'x' }, /* BS */
355   { 0x7d, 'y' }, /* CS */
356   { 0x71, 'z' }, /* Program information (bangumi setsumei) */
357   { 0x77, '\\' }, /* Mini program table (mini bangumihyou) */
358   { 0x13, '|' }, /* Sound (onta kirikae) */
359   { 0x7a, '[' }, /* Ground Digital (chideji) */
360   { 0x7b, ']' }, /* Ground Analog (chiana) */
361
362   { 0xd0, '\"' }, /* Settings Menu (settei menu) */
363   { 0x6d, '.' }, /* Radio/Data (rajio/data) */
364   { 0x60, ',' }, /* CH 10-key input (search) */
365   { 0x52, ':' }, /* subtitle (jimaku) */
366   { 0x50, ';' }, /* hold (seishi) */
367
368   { 0x3a, 'A' }, /* Input- (nyuuryokukirikae-) */
369   { 0x0f, 'B' }, /* Input+ (nyuuryokukirikae+) */
370   { 0x29, 'C' }, /* Two screens (nigamen) */
371   { 0x25, 'D' }, /* Broadband */
372   { 0x27, 'E' }, /* |<< Skip backward */
373   { 0x26, 'F' }, /* >>| Skip forward  */
374   { 0x61, '!' }, /* 1 NHK1 */
375   { 0x62, '@' }, /* 2 NHK2 */
376   { 0x63, '#' }, /* 3 NHKh */
377   { 0x64, '$' }, /* 4 BS Nihon TV */
378   { 0x65, '%' }, /* 5 BS Asashi */
379   { 0x66, '^' }, /* 6 BS-i */
380   { 0x67, '&' }, /* 7 BSJ */
381   { 0x68, '*' }, /* 8 BS Fuji */
382   { 0x69, '(' }, /* 9 WOW */
383   { 0x6a, ')' }, /* 10 Star */
384   { 0x6b, '-' }, /* 11 BS11 */
385   { 0x6c, '+' }, /* 12 TwellV */
386   { 0x27, '=' }, /* Quick (Delete) */
387   { 0x34, '<' }, /* REGZA link */
388   { 0x6e, '>' }, /* Program Table */
389   { 0x20, '/' }, /* ^^ */
390   { 0x22, '\'' }, /* << */
391   { 0x23, '?' }, /* >> */
392   { 0x21, '_' }, /* vv */
393
394   {0, 0} /* <<END>>   */
395 };
396
397 static const struct codetable
398 cir_codetable_bravia[] = {
399   { 0x15, ' ' }, /* Power */
400   { 0x95, '0' }, /* d (16-bit: 0x4b) */
401   { 0x00, '1' }, /* 1 */
402   { 0x01, '2' }, /* 2 */
403   { 0x02, '3' }, /* 3 */
404   { 0x03, '4' }, /* 4 */
405   { 0x04, '5' }, /* 5 */
406   { 0x05, '6' }, /* 6 */
407   { 0x06, '7' }, /* 7 */
408   { 0x07, '8' }, /* 8 */
409   { 0x08, '9' }, /* 9 */
410   { 0x09, 'a' }, /* 10 */
411   { 0x0a, 'b' }, /* 11 */
412   { 0x0b, 'c' }, /* 12 */
413   { 0x10, 'd' }, /* CH+ */
414   { 0x11, 'd' }, /* CH- */
415   { 0x12, 'f' }, /* Vol+ */
416   { 0x13, 'g' }, /* Vol- */
417   { 0x14, 'h' }, /* Mute */
418   { 0xa4, 'i' }, /* BLUE (16-bit: 0x4b) */
419   { 0xa5, 'j' }, /* RED (16-bit: 0x4b) */
420   { 0xa6, 'k' }, /* GREEN (16-bit: 0x4b) */
421   { 0xa7, 'l' }, /* YELLOW (16-bit: 0x4b) */
422   { 0x3a, 'm' }, /* DISPLAY control (gamen hyouji) */
423   { 0x3d, 'n' }, /* Display Wide (waido kirikae) */
424   { 0x74, 'o' }, /* UP */
425   { 0x75, 'p' }, /* DOWN */
426   { 0x33, 'q' }, /* RIGHT */
427   { 0x34, 'r' }, /* LEFT */
428   { 0x65, CH_RETURN }, /* Commit (kettei) */
429   { 0xa3, CH_BACKSPACE }, /* Back (modoru) (16-bit: 0x4b) */
430   { 0xac, 's' }, /* BS (16-bit: 0x4b) */
431   { 0xab, 't' }, /* CS (16-bit: 0x4b) */
432   { 0x5b, 'u' }, /* Program table (bangumi hyou) (16-bit: 0x52) */
433   { 0x17, 'v' }, /* Sound channel (onsei kirikae) */
434   { 0xa8, 'w' }, /* subtitle (jimaku) (16-bit: 0x4b) */
435   { 0x5c, 'x' }, /* hold (memo) */
436   { 0xb6, 'y' }, /* Tool (16-bit: 0x4b) */
437   { 0x8c, 'z' }, /* 10 key input (10ki-) (16-bit: 0x4b) */
438   { 0x60, '!' }, /* Menu */
439   { 0xae, '@' }, /* Analog (16-bit: 0x4b) */
440   { 0xb2, '#' }, /* Digital (16-bit: 0x4b) */
441   { 0x25, '$' }, /* Input (nyuuryoku kirikae) */
442
443   {0, 0} /* <<END>>   */,
444 };
445
446 static int
447 ch_is_backspace (int ch)
448 {
449   return ch == CH_BACKSPACE;
450 }
451
452 static int
453 ch_is_enter (int ch)
454 {
455   return ch == CH_RETURN;
456 }
457
458 /* liner search is good enough for this small amount of data */
459 static uint8_t
460 find_char_codetable (uint32_t cir_code, const struct codetable *ctp)
461 {
462   while (ctp->cir_code != 0x0000 || ctp->char_code != 0x00)
463     if (ctp->cir_code == cir_code)
464       return ctp->char_code;
465     else
466       ctp++;
467
468   /* Not found */
469   return cir_code & 0xff;
470 }
471
472 static int
473 hex (int x)
474 {
475   if (x < 10)
476     return x + '0';
477   else
478     return (x - 10) + 'a';
479 }
480
481 static int
482 cir_getchar (systime_t timeout)
483 {
484   uint16_t cir_addr;
485   eventmask_t m;
486 #if defined(DEBUG_CIR)
487   uint16_t *p;
488 #endif
489
490 #if defined(DEBUG_CIR)
491   cirinput_p = cirinput;
492 #endif
493
494   chEvtClear (ALL_EVENTS);
495   cir_init ();
496
497   m = chEvtWaitOneTimeout (ALL_EVENTS, timeout);
498   if (m == 0)
499     return -1;
500
501 #if defined(DEBUG_CIR)
502   DEBUG_INFO ("****\r\n");
503   DEBUG_SHORT (intr_ext);
504   DEBUG_SHORT (intr_trg);
505   DEBUG_SHORT (intr_ovf);
506   DEBUG_INFO ("----\r\n");
507   for (p = cirinput; p < cirinput_p; p++)
508     DEBUG_SHORT (*p);
509   DEBUG_INFO ("====\r\n");
510
511   cirinput_p = cirinput;
512
513   DEBUG_INFO ("**** CIR data:");
514   DEBUG_WORD (cir_data);
515   if (cir_seq > 48)
516     DEBUG_SHORT (cir_data_more);
517   DEBUG_BYTE (cir_seq);
518 #endif
519
520   switch (cir_proto)
521     {
522     case CIR_PROTO_RC5:
523       cir_data &= 0x003f;
524       goto err;
525     case CIR_PROTO_RC6:
526       cir_addr = cir_data >> 8; /* in case of cir_seq == 16.  32??? */
527       cir_data &= 0x00ff;
528       return find_char_codetable (cir_data, cir_codetable_dell_mr425);
529     case CIR_PROTO_NEC:
530       cir_addr = cir_data&0xffff;
531       if (cir_addr == CIR_ADDR_TOSHIBA_REGZA)
532         {
533           cir_data = (cir_data >> 16) & 0x00ff;
534           return find_char_codetable (cir_data, cir_codetable_regza);
535         }
536       else
537         goto err;
538     case CIR_PROTO_SHARP:
539       cir_addr = cir_data&0x0fff;
540       if (cir_addr == CIR_ADDR_SHARP_AQUOS)
541         {
542           cir_data = (cir_data>>16)&0x0fff;
543           return find_char_codetable (cir_data, cir_codetable_aquos);
544         }
545       else
546         goto err;
547     case CIR_PROTO_SONY:
548       /* Remove ADDRESS bits and filter COMMAND bits */
549       if (cir_seq == 1 + 12)
550         {
551           cir_addr = cir_data >> 7;
552           cir_data = cir_data & 0x007f;
553           /* ADDRESS = 0x01 (5-bit) */
554         }
555       else
556         {
557           cir_addr = cir_data >> 8;
558           cir_data = cir_data & 0x00ff;
559           /* ADDRESS = 0x4b or 0x52 (7-bit) */
560         }
561       return find_char_codetable (cir_data, cir_codetable_bravia);
562     err:
563     default:
564       /* encode debug information */
565       pin_input_len = 16;
566       pin_input_buffer[0] = hex (cir_proto >> 4);
567       pin_input_buffer[1] = hex (cir_proto & 0x0f);
568       pin_input_buffer[2] = ':';
569       pin_input_buffer[3] = hex ((cir_data >> 28) & 0x0f);
570       pin_input_buffer[4] = hex ((cir_data >> 24) & 0x0f);
571       pin_input_buffer[5] = hex ((cir_data >> 20) & 0x0f);
572       pin_input_buffer[6] = hex ((cir_data >> 16) & 0x0f);
573       pin_input_buffer[7] = hex ((cir_data >> 12) & 0x0f);
574       pin_input_buffer[8] = hex ((cir_data >> 8) & 0x0f);
575       pin_input_buffer[9] = hex ((cir_data >> 4) & 0x0f);
576       pin_input_buffer[10] = hex (cir_data & 0x0f);
577       pin_input_buffer[11] = ':';
578       pin_input_buffer[12] = hex ((cir_data_more >> 12) & 0x0f);
579       pin_input_buffer[13] = hex ((cir_data_more >> 8) & 0x0f);
580       pin_input_buffer[14] = hex ((cir_data_more >> 4) & 0x0f);
581       pin_input_buffer[15] = hex (cir_data_more & 0x0f);
582       return CH_RETURN;
583     }
584 }
585
586 /*
587  * RC-5 protocol doesn't have a start bit, while any other protocols
588  * have the one.
589  */
590 #define CIR_BIT_START_RC5_DETECT 1600 /* RC-5: 889us, Sony start: 2400us */
591
592 #define CIR_BIT_START_RC5_LENGTH (889 + 889/2)
593 #define CIR_BIT_PERIOD_RC6 444
594 #define CIR_BIT_PERIOD 1500
595 #define CIR_BIT_SIRC_PERIOD_ON 1000
596
597 static Thread *pin_thread;
598
599 /* 
600  * Let user input PIN string.
601  * Return length of the string.
602  * The string itself is in PIN_INPUT_BUFFER.
603  */
604 int
605 pinpad_getline (int msg_code, systime_t timeout)
606 {
607   (void)msg_code;
608
609   pin_thread = chThdSelf ();
610
611   DEBUG_INFO (">>>\r\n");
612
613   pin_input_len = 0;
614   while (1)
615     {
616       int ch;
617
618       ch = cir_getchar (timeout);
619       if (ch < 0)
620         return 0;               /* timeout */
621
622       if (ch_is_backspace (ch))
623         {
624           led_blink (2);
625           if (pin_input_len > 0)
626             pin_input_len--;
627         }
628       else if (ch_is_enter (ch))
629         break;
630       else if (pin_input_len < MAX_PIN_CHARS)
631         {
632           led_blink (0);
633           pin_input_buffer[pin_input_len++] = ch;
634         }
635     }
636
637   cir_ext_disable ();
638
639   return pin_input_len;
640 }
641
642 /**
643  * @brief  Interrupt handler of EXTI.
644  * @note   This handler will be invoked at the beginning of signal.
645  *         Setup timer to measure period and duty using PWM input mode.
646  */
647 void
648 cir_ext_interrupt (void)
649 {
650   cir_ext_disable ();
651
652 #if defined(DEBUG_CIR)
653   intr_ext++;
654   if (cirinput_p - cirinput < MAX_CIRINPUT_BIT)
655     {
656       *cirinput_p++ = 0x0000;
657       *cirinput_p++ = (uint16_t)chTimeNow ();
658     }
659 #endif
660
661   TIMx->EGR = TIM_EGR_UG;       /* Generate UEV to load PSC and ARR */
662   /* Enable Timer */
663   TIMx->SR &= ~(TIM_SR_UIF
664                 | TIM_SR_CC1IF | TIM_SR_CC2IF
665                 | TIM_SR_TIF
666                 | TIM_SR_CC1OF | TIM_SR_CC2OF);
667   TIMx->DIER = TIM_DIER_UIE /*overflow*/ | TIM_DIER_TIE /*trigger*/;
668   TIMx->CR1 |= TIM_CR1_CEN;
669 }
670
671 #define CIR_PERIOD_ON_RC5_OR_RC6 (((cir_proto == CIR_PROTO_RC5) ? 2 : 1) \
672                                   * CIR_BIT_PERIOD_RC6 * 3 / 2)
673
674 /**
675  * @brief  Interrupt handler of timer.
676  * @note   Timer is PWM input mode, this handler will be invoked on each cycle
677  */
678 void
679 cir_timer_interrupt (void)
680 {
681   uint16_t period, on, off;
682
683   period = TIMx->CCR1;
684   on = TIMx->CCR2;
685   off = period - on;
686
687   if ((TIMx->SR & TIM_SR_TIF))
688     {
689       if (cir_seq == 0)
690         {
691           if (on >= CIR_BIT_START_RC5_DETECT)
692             {
693               cir_proto = CIR_PROTO_OTHER;
694               cir_data_zero = 0;
695             }
696           else
697             {
698               cir_proto = CIR_PROTO_RC5;
699               cir_data = 1;
700               if (on >= CIR_BIT_START_RC5_LENGTH)
701                 {
702                   cir_data <<= 1;
703                   cir_seq++;
704                   if (off >= CIR_BIT_START_RC5_LENGTH)
705                     cir_data_zero = 0;
706                   else
707                     cir_data_zero = 1;
708                 }
709               else
710                 cir_data_zero = 0;
711             }
712         }
713       else if (cir_proto == CIR_PROTO_OTHER)
714         {
715           if (cir_seq == 1 + 16)
716             cir_data_more = (uint16_t)(cir_data >> 16);
717
718           cir_data >>= 1;
719           cir_data |= (period >= CIR_BIT_PERIOD) ? 0x80000000 : 0;
720
721           /* Detection of RC-6 protocol */
722           if (cir_data_zero && on > CIR_BIT_PERIOD_RC6*3/2)
723             /* TR-bit 0 is detected */
724             {
725               cir_proto = CIR_PROTO_RC6;
726               cir_seq = 0;
727               cir_data = 0;     /* ignore MODE bits */
728               if (on > CIR_BIT_PERIOD_RC6*5/2)
729                 {
730                   cir_data = 1;
731                   if (off > CIR_BIT_PERIOD_RC6*3/2)
732                     cir_data_zero = 1;
733                   else
734                     cir_data_zero = 0;
735                 }
736               else              /* Off must be short */
737                 {
738                   cir_data_zero = 1;
739                 }
740             }
741           else if ((!cir_data_zero
742                && on > CIR_BIT_PERIOD_RC6*3/2 && off > CIR_BIT_PERIOD_RC6*3/2))
743             /* TR-bit 1 is detected */
744             {
745               cir_proto = CIR_PROTO_RC6;
746               cir_seq = 0;
747               cir_data = 0;     /* ignore MODE bits */
748               cir_data_zero = 0;
749             }
750           else
751             {
752               /* Check if it looks like TR-bit of RC6 protocol */
753               if (off <= CIR_BIT_PERIOD_RC6*3/2)
754                 cir_data_zero = 0;
755               else
756                 cir_data_zero = 1;
757             }
758         }
759       else if (cir_proto == CIR_PROTO_RC5 || cir_proto == CIR_PROTO_RC6)
760         {
761           if (cir_data_zero)
762             {
763               cir_data <<= 1;
764
765               if (on > CIR_PERIOD_ON_RC5_OR_RC6)
766                 {
767                   cir_data <<= 1;
768                   cir_data |= 1;
769                   cir_seq++;
770                   if (off > CIR_PERIOD_ON_RC5_OR_RC6)
771                     cir_data_zero = 1;
772                   else
773                     cir_data_zero = 0;
774                 }
775               else              /* Off must be short */
776                 cir_data_zero = 1;
777             }
778           else
779             {
780               cir_data <<= 1;
781               cir_data |= 1;
782
783               /* On must be short */
784               if (off > CIR_PERIOD_ON_RC5_OR_RC6)
785                 cir_data_zero = 1;
786               else
787                 cir_data_zero = 0;
788             }
789         }
790
791       cir_seq++;
792
793 #if defined(DEBUG_CIR)
794       if (cirinput_p - cirinput < MAX_CIRINPUT_BIT)
795         {
796           *cirinput_p++ = on;
797           *cirinput_p++ = off;
798         }
799       intr_trg++;
800 #endif
801
802       TIMx->EGR = TIM_EGR_UG;   /* Generate UEV */
803       TIMx->SR &= ~TIM_SR_TIF;
804     }
805   else
806     /* overflow occurred */
807     {
808       systime_t now = chTimeNow ();
809
810       TIMx->SR &= ~TIM_SR_UIF;
811
812       if (on > 0)
813         {
814           uint8_t ignore_input = 0;
815
816           /* Disable the timer */
817           TIMx->CR1 &= ~TIM_CR1_CEN;
818           TIMx->DIER = 0;
819
820           if (cir_seq == 12 || cir_seq == 15)
821             {
822 #if defined(DEBUG_CIR)
823               if (cirinput_p - cirinput < MAX_CIRINPUT_BIT)
824                 {
825                   *cirinput_p++ = on;
826                   *cirinput_p++ = 0xffff;
827                 }
828 #endif
829               cir_proto = CIR_PROTO_SONY;
830               cir_data >>= 1;
831               cir_data |= (on >= CIR_BIT_SIRC_PERIOD_ON) ? 0x80000000 : 0;
832               cir_data >>= (32 - cir_seq);
833               cir_seq++;
834             }
835           else
836             {
837               if (cir_proto == CIR_PROTO_RC5 || cir_proto == CIR_PROTO_RC6)
838                 {
839                   cir_data <<= 1;
840                   cir_seq++;
841                   if (cir_data_zero)
842                     {
843                       if (on > CIR_PERIOD_ON_RC5_OR_RC6)
844                         {
845                           cir_data <<= 1;
846                           cir_data |= 1;
847                           cir_seq++;
848                         }
849                     }
850                   else
851                     cir_data |= 1;
852                 }
853               /* Or else, it must be the stop bit, just ignore */
854             }
855
856           if (now - cir_input_last < CIR_PERIOD_INHIBIT_CHATTER)
857             {
858               cir_input_last = now;
859               ignore_input = 1;
860             }
861           else if (cir_proto == CIR_PROTO_SONY)
862             {
863               if (cir_seq != 1 + 12 && cir_seq != 1 + 15)
864                 ignore_input = 1;
865             }
866           else if (cir_proto == CIR_PROTO_OTHER)
867             {
868               if (cir_seq == 1 + 32)
869                 {
870                   if (((cir_data >> 16) & 0xff) == ((cir_data >> 24) ^ 0xff))
871                     cir_proto = CIR_PROTO_NEC;
872                   else
873                     ignore_input = 1;
874                 }
875               else if (cir_seq == 1 + 48)
876                 {
877                   if ((cir_data >> 28) ==
878                       (((cir_data_more >> 12) & 0x0f)
879                        ^ ((cir_data_more >> 8) & 0x0f)
880                        ^ ((cir_data_more >> 4) & 0x0f)
881                        ^ (cir_data_more & 0x0f)
882                        ^ ((cir_data >> 24) & 0x0f)
883                        ^ ((cir_data >> 20) & 0x0f) ^ ((cir_data >> 16) & 0x0f)
884                        ^ ((cir_data >> 12) & 0x0f) ^ ((cir_data >> 8) & 0x0f)
885                        ^ ((cir_data >> 4) & 0x0f) ^ (cir_data & 0x0f)))
886                     cir_proto = CIR_PROTO_SHARP;
887                   else
888                     ignore_input = 1;
889                 }
890               else
891                 ignore_input = 1;
892             }
893           else if (cir_proto == CIR_PROTO_RC6)
894             {
895               if (cir_seq != 16 && cir_seq != 32)
896                 ignore_input = 1;
897             }
898           else if (cir_proto == CIR_PROTO_RC5)
899             {
900               if (cir_seq != 14)
901                 ignore_input = 1;
902             }
903           else
904             ignore_input = 1;
905
906           if (ignore_input)
907             /* Ignore data received and enable CIR again */
908             cir_init ();
909           else
910             {
911               cir_input_last = now;
912               /* Notify thread */
913               if (pin_thread)
914                 chEvtSignalI (pin_thread, (eventmask_t)1);
915             }
916
917 #if defined(DEBUG_CIR)
918           if (cirinput_p - cirinput < MAX_CIRINPUT_BIT)
919             {
920               *cirinput_p++ = 0xffff;
921               *cirinput_p++ = (uint16_t)chTimeNow ();
922             }
923           intr_ovf++;
924 #endif
925         }
926     }
927 }