pin-cir: support Sony protocol
[gnuk/gnuk.git] / src / pin-cir.c
1 /*
2  * pin-cir.c -- PIN input device support (Consumer Infra-Red)
3  *
4  * Copyright (C) 2010 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  * NEC Protocol: (START + 32-bit + STOP) + (START + STOP) x N
35  *      32-bit: 8-bit command inverted + 8-bit command + 16-bit address
36  *      Example: Controller of Toshiba REGZA
37  *      Example: Controller of Ceiling Light by NEC
38  *
39  * Sony Protocol: (START + 12-bit)
40  *      12-bit: 5-bit address + 7-bit command
41  *      Example: Controller of Sony BRAVIA
42  *
43  * Unknown Protocol 1: (START + 48-bit + STOP) x N
44  *      Example: Controller of Sharp AQUOS
45  *      Example: Controller of Ceiling Light by Mitsubishi
46  *
47  * Unsupported:
48  *
49  * Unknown Protocol 2: (START + 112-bit + STOP)
50  *      Example: Controller of Mitsubishi air conditioner
51  *
52  * Unknown Protocol 3: (START + 128-bit + STOP)
53  *      Example: Controller of Fujitsu air conditioner
54  *
55  * Unknown Protocol 4: (START + 152-bit + STOP)
56  *      Example: Controller of Sanyo air conditioner
57  */
58
59 /*
60  * PB0 / TIM3_CH3
61  *
62  * 72MHz
63  *
64  * Prescaler = 72
65  *
66  * 1us
67  *
68  *
69  * TIM3_CR1
70  *  CKD  = 10 (sampling x4)
71  *  ARPE = 0  (not buffered)
72  *  CMS  = 00 (up counter)
73  *  DIR  = 0  (up counter)
74  *  OPM  = 0  (up counter)
75  *  URS  = 1  (update request source: overflow only)
76  *  UDIS = 0  (UEV (update event) enabled)
77  *  CEN  = 1  (counter enable)
78  *
79  * TIM3_CR2
80  *  TI1S = 1 (TI1 is XOR of ch1, ch2, ch3)
81  *  MMS  = 000 (TRGO at Reset)
82  *  CCDS = 0 (DMA on capture)
83  *  RSVD = 000
84  *
85  * TIM3_SMCR
86  *  ETP  = 0
87  *  ECE  = 0
88  *  ETPS = 00
89  *  ETF  = 0000
90  *  MSM  = 0
91  *  TS   = 101 (TI1FP1 selected)
92  *  RSVD = 0
93  *  SMS  = 100 (Reset-mode)
94  *
95  * TIM3_DIER
96  *
97  * TIM3_SR
98  *
99  * TIM3_EGR
100  *
101  * TIM3_CCMR1
102  *  CC1S = 01 (TI1 selected)
103  *  CC2S = 10 (TI1 selected)
104  *
105  * TIM3_CCMR2
106  *
107  * TIM3_CCER
108  *  CC2P = 1 (polarity = falling edge: TI1FP1)
109  *  CC2E = 1
110  *  CC1P = 0 (polarity = rising edge: TI1FP1)
111  *  CC1E = 1
112  *
113  * TIM3_CNT
114  * TIM3_PSC = 71
115  * TIM3_ARR = 18000
116  *
117  * TIM3_CCR1  period
118  * TIM3_CCR2  duty
119  *
120  * TIM3_DCR
121  * TIM3_DMAR
122  */
123
124 #define PINDISP_TIMEOUT_INTERVAL0       MS2ST(25)
125 #define PINDISP_TIMEOUT_INTERVAL1       MS2ST(300)
126
127 static void
128 pindisp (uint8_t c)
129 {
130   switch (c)
131     {
132     case 'G':
133       palWritePort (IOPORT2, 0xa1ff);
134       break;
135     case 'P':
136       palWritePort (IOPORT2, 0x98ff);
137       break;
138     case '.':
139       palWritePort (IOPORT2, 0x7fff);
140       break;
141     default:
142       palWritePort (IOPORT2, 0xffff);
143     }
144 }
145
146 #if defined(DEBUG_CIR)
147 static uint16_t intr_ext;
148 static uint16_t intr_trg;
149 static uint16_t intr_ovf;
150
151 #define MAX_CIRINPUT_BIT 512
152 static uint16_t cirinput[MAX_CIRINPUT_BIT];
153 static uint16_t *cirinput_p;
154 #endif
155
156 static uint32_t cir_data;
157 static uint8_t cir_seq;
158 #define CIR_BIT_PERIOD 1500
159 #define CIR_BIT_SIRC_PERIOD_ON 1000
160
161 static void
162 cir_init (void)
163 {
164   cir_data = 0;
165   cir_seq = 0;
166   cir_ext_enable ();
167 }
168
169 static Thread *pin_thread;
170
171 msg_t
172 pin_main (void *arg)
173 {
174   uint8_t s = 0;
175
176   (void)arg;
177   pin_thread = chThdSelf ();
178
179 #if defined(DEBUG_CIR)
180   cirinput_p = cirinput;
181 #endif
182
183   chEvtClear (ALL_EVENTS);
184
185   cir_init ();
186
187   while (!chThdShouldTerminate ())
188     {
189       eventmask_t m;
190
191       m = chEvtWaitOneTimeout (ALL_EVENTS, PINDISP_TIMEOUT_INTERVAL1);
192
193       if (m)
194         {
195 #if defined(DEBUG_CIR)
196           uint16_t *p;
197
198           DEBUG_INFO ("****\r\n");
199           DEBUG_SHORT (intr_ext);
200           DEBUG_SHORT (intr_trg);
201           DEBUG_SHORT (intr_ovf);
202           DEBUG_INFO ("----\r\n");
203           for (p = cirinput; p < cirinput_p; p++)
204             DEBUG_SHORT (*p);
205           DEBUG_INFO ("====\r\n");
206
207           cirinput_p = cirinput;
208 #endif
209           DEBUG_INFO ("**** CIR data:");
210           DEBUG_WORD (cir_data);
211           cir_init ();
212         }
213
214       switch (s++)
215         {
216         case 0:
217           pindisp ('G');
218           break;
219         case 1:
220           pindisp ('P');
221           break;
222         case 2:
223           pindisp ('G');
224           break;
225         case 3:
226           pindisp ('.');
227           break;
228         default:
229           pindisp (' ');
230           s = 0;
231           break;
232         }
233
234       chThdSleep (PINDISP_TIMEOUT_INTERVAL0);
235     }
236
237   return 0;
238 }
239
240 void
241 cir_ext_interrupt (void)
242 {
243   cir_ext_disable ();
244
245 #if defined(DEBUG_CIR)
246   intr_ext++;
247   if (cirinput_p - cirinput < MAX_CIRINPUT_BIT)
248     {
249       *cirinput_p++ = 0x0000;
250       *cirinput_p++ = (uint16_t)chTimeNow ();
251     }
252 #endif
253
254   TIM3->EGR = TIM_EGR_UG;       /* Generate UEV to load PSC and ARR */
255   /* Enable Timer */
256   TIM3->SR &= ~(TIM_SR_UIF
257                 | TIM_SR_CC1IF | TIM_SR_CC2IF
258                 | TIM_SR_TIF
259                 | TIM_SR_CC1OF | TIM_SR_CC2OF);
260   TIM3->DIER = TIM_DIER_UIE /*overflow*/ | TIM_DIER_TIE /*trigger*/;
261   TIM3->CR1 |= TIM_CR1_CEN;
262 }
263
264 void
265 cir_timer_interrupt (void)
266 {
267   uint16_t period, on, off;
268
269   period = TIM3->CCR1;
270   on = TIM3->CCR2;
271   off = period - on;
272
273   if ((TIM3->SR & TIM_SR_TIF))
274     {
275       if (cir_seq >= 1)
276         {
277           cir_data >>= 1;
278           cir_data |= (period >= CIR_BIT_PERIOD) ? 0x80000000 : 0;
279         }
280
281       cir_seq++;
282
283 #if defined(DEBUG_CIR)
284       if (cirinput_p - cirinput < MAX_CIRINPUT_BIT)
285         {
286           *cirinput_p++ = on;
287           *cirinput_p++ = off;
288         }
289       intr_trg++;
290 #endif
291
292       TIM3->EGR = TIM_EGR_UG;   /* Generate UEV */
293       TIM3->SR &= ~TIM_SR_TIF;
294     }
295   else
296     /* overflow occurred */
297     {
298       TIM3->SR &= ~TIM_SR_UIF;
299
300       if (on > 0)
301         {
302           /* Disable the timer */
303           TIM3->CR1 &= ~TIM_CR1_CEN;
304           TIM3->DIER = 0;
305
306           if (cir_seq == 12)
307             {
308 #if defined(DEBUG_CIR)
309               if (cirinput_p - cirinput < MAX_CIRINPUT_BIT)
310                 {
311                   *cirinput_p++ = on;
312                   *cirinput_p++ = 0xffff;
313                 }
314 #endif
315               cir_data >>= 21;
316               cir_data |= (on >= CIR_BIT_SIRC_PERIOD_ON) ? 0x800: 0;
317               cir_seq++;
318             }
319           else
320             /* It must be the stop bit, just ignore */
321             {
322               ;
323             }
324
325           if (cir_seq == 1 + 12
326 #if defined(DEBUG_CIR)
327               || cir_seq > 12
328 #endif
329               || cir_seq == 1 + 32
330               || cir_seq == 1 + 48)
331             {
332               /* Notify thread */
333               chEvtSignal (pin_thread, (eventmask_t)1);
334             }
335           else
336             /* Ignore data received and enable CIR again */
337             cir_init ();
338
339 #if defined(DEBUG_CIR)
340           if (cirinput_p - cirinput < MAX_CIRINPUT_BIT)
341             {
342               *cirinput_p++ = 0xffff;
343               *cirinput_p++ = (uint16_t)chTimeNow ();
344             }
345           intr_ovf++;
346 #endif
347         }
348     }
349 }