support PIN modification
[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 #if 0
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  * Philips RC-5 Protocol: 14-bit (MSB first)
39  *
40  * Philips RC-6 Protocol: (START + 1 + MODE + TR + 32-bit / 16-bit) (MSB first)
41  *                                     3-bit      (mode 6 / mode 0)
42  *      Example: Controller of DELL (mode 6)
43  *
44  * NEC Protocol: (START + 32-bit + STOP) + (START + STOP) x N  (LSB first)
45  *      32-bit: 8-bit command inverted + 8-bit command + 16-bit address
46  *      Example: Controller of Toshiba REGZA
47  *      Example: Controller of Ceiling Light by NEC
48  *
49  * Sony Protocol: (START + 12-bit) or (START + 15-bit)  (LSB first)
50  *      12-bit: 5-bit address + 7-bit command
51  *      Example: Controller of Sony BRAVIA
52  *
53  * Sharp Protocol: (START + 48-bit + STOP) x N  (LSB first)
54  *      48-bit: 32-bit address + 12-bit command + 4-bit parity
55  *      Example: Controller of Sharp AQUOS
56  *      Example: Controller of Ceiling Light by Mitsubishi
57  *
58  * Unsupported:
59  *
60  * Unknown Protocol 2: (START + 112-bit + STOP)  (LSB first)
61  *      Example: Controller of Mitsubishi air conditioner
62  *
63  * Unknown Protocol 3: (START + 128-bit + STOP)  (LSB first)
64  *      Example: Controller of Fujitsu air conditioner
65  *
66  * Unknown Protocol 4: (START + 152-bit + STOP)  (LSB first)
67  *      Example: Controller of Sanyo air conditioner
68  *
69  */
70
71 /*
72  * PB0 / TIM3_CH3
73  *
74  * 72MHz
75  *
76  * Prescaler = 72
77  *
78  * 1us
79  *
80  *
81  * TIM3_CR1
82  *  CKD  = 10 (sampling x4)
83  *  ARPE = 0  (not buffered)
84  *  CMS  = 00 (up counter)
85  *  DIR  = 0  (up counter)
86  *  OPM  = 0  (up counter)
87  *  URS  = 1  (update request source: overflow only)
88  *  UDIS = 0  (UEV (update event) enabled)
89  *  CEN  = 1  (counter enable)
90  *
91  * TIM3_CR2
92  *  TI1S = 1 (TI1 is XOR of ch1, ch2, ch3)
93  *  MMS  = 000 (TRGO at Reset)
94  *  CCDS = 0 (DMA on capture)
95  *  RSVD = 000
96  *
97  * TIM3_SMCR
98  *  ETP  = 0
99  *  ECE  = 0
100  *  ETPS = 00
101  *  ETF  = 0000
102  *  MSM  = 0
103  *  TS   = 101 (TI1FP1 selected)
104  *  RSVD = 0
105  *  SMS  = 100 (Reset-mode)
106  *
107  * TIM3_DIER
108  *
109  * TIM3_SR
110  *
111  * TIM3_EGR
112  *
113  * TIM3_CCMR1
114  *  CC1S = 01 (TI1 selected)
115  *  CC2S = 10 (TI1 selected)
116  *
117  * TIM3_CCMR2
118  *
119  * TIM3_CCER
120  *  CC2P = 1 (polarity = falling edge: TI1FP1)
121  *  CC2E = 1
122  *  CC1P = 0 (polarity = rising edge: TI1FP1)
123  *  CC1E = 1
124  *
125  * TIM3_CNT
126  * TIM3_PSC = 71
127  * TIM3_ARR = 18000
128  *
129  * TIM3_CCR1  period
130  * TIM3_CCR2  duty
131  *
132  * TIM3_DCR
133  * TIM3_DMAR
134  */
135
136 #define PINDISP_TIMEOUT_INTERVAL0       MS2ST(25)
137 #define PINDISP_TIMEOUT_INTERVAL1       MS2ST(300)
138
139 static void
140 pindisp (uint8_t c)
141 {
142 #if defined(HAVE_7SEGLED)
143   switch (c)
144     {
145     case 'G':
146       palWritePort (IOPORT2, 0xa1ff);
147       break;
148     case 'P':
149       palWritePort (IOPORT2, 0x98ff);
150       break;
151     case '.':
152       palWritePort (IOPORT2, 0x7fff);
153       break;
154     default:
155       palWritePort (IOPORT2, 0xffff);
156     }
157 #else
158   (void)c;
159 #endif
160 }
161
162 #if defined(DEBUG_CIR)
163 static uint16_t intr_ext;
164 static uint16_t intr_trg;
165 static uint16_t intr_ovf;
166
167 #define MAX_CIRINPUT_BIT 512
168 static uint16_t cirinput[MAX_CIRINPUT_BIT];
169 static uint16_t *cirinput_p;
170 #endif
171
172 static uint32_t cir_data;
173 static uint16_t cir_data_more;
174 static uint8_t cir_proto;
175 #define CIR_PROTO_RC5   1
176 #define CIR_PROTO_RC6   2
177 #define CIR_PROTO_OTHER 3
178 #define CIR_PROTO_SONY  4
179 #define CIR_PROTO_NEC   5
180 #define CIR_PROTO_SHARP 6
181
182 #define CIR_KEY_RC6_ENTER       0x0d   /* Mute */
183 #define CIR_KEY_RC6_BACKSPACE   0xa4   /* <=   */
184 #define CIR_KEY_NEC_ENTER       0x3d   /* 'kettei' */
185 #define CIR_KEY_NEC_BACKSPACE   0x3b   /* 'modoru' */
186 #define CIR_KEY_SONY_ENTER      0x65   /* 'kettei' */
187 #define CIR_KEY_SONY_BACKSPACE  0xa3   /* 'modoru' */
188 #define CIR_KEY_SHARP_ENTER     0x0252 /* 'kettei' */
189 #define CIR_KEY_SHARP_BACKSPACE 0xe4   /* 'modoru' */
190
191 /* CIR_DATA_ZERO: Used for zero-bit handling of RC-5/RC-6 */
192 static uint8_t cir_data_zero;
193
194 static uint8_t cir_seq;
195
196 static systime_t cir_input_last;
197 #define CIR_PERIOD_INHIBIT_CHATTER 200 /* mili second */
198
199 /*
200  * RC-5 protocol doesn't have a start bit, while any other protocols
201  * have the one.
202  */
203 #define CIR_BIT_START_RC5_DETECT 1600 /* RC-5: 889us, Sony start: 2400us */
204
205 #define CIR_BIT_START_RC5_LENGTH (889 + 889/2)
206 #define CIR_BIT_PERIOD_RC6 444
207 #define CIR_BIT_PERIOD 1500
208 #define CIR_BIT_SIRC_PERIOD_ON 1000
209
210 static void
211 cir_init (void)
212 {
213   cir_data = 0;
214   cir_seq = 0;
215   /* Don't touch cir_proto here */
216   cir_ext_enable ();
217 }
218
219 static Thread *pin_thread;
220
221 static int
222 cir_key_is_backspace (void)
223 {
224   return (cir_proto == CIR_PROTO_RC6 && cir_data == CIR_KEY_RC6_BACKSPACE)
225     || (cir_proto == CIR_PROTO_NEC && cir_data == CIR_KEY_NEC_BACKSPACE)
226     || (cir_proto == CIR_PROTO_SONY && cir_data == CIR_KEY_SONY_BACKSPACE)
227     || (cir_proto == CIR_PROTO_SHARP && cir_data == CIR_KEY_SHARP_BACKSPACE);
228 }
229
230 static int
231 cir_key_is_enter (void)
232 {
233   return (cir_proto == CIR_PROTO_RC6 && cir_data == CIR_KEY_RC6_ENTER)
234     || (cir_proto == CIR_PROTO_NEC && cir_data == CIR_KEY_NEC_ENTER)
235     || (cir_proto == CIR_PROTO_SONY && cir_data == CIR_KEY_SONY_ENTER)
236     || (cir_proto == CIR_PROTO_SHARP && cir_data == CIR_KEY_SHARP_ENTER);
237 }
238
239 msg_t
240 pin_main (void *arg)
241 {
242   uint8_t s = 0;
243   int msg_code = (int)arg;
244
245   (void)msg_code;
246   pin_thread = chThdSelf ();
247
248 #if defined(DEBUG_CIR)
249   cirinput_p = cirinput;
250 #endif
251
252   pin_input_len = 0;
253   chEvtClear (ALL_EVENTS);
254   cir_init ();
255
256   while (!chThdShouldTerminate ())
257     {
258       eventmask_t m;
259
260       m = chEvtWaitOneTimeout (ALL_EVENTS, PINDISP_TIMEOUT_INTERVAL1);
261
262       if (m)
263         {
264 #if defined(DEBUG_CIR)
265           uint16_t *p;
266
267           DEBUG_INFO ("****\r\n");
268           DEBUG_SHORT (intr_ext);
269           DEBUG_SHORT (intr_trg);
270           DEBUG_SHORT (intr_ovf);
271           DEBUG_INFO ("----\r\n");
272           for (p = cirinput; p < cirinput_p; p++)
273             DEBUG_SHORT (*p);
274           DEBUG_INFO ("====\r\n");
275
276           cirinput_p = cirinput;
277 #endif
278           DEBUG_INFO ("**** CIR data:");
279           DEBUG_WORD (cir_data);
280           if (cir_seq > 48)
281             {
282               DEBUG_SHORT (cir_data_more);
283             }
284           DEBUG_BYTE (cir_seq);
285
286           if (cir_key_is_backspace ())
287             {
288               if (pin_input_len > 0)
289                 pin_input_len--;
290             }
291           else if (cir_key_is_enter ())
292             {
293               pindisp (' ');
294               chThdExit (0);
295             }
296           else if (pin_input_len < MAX_PIN_CHARS)
297             pin_input_buffer[pin_input_len++] = (uint8_t)cir_data;
298
299           cir_init ();
300         }
301
302       switch (s++)
303         {
304         case 0:
305           pindisp ('G');
306           break;
307         case 1:
308           pindisp ('P');
309           break;
310         case 2:
311           pindisp ('G');
312           break;
313         case 3:
314           pindisp ('.');
315           break;
316         default:
317           pindisp (' ');
318           s = 0;
319           break;
320         }
321
322       chThdSleep (PINDISP_TIMEOUT_INTERVAL0);
323     }
324
325   return 0;
326 }
327
328 void
329 cir_ext_interrupt (void)
330 {
331   cir_ext_disable ();
332
333 #if defined(DEBUG_CIR)
334   intr_ext++;
335   if (cirinput_p - cirinput < MAX_CIRINPUT_BIT)
336     {
337       *cirinput_p++ = 0x0000;
338       *cirinput_p++ = (uint16_t)chTimeNow ();
339     }
340 #endif
341
342   TIM3->EGR = TIM_EGR_UG;       /* Generate UEV to load PSC and ARR */
343   /* Enable Timer */
344   TIM3->SR &= ~(TIM_SR_UIF
345                 | TIM_SR_CC1IF | TIM_SR_CC2IF
346                 | TIM_SR_TIF
347                 | TIM_SR_CC1OF | TIM_SR_CC2OF);
348   TIM3->DIER = TIM_DIER_UIE /*overflow*/ | TIM_DIER_TIE /*trigger*/;
349   TIM3->CR1 |= TIM_CR1_CEN;
350 }
351
352 #define CIR_PERIOD_ON_RC5_OR_RC6 (((cir_proto == CIR_PROTO_RC5) ? 2 : 1) \
353                                   * CIR_BIT_PERIOD_RC6 * 3 / 2)
354
355 void
356 cir_timer_interrupt (void)
357 {
358   uint16_t period, on, off;
359
360   period = TIM3->CCR1;
361   on = TIM3->CCR2;
362   off = period - on;
363
364   if ((TIM3->SR & TIM_SR_TIF))
365     {
366       if (cir_seq == 0)
367         {
368           if (on >= CIR_BIT_START_RC5_DETECT)
369             {
370               cir_proto = CIR_PROTO_OTHER;
371               cir_data_zero = 0;
372             }
373           else
374             {
375               cir_proto = CIR_PROTO_RC5;
376               cir_data = 1;
377               if (on >= CIR_BIT_START_RC5_LENGTH)
378                 {
379                   cir_data <<= 1;
380                   cir_seq++;
381                   if (off >= CIR_BIT_START_RC5_LENGTH)
382                     cir_data_zero = 0;
383                   else
384                     cir_data_zero = 1;
385                 }
386               else
387                 cir_data_zero = 0;
388             }
389         }
390       else if (cir_proto == CIR_PROTO_OTHER)
391         {
392           if (cir_seq == 1 + 16)
393             cir_data_more = (uint16_t)(cir_data >> 16);
394
395           cir_data >>= 1;
396           cir_data |= (period >= CIR_BIT_PERIOD) ? 0x80000000 : 0;
397
398           /* Detection of RC-6 protocol */
399           if (cir_data_zero && on > CIR_BIT_PERIOD_RC6*3/2)
400             /* TR-bit 0 is detected */
401             {
402               cir_proto = CIR_PROTO_RC6;
403               cir_seq = 0;
404               cir_data = 0;     /* ignore MODE bits */
405               if (on > CIR_BIT_PERIOD_RC6*5/2)
406                 {
407                   cir_data = 1;
408                   if (off > CIR_BIT_PERIOD_RC6*3/2)
409                     cir_data_zero = 1;
410                   else
411                     cir_data_zero = 0;
412                 }
413               else              /* Off must be short */
414                 {
415                   cir_data_zero = 1;
416                 }
417             }
418           else if ((!cir_data_zero
419                && on > CIR_BIT_PERIOD_RC6*3/2 && off > CIR_BIT_PERIOD_RC6*3/2))
420             /* TR-bit 1 is detected */
421             {
422               cir_proto = CIR_PROTO_RC6;
423               cir_seq = 0;
424               cir_data = 0;     /* ignore MODE bits */
425               cir_data_zero = 0;
426             }
427           else
428             {
429               /* Check if it looks like TR-bit of RC6 protocol */
430               if (off <= CIR_BIT_PERIOD_RC6*3/2)
431                 cir_data_zero = 0;
432               else
433                 cir_data_zero = 1;
434             }
435         }
436       else if (cir_proto == CIR_PROTO_RC5 || cir_proto == CIR_PROTO_RC6)
437         {
438           if (cir_data_zero)
439             {
440               cir_data <<= 1;
441
442               if (on > CIR_PERIOD_ON_RC5_OR_RC6)
443                 {
444                   cir_data <<= 1;
445                   cir_data |= 1;
446                   cir_seq++;
447                   if (off > CIR_PERIOD_ON_RC5_OR_RC6)
448                     cir_data_zero = 1;
449                   else
450                     cir_data_zero = 0;
451                 }
452               else              /* Off must be short */
453                 cir_data_zero = 1;
454             }
455           else
456             {
457               cir_data <<= 1;
458               cir_data |= 1;
459
460               /* On must be short */
461               if (off > CIR_PERIOD_ON_RC5_OR_RC6)
462                 cir_data_zero = 1;
463               else
464                 cir_data_zero = 0;
465             }
466         }
467
468       cir_seq++;
469
470 #if defined(DEBUG_CIR)
471       if (cirinput_p - cirinput < MAX_CIRINPUT_BIT)
472         {
473           *cirinput_p++ = on;
474           *cirinput_p++ = off;
475         }
476       intr_trg++;
477 #endif
478
479       TIM3->EGR = TIM_EGR_UG;   /* Generate UEV */
480       TIM3->SR &= ~TIM_SR_TIF;
481     }
482   else
483     /* overflow occurred */
484     {
485       systime_t now = chTimeNow ();
486
487       TIM3->SR &= ~TIM_SR_UIF;
488
489       if (on > 0)
490         {
491           uint8_t ignore_input = 0;
492
493           /* Disable the timer */
494           TIM3->CR1 &= ~TIM_CR1_CEN;
495           TIM3->DIER = 0;
496
497           if (cir_seq == 12 || cir_seq == 15)
498             {
499 #if defined(DEBUG_CIR)
500               if (cirinput_p - cirinput < MAX_CIRINPUT_BIT)
501                 {
502                   *cirinput_p++ = on;
503                   *cirinput_p++ = 0xffff;
504                 }
505 #endif
506               cir_proto = CIR_PROTO_SONY;
507               cir_data >>= 1;
508               cir_data |= (on >= CIR_BIT_SIRC_PERIOD_ON) ? 0x80000000 : 0;
509               cir_data >>= (32 - cir_seq);
510               cir_seq++;
511             }
512           else
513             {
514               if (cir_proto == CIR_PROTO_RC5 || cir_proto == CIR_PROTO_RC6)
515                 {
516                   cir_data <<= 1;
517                   cir_seq++;
518                   if (cir_data_zero)
519                     {
520                       if (on > CIR_PERIOD_ON_RC5_OR_RC6)
521                         {
522                           cir_data <<= 1;
523                           cir_data |= 1;
524                           cir_seq++;
525                         }
526                     }
527                   else
528                     cir_data |= 1;
529                 }
530               /* Or else, it must be the stop bit, just ignore */
531             }
532
533           if (now - cir_input_last < CIR_PERIOD_INHIBIT_CHATTER)
534             {
535               cir_input_last = now;
536               ignore_input = 1;
537             }
538           /* Remove ADDRESS bits and filter COMMAND bits */
539           else if (cir_proto == CIR_PROTO_SONY)
540             {
541               if (cir_seq == 1 + 12)
542                 cir_data = cir_data & 0x007f;
543               else if (cir_seq == 1 + 15)
544                 cir_data = cir_data & 0x00ff;
545               else
546                 ignore_input = 1;
547             }
548           else if (cir_proto == CIR_PROTO_OTHER)
549             {
550               if (cir_seq == 1 + 32)
551                 {
552                   if (((cir_data >> 16) & 0xff) == ((cir_data >> 24) ^ 0xff))
553                     {
554                       cir_proto = CIR_PROTO_NEC;
555                       cir_data = (cir_data >> 16) & 0x00ff;
556                     }
557                   else
558                     ignore_input = 1;
559                 }
560               else if (cir_seq == 1 + 48)
561                 {
562                   if ((cir_data >> 28) ==
563                       (((cir_data_more >> 12) & 0x0f)
564                        ^ ((cir_data_more >> 8) & 0x0f)
565                        ^ ((cir_data_more >> 4) & 0x0f)
566                        ^ (cir_data_more & 0x0f)
567                        ^ ((cir_data >> 24) & 0x0f)
568                        ^ ((cir_data >> 20) & 0x0f) ^ ((cir_data >> 16) & 0x0f)
569                        ^ ((cir_data >> 12) & 0x0f) ^ ((cir_data >> 8) & 0x0f)
570                        ^ ((cir_data >> 4) & 0x0f) ^ (cir_data & 0x0f)))
571                     {
572                       cir_proto = CIR_PROTO_SHARP;
573                       cir_data = (cir_data >> 16) & 0x0fff;
574                     }
575                   else
576                     ignore_input = 1;
577                 }
578               else
579                 ignore_input = 1;
580             }
581           else if (cir_proto == CIR_PROTO_RC6)
582             {
583               if (cir_seq == 16 || cir_seq == 32)
584                 cir_data &= 0x00ff;
585               else
586                 ignore_input = 1;
587             }
588           else if (cir_proto == CIR_PROTO_RC5)
589             {
590               if (cir_seq == 14)
591                 cir_data &= 0x003f;
592               else
593                 ignore_input = 1;
594             }
595           else
596             ignore_input = 1;
597
598           if (ignore_input)
599             /* Ignore data received and enable CIR again */
600             cir_init ();
601           else
602             {
603               cir_input_last = now;
604               /* Notify thread */
605               chEvtSignal (pin_thread, (eventmask_t)1);
606             }
607
608 #if defined(DEBUG_CIR)
609           if (cirinput_p - cirinput < MAX_CIRINPUT_BIT)
610             {
611               *cirinput_p++ = 0xffff;
612               *cirinput_p++ = (uint16_t)chTimeNow ();
613             }
614           intr_ovf++;
615 #endif
616         }
617     }
618 }