PIN input CIR support change

This commit is contained in:
NIIBE Yutaka
2011-11-01 14:57:11 +09:00
parent de39c484d0
commit ed7e904aef
9 changed files with 749 additions and 291 deletions

View File

@@ -1,5 +1,30 @@
2011-11-01 Niibe Yutaka <gniibe@fsij.org> 2011-11-01 Niibe Yutaka <gniibe@fsij.org>
* boards/STBEE_MINI/board.h (TIMx): Define.
boards/STBEE/board.h (TIMx): Ditto.
boards/STM8S_DISCOVERY/board.h: Ditto.
* src/pin-cir.c (pinpad_getline): New.
(cir_timer_interrupt, cir_ext_interrupt): Use TIMx.
(cir_key_is_backspace, cir_key_is_enter, pin_main, pindisp):
Remove.
(cir_codetable_dell_mr425, cir_codetable_aquos)
(cir_codetable_regza, cir_codetable_bravia, ch_is_backspace)
(ch_is_enter, find_char_codetable, hex, cir_getchar): New.
(cir_timer_interrupt): Don't filter out ADDRESS.
* src/openpgp.c (get_pinpad_input): Don't invoke thread,
but just call pinpad_getline.
* src/main.c (display_interaction, display_fatal_code)
(display_status_code, led_blink): New.
(main): Call display_* routine.
(fatal): Notify main thread.
* src/usb_prop.c (gnuk_device_SetConfiguration): Notify main
thread.
* src/pin-cir.c (pindisp): Remove.
* boards/FST_01_00: New (for 8MHz FST-01). * boards/FST_01_00: New (for 8MHz FST-01).
* src/ac.c (calc_md): Fix comparison. * src/ac.c (calc_md): Fix comparison.

View File

@@ -40,6 +40,10 @@
#if defined(PINPAD_SUPPORT) #if defined(PINPAD_SUPPORT)
#define HAVE_7SEGLED 1 #define HAVE_7SEGLED 1
/*
* Timer assignment for CIR
*/
#define TIMx TIM3
#endif #endif
/* /*

View File

@@ -41,6 +41,10 @@
#if defined(PINPAD_SUPPORT) #if defined(PINPAD_SUPPORT)
#define HAVE_7SEGLED 1 #define HAVE_7SEGLED 1
/*
* Timer assignment for CIR
*/
#define TIMx TIM3
#endif #endif
/* /*

View File

@@ -56,6 +56,11 @@
*/ */
#define GPIOA_LED 8 #define GPIOA_LED 8
/*
* Timer assignment for CIR
*/
#define TIMx TIM3
/* /*
* I/O ports initial setup, this configuration is established soon after reset * I/O ports initial setup, this configuration is established soon after reset
* in the initialization code. * in the initialization code.

View File

@@ -348,5 +348,16 @@ extern void dial_sw_enable (void);
extern uint8_t pin_input_buffer[MAX_PIN_CHARS]; extern uint8_t pin_input_buffer[MAX_PIN_CHARS];
extern uint8_t pin_input_len; extern uint8_t pin_input_len;
extern msg_t pin_main (void *arg); extern int pinpad_getline (int msg_code, systime_t timeout);
#define LED_ONESHOT_SHORT ((eventmask_t)1)
#define LED_ONESHOT_LONG ((eventmask_t)2)
#define LED_TWOSHOT ((eventmask_t)4)
#define LED_STATUS_MODE ((eventmask_t)8)
#define LED_INPUT_MODE ((eventmask_t)16)
#define LED_FATAL_MODE ((eventmask_t)32)
extern Thread *main_thread;
extern void led_blink (int spec);
#endif #endif

View File

@@ -1,7 +1,7 @@
/* /*
* main.c - main routine of Gnuk * main.c - main routine of Gnuk
* *
* Copyright (C) 2010 Free Software Initiative of Japan * Copyright (C) 2010, 2011 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org> * Author: NIIBE Yutaka <gniibe@fsij.org>
* *
* This file is a part of Gnuk, a GnuPG USB Token implementation. * This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -196,6 +196,161 @@ device_initialize_once (void)
static volatile uint8_t fatal_code; static volatile uint8_t fatal_code;
Thread *main_thread;
#define GNUK_INIT 0
#define GNUK_RUNNING 1
#define GNUK_INPUT_WAIT 2
#define GNUK_FATAL 255
/*
* 0 for initializing
* 1 for normal mode
* 2 for input waiting
* 255 for fatal
*/
static uint8_t main_mode;
static void display_interaction (void)
{
eventmask_t m;
while (1)
{
m = chEvtWaitOne (ALL_EVENTS);
set_led (1);
switch (m)
{
case LED_ONESHOT_SHORT:
chThdSleep (MS2ST (100));
break;
case LED_ONESHOT_LONG:
chThdSleep (MS2ST (400));
break;
case LED_TWOSHOT:
chThdSleep (MS2ST (50));
set_led (0);
chThdSleep (MS2ST (50));
set_led (1);
chThdSleep (MS2ST (50));
break;
case LED_STATUS_MODE:
chThdSleep (MS2ST (400));
set_led (0);
return;
case LED_FATAL_MODE:
main_mode = GNUK_FATAL;
set_led (0);
return;
default:
break;
}
set_led (0);
}
}
static void display_fatal_code (void)
{
set_led (1);
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_STOP);
set_led (1);
if (fatal_code & 1)
chThdSleep (LED_TIMEOUT_ONE);
else
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
if (fatal_code & 2)
chThdSleep (LED_TIMEOUT_ONE);
else
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
chThdSleep (LED_TIMEOUT_STOP);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
}
static void display_status_code (void)
{
if (icc_state == ICC_STATE_START)
{
set_led (1);
chThdSleep (LED_TIMEOUT_ONE);
set_led (0);
chThdSleep (LED_TIMEOUT_STOP * 3);
}
else
/* GPGthread running */
{
set_led (1);
if ((auth_status & AC_ADMIN_AUTHORIZED) != 0)
chThdSleep (LED_TIMEOUT_ONE);
else
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
if ((auth_status & AC_OTHER_AUTHORIZED) != 0)
chThdSleep (LED_TIMEOUT_ONE);
else
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
if ((auth_status & AC_PSO_CDS_AUTHORIZED) != 0)
chThdSleep (LED_TIMEOUT_ONE);
else
chThdSleep (LED_TIMEOUT_ZERO);
if (icc_state == ICC_STATE_WAIT)
{
set_led (0);
chThdSleep (LED_TIMEOUT_STOP * 2);
}
else if (icc_state == ICC_STATE_RECEIVE)
{
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
chThdSleep (LED_TIMEOUT_ONE);
set_led (0);
chThdSleep (LED_TIMEOUT_STOP);
}
else
{
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
chThdSleep (LED_TIMEOUT_STOP);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
}
}
}
void
led_blink (int spec)
{
if (spec == 0)
chEvtSignal (main_thread, LED_ONESHOT_SHORT);
else if (spec == 1)
chEvtSignal (main_thread, LED_ONESHOT_LONG);
else
chEvtSignal (main_thread, LED_TWOSHOT);
}
/* /*
* Entry point. * Entry point.
* *
@@ -210,6 +365,8 @@ main (int argc, char **argv)
(void)argc; (void)argc;
(void)argv; (void)argv;
main_thread = chThdSelf ();
flash_unlock (); flash_unlock ();
device_initialize_once (); device_initialize_once ();
usb_lld_init (); usb_lld_init ();
@@ -231,105 +388,47 @@ main (int argc, char **argv)
while (1) while (1)
{ {
eventmask_t m;
count++; count++;
m = chEvtWaitOneTimeout (ALL_EVENTS, LED_TIMEOUT_INTERVAL);
if (fatal_code != 0) switch (m)
{ {
case LED_STATUS_MODE:
main_mode = GNUK_RUNNING;
break;
case LED_FATAL_MODE:
main_mode = GNUK_FATAL;
break;
case LED_INPUT_MODE:
main_mode = GNUK_INPUT_WAIT;
set_led (1); set_led (1);
chThdSleep (LED_TIMEOUT_ZERO); chThdSleep (MS2ST (400));
set_led (0); set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL); break;
set_led (1); default:
chThdSleep (LED_TIMEOUT_ZERO); break;
set_led (0); }
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_STOP);
set_led (1);
if (fatal_code & 1)
chThdSleep (LED_TIMEOUT_ONE);
else
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
if (fatal_code & 2)
chThdSleep (LED_TIMEOUT_ONE);
else
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
chThdSleep (LED_TIMEOUT_STOP);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
}
if (bDeviceState != CONFIGURED) switch (main_mode)
{ {
case GNUK_FATAL:
display_fatal_code ();
break;
case GNUK_INIT:
set_led (1); set_led (1);
chThdSleep (LED_TIMEOUT_ZERO); chThdSleep (LED_TIMEOUT_ZERO);
set_led (0); set_led (0);
chThdSleep (LED_TIMEOUT_STOP * 3); chThdSleep (LED_TIMEOUT_STOP * 3);
} break;
else case GNUK_INPUT_WAIT:
/* Device configured */ display_interaction ();
if (icc_state == ICC_STATE_START) break;
{ case GNUK_RUNNING:
set_led (1); default:
chThdSleep (LED_TIMEOUT_ONE); display_status_code ();
set_led (0); break;
chThdSleep (LED_TIMEOUT_STOP * 3); }
}
else
/* GPGthread running */
{
set_led (1);
if ((auth_status & AC_ADMIN_AUTHORIZED) != 0)
chThdSleep (LED_TIMEOUT_ONE);
else
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
if ((auth_status & AC_OTHER_AUTHORIZED) != 0)
chThdSleep (LED_TIMEOUT_ONE);
else
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
if ((auth_status & AC_PSO_CDS_AUTHORIZED) != 0)
chThdSleep (LED_TIMEOUT_ONE);
else
chThdSleep (LED_TIMEOUT_ZERO);
if (icc_state == ICC_STATE_WAIT)
{
set_led (0);
chThdSleep (LED_TIMEOUT_STOP * 2);
}
else if (icc_state == ICC_STATE_RECEIVE)
{
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
chThdSleep (LED_TIMEOUT_ONE);
set_led (0);
chThdSleep (LED_TIMEOUT_STOP);
}
else
{
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
chThdSleep (LED_TIMEOUT_STOP);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
}
}
#ifdef DEBUG_MORE #ifdef DEBUG_MORE
if (bDeviceState == CONFIGURED && (count % 10) == 0) if (bDeviceState == CONFIGURED && (count % 10) == 0)
@@ -349,6 +448,7 @@ void
fatal (uint8_t code) fatal (uint8_t code)
{ {
fatal_code = code; fatal_code = code;
chEvtSignal (main_thread, LED_FATAL_MODE);
_write ("fatal\r\n", 7); _write ("fatal\r\n", 7);
for (;;); for (;;);
} }

View File

@@ -97,24 +97,19 @@ gpg_fini (void)
#if defined(PINPAD_SUPPORT) #if defined(PINPAD_SUPPORT)
/* /*
* Invoke the thread PIN_MAIN, and let user input PIN string. * Let user input PIN string.
* Return length of the string. * Return length of the string.
* The string itself is in PIN_INPUT_BUFFER. * The string itself is in PIN_INPUT_BUFFER.
*/ */
static int static int
get_pinpad_input (int msg_code) get_pinpad_input (int msg_code)
{ {
Thread *t; int r;
t = chThdCreateFromHeap (NULL, THD_WA_SIZE (128), chEvtSignal (main_thread, LED_INPUT_MODE);
NORMALPRIO, pin_main, (void *)msg_code); r = pinpad_getline (msg_code, MS2ST (8000));
if (t == NULL) chEvtSignal (main_thread, LED_STATUS_MODE);
return -1; return r;
else
{
chThdWait (t);
return pin_input_len;
}
} }
#endif #endif

View File

@@ -27,13 +27,41 @@
#include "board.h" #include "board.h"
#include "gnuk.h" #include "gnuk.h"
#if 0 #ifdef DEBUG
#define DEBUG_CIR 1 #define DEBUG_CIR 1
#endif #endif
uint8_t pin_input_buffer[MAX_PIN_CHARS]; uint8_t pin_input_buffer[MAX_PIN_CHARS];
uint8_t pin_input_len; uint8_t pin_input_len;
/*
* Supported/tested TV controllers:
*
* Controller of Toshiba REGZA
* Controller of Sony BRAVIA
* Controller of Sharp AQUOS
* Dell Wireless Travel Remote MR425
*
* The code supports RC-5 protocol in fact, but I don't have any
* controller at hand which I can test with, so I don't have any data
* for controller of RC-5.
*
* Current code assumes following mapping:
*
* --------------------------------------
* Protocol Controller
* --------------------------------------
* RC-6 Dell MR425
* NEC Toshiba REGZA
* Sharp Sharp AQUOS
* Sony Sony BRAVIA
* --------------------------------------
*
* In future, when I will have other controllers, this mapping will be
* (should be) configurable, at compile time at least, preferably at
* runtime.
*/
/* /*
* Philips RC-5 Protocol: 14-bit (MSB first) * Philips RC-5 Protocol: 14-bit (MSB first)
* *
@@ -69,18 +97,26 @@ uint8_t pin_input_len;
*/ */
/* /*
* PB0 / TIM3_CH3 * The implementation note of CIR signal decoding (on STM32).
*
* (1) Use EXTI interrupt to detect the first edge of signal.
* (2) Use Timer (with PWM input mode) to measure timings of square wave.
*
*/
/*
* Timer settings.
*
* See THE reference manual (RM0008) section 15.3.6 PWM input mode.
* *
* 72MHz * 72MHz
*
* Prescaler = 72 * Prescaler = 72
* *
* 1us * 1us
* *
* * TIMx_CR1
* TIM3_CR1 * CKD = 00 (tDTS = tCK_INT)
* CKD = 10 (sampling x4) * ARPE = 1 (buffered)
* ARPE = 0 (not buffered)
* CMS = 00 (up counter) * CMS = 00 (up counter)
* DIR = 0 (up counter) * DIR = 0 (up counter)
* OPM = 0 (up counter) * OPM = 0 (up counter)
@@ -88,13 +124,13 @@ uint8_t pin_input_len;
* UDIS = 0 (UEV (update event) enabled) * UDIS = 0 (UEV (update event) enabled)
* CEN = 1 (counter enable) * CEN = 1 (counter enable)
* *
* TIM3_CR2 * TIMx_CR2
* TI1S = 1 (TI1 is XOR of ch1, ch2, ch3) * TI1S = 1 (TI1 is XOR of ch1, ch2, ch3)
* MMS = 000 (TRGO at Reset) * MMS = 000 (TRGO at Reset)
* CCDS = 0 (DMA on capture) * CCDS = 0 (DMA on capture)
* RSVD = 000 * RSVD = 000
* *
* TIM3_SMCR * TIMx_SMCR
* ETP = 0 * ETP = 0
* ECE = 0 * ECE = 0
* ETPS = 00 * ETPS = 00
@@ -104,60 +140,37 @@ uint8_t pin_input_len;
* RSVD = 0 * RSVD = 0
* SMS = 100 (Reset-mode) * SMS = 100 (Reset-mode)
* *
* TIM3_DIER * TIMx_DIER
* *
* TIM3_SR * TIMx_SR
* *
* TIM3_EGR * TIMx_EGR
* *
* TIM3_CCMR1 * TIMx_CCMR1
* CC1S = 01 (TI1 selected) * CC1S = 01 (TI1 selected)
* CC2S = 10 (TI1 selected) * CC2S = 10 (TI1 selected)
* IC1F = 1001 (fSAMPLING=fDTS/8, N=8)
* IC2F = 1001 (fSAMPLING=fDTS/8, N=8)
* *
* TIM3_CCMR2 * TIMx_CCMR2
* *
* TIM3_CCER * TIMx_CCER
* CC2P = 1 (polarity = falling edge: TI1FP1) * CC2P = 1 (polarity = falling edge: TI1FP1)
* CC2E = 1 * CC2E = 1
* CC1P = 0 (polarity = rising edge: TI1FP1) * CC1P = 0 (polarity = rising edge: TI1FP1)
* CC1E = 1 * CC1E = 1
* *
* TIM3_CNT * TIMx_CNT
* TIM3_PSC = 71 * TIMx_PSC = 71
* TIM3_ARR = 18000 * TIMx_ARR = 18000
* *
* TIM3_CCR1 period * TIMx_CCR1 period
* TIM3_CCR2 duty * TIMx_CCR2 duty
* *
* TIM3_DCR * TIMx_DCR
* TIM3_DMAR * TIMx_DMAR
*/ */
#define PINDISP_TIMEOUT_INTERVAL0 MS2ST(25)
#define PINDISP_TIMEOUT_INTERVAL1 MS2ST(300)
static void
pindisp (uint8_t c)
{
#if defined(HAVE_7SEGLED)
switch (c)
{
case 'G':
palWritePort (IOPORT2, 0xa1ff);
break;
case 'P':
palWritePort (IOPORT2, 0x98ff);
break;
case '.':
palWritePort (IOPORT2, 0x7fff);
break;
default:
palWritePort (IOPORT2, 0xffff);
}
#else
(void)c;
#endif
}
#if defined(DEBUG_CIR) #if defined(DEBUG_CIR)
static uint16_t intr_ext; static uint16_t intr_ext;
@@ -179,14 +192,6 @@ static uint8_t cir_proto;
#define CIR_PROTO_NEC 5 #define CIR_PROTO_NEC 5
#define CIR_PROTO_SHARP 6 #define CIR_PROTO_SHARP 6
#define CIR_KEY_RC6_ENTER 0x0d /* Mute */
#define CIR_KEY_RC6_BACKSPACE 0xa4 /* <= */
#define CIR_KEY_NEC_ENTER 0x3d /* 'kettei' */
#define CIR_KEY_NEC_BACKSPACE 0x3b /* 'modoru' */
#define CIR_KEY_SONY_ENTER 0x65 /* 'kettei' */
#define CIR_KEY_SONY_BACKSPACE 0xa3 /* 'modoru' */
#define CIR_KEY_SHARP_ENTER 0x0252 /* 'kettei' */
#define CIR_KEY_SHARP_BACKSPACE 0xe4 /* 'modoru' */
/* CIR_DATA_ZERO: Used for zero-bit handling of RC-5/RC-6 */ /* CIR_DATA_ZERO: Used for zero-bit handling of RC-5/RC-6 */
static uint8_t cir_data_zero; static uint8_t cir_data_zero;
@@ -196,6 +201,388 @@ static uint8_t cir_seq;
static systime_t cir_input_last; static systime_t cir_input_last;
#define CIR_PERIOD_INHIBIT_CHATTER 200 /* mili second */ #define CIR_PERIOD_INHIBIT_CHATTER 200 /* mili second */
static void
cir_init (void)
{
cir_data = 0;
cir_seq = 0;
/* Don't touch cir_proto here */
cir_ext_enable ();
}
#define CH_RETURN 0x0d
#define CH_BACKSPACE 0x08
struct codetable {
uint16_t cir_code;
uint8_t char_code;
};
/* NOTE: no way to input '0' */
static const struct codetable
cir_codetable_dell_mr425[] = {
{0x10, '7' }, /* Speaker Louder */
{0x11, '8' }, /* Speaker Quieter */
{0x0d, '9' }, /* Speaker Mute */
{0xce, 'a' }, /* Black triangle UP */
{0xcf, 'b' }, /* Black triangle DOWN */
{0x58, 'c' }, /* White triangle UP */
{0x5a, 'd' }, /* White triangle LEFT */
{0x5c, CH_RETURN }, /* Check */
{0x5b, 'e' }, /* White triangle RIGHT */
{0xa4, CH_BACKSPACE }, /* Back */
{0x59, 'f' }, /* White triangle DOWN */
{0x2f, '1' }, /* Rewind */
{0x2c, '2' }, /* Play / Pause */
{0x2e, '3' }, /* Forward */
{0x21, '4' }, /* Skip backward */
{0x31, '5' }, /* Stop */
{0x20, '6' }, /* Skip forward */
{0, 0} /* <<END>> */
};
#define CIR_ADDR_SHARP_AQUOS 0x028f
static const struct codetable
cir_codetable_aquos[] = {
{ 0x0116, ' ' }, /* Power */
{ 0x025e, '0' }, /* d */
{ 0x024e, '1' }, /* 1 */
{ 0x024f, '2' }, /* 2 */
{ 0x0250, '3' }, /* 3 */
{ 0x0251, '4' }, /* 4 */
{ 0x0252, '5' }, /* 5 */
{ 0x0253, '6' }, /* 6 */
{ 0x0254, '7' }, /* 7 */
{ 0x0255, '8' }, /* 8 */
{ 0x0256, '9' }, /* 9 */
{ 0x0257, 'a' }, /* 10/0 */
{ 0x0258, 'b' }, /* 11 */
{ 0x0259, 'c' }, /* 12 */
{ 0x0111, 'd' }, /* Ch ^ */
{ 0x0112, 'e' }, /* Ch v */
{ 0x0114, 'f' }, /* Vol + */
{ 0x0115, 'g' }, /* Vol - */
{ 0x0117, 'h' }, /* Mute */
{ 0x0280, 'i' }, /* BLUE */
{ 0x0281, 'j' }, /* RED */
{ 0x0282, 'k' }, /* GREEN */
{ 0x0283, 'l' }, /* YELLOW */
{ 0x011b, 'm' }, /* DISPLAY CONTROL (gamen hyouji) */
{ 0x01d5, 'n' }, /* DISPLAY SIZE */
{ 0x0157, 'o' }, /* UP */
{ 0x01d7, 'p' }, /* LEFT */
{ 0x01d8, 'q' }, /* RIGHT */
{ 0x0120, 'r' }, /* DOWN */
{ 0x0152, CH_RETURN }, /* Commit (kettei) */
{ 0x01e4, CH_BACKSPACE }, /* Back (modoru) */
{ 0x01f5, 's' }, /* Quit (shuuryou) */
{ 0x0b03, 't' }, /* Rewind (hayamodoshi) */
{ 0x0b01, 'u' }, /* Play (saisei) */
{ 0x0b04, 'v' }, /* Forward (hayaokuri) */
{ 0x0b02, 'w' }, /* Stop (teishi) */
{ 0x028a, 'x' }, /* BS */
{ 0x028b, 'y' }, /* CS */
{ 0x025f, 'z' }, /* Program information (bangumi jouhou) */
{ 0x0260, '\\' }, /* Program table (bangumi hyou) */
{ 0x0118, '|' }, /* Sound channel (onsei kirikae) */
{ 0x028e, '[' }, /* Ground Analog (chijou A) */
{ 0x0289, ']' }, /* Ground Digital (chijou D) */
{ 0x0b07, '\"' }, /* Feature select (kinou sentaku) */
{ 0x026b, '.' }, /* TV/Radio/Data (terebi/rajio/data) */
{ 0x025a, ',' }, /* 3 code input (3 keta nyuuryoku) */
{ 0x0267, ':' }, /* subtitle (jimaku) */
{ 0x0159, ';' }, /* hold (seishi) */
{ 0x01c4, 'A' }, /* Menu */
{ 0x011a, 'B' }, /* Off timer */
{ 0x0121, 'C' }, /* CATV */
{ 0x0b05, 'D' }, /* Record */
{ 0x0b06, 'E' }, /* Recording stop */
{ 0x0113, 'F' }, /* Inputs (nyuuryoku kirikae) */
{ 0x0275, 'G' }, /* other programs (ura bangumi) */
{ 0x0266, 'H' }, /* signal control (eizou kirikae) */
{ 0x01e7, 'I' }, /* AV position */
{ 0x027f, 'J' }, /* i.LINK */
{ 0x0b00, 'K' }, /* Recorder power */
{ 0x028f, 'L' }, /* as you like it (okonomi senkyoku) */
{0, 0} /* <<END>> */
};
#define CIR_ADDR_TOSHIBA_REGZA 0xbf40
static const struct codetable
cir_codetable_regza[] = {
{ 0x12, ' ' }, /* Power */
{ 0x14, '0' }, /* d (data) */
{ 0x01, '1' }, /* 1 */
{ 0x02, '2' }, /* 2 */
{ 0x03, '3' }, /* 3 */
{ 0x04, '4' }, /* 4 */
{ 0x05, '5' }, /* 5 */
{ 0x06, '6' }, /* 6 */
{ 0x07, '7' }, /* 7 */
{ 0x08, '8' }, /* 8 */
{ 0x09, '9' }, /* 9 */
{ 0x0a, 'a' }, /* 10 */
{ 0x0b, 'b' }, /* 11 */
{ 0x0c, 'c' }, /* 12 */
{ 0x1b, 'd' }, /* Ch ^ */
{ 0x1f, 'e' }, /* Ch v */
{ 0x1a, 'f' }, /* Vol + */
{ 0x1e, 'g' }, /* Vol - */
{ 0x10, 'h' }, /* Mute */
{ 0x73, 'i' }, /* BLUE */
{ 0x74, 'j' }, /* RED */
{ 0x75, 'k' }, /* GREEN */
{ 0x76, 'l' }, /* YELLOW */
{ 0x1c, 'm' }, /* Display control */
{ 0x2b, 'n' }, /* Display size */
{ 0x3e, 'o' }, /* UP */
{ 0x5f, 'p' }, /* LEFT */
{ 0x5b, 'q' }, /* RIGHT */
{ 0x3f, 'r' }, /* DOWN */
{ 0x3d, CH_RETURN }, /* Commit (kettei) */
{ 0x3b, CH_BACKSPACE }, /* Back (modoru) */
{ 0x3c, 's' }, /* Quit (shuuryou) */
{ 0x2c, 't' }, /* << (Rewind) */
{ 0x2d, 'u' }, /* >/|| (Play/Stop) */
{ 0x2e, 'v' }, /* >> (Forward) */
{ 0x2b, 'w' }, /* Stop (teishi) */
{ 0x7c, 'x' }, /* BS */
{ 0x7d, 'y' }, /* CS */
{ 0x71, 'z' }, /* Program information (bangumi setsumei) */
{ 0x77, '\\' }, /* Mini program table (mini bangumihyou) */
{ 0x13, '|' }, /* Sound (onta kirikae) */
{ 0x7a, '[' }, /* Ground Digital (chideji) */
{ 0x7b, ']' }, /* Ground Analog (chiana) */
{ 0xd0, '\"' }, /* Settings Menu (settei menu) */
{ 0x6d, '.' }, /* Radio/Data (rajio/data) */
{ 0x60, ',' }, /* CH 10-key input (search) */
{ 0x52, ':' }, /* subtitle (jimaku) */
{ 0x50, ';' }, /* hold (seishi) */
{ 0x3a, 'A' }, /* Input- (nyuuryokukirikae-) */
{ 0x0f, 'B' }, /* Input+ (nyuuryokukirikae+) */
{ 0x29, 'C' }, /* Two screens (nigamen) */
{ 0x25, 'D' }, /* Broadband */
{ 0x27, 'E' }, /* |<< Skip backward */
{ 0x26, 'F' }, /* >>| Skip forward */
{ 0x61, '!' }, /* 1 NHK1 */
{ 0x62, '@' }, /* 2 NHK2 */
{ 0x63, '#' }, /* 3 NHKh */
{ 0x64, '$' }, /* 4 BS Nihon TV */
{ 0x65, '%' }, /* 5 BS Asashi */
{ 0x66, '^' }, /* 6 BS-i */
{ 0x67, '&' }, /* 7 BSJ */
{ 0x68, '*' }, /* 8 BS Fuji */
{ 0x69, '(' }, /* 9 WOW */
{ 0x6a, ')' }, /* 10 Star */
{ 0x6b, '-' }, /* 11 BS11 */
{ 0x6c, '+' }, /* 12 TwellV */
{ 0x27, '=' }, /* Quick (Delete) */
{ 0x34, '<' }, /* REGZA link */
{ 0x6e, '>' }, /* Program Table */
{ 0x20, '/' }, /* ^^ */
{ 0x22, '\'' }, /* << */
{ 0x23, '?' }, /* >> */
{ 0x21, '_' }, /* vv */
{0, 0} /* <<END>> */
};
static const struct codetable
cir_codetable_bravia[] = {
{ 0x15, ' ' }, /* Power */
{ 0x95, '0' }, /* d (16-bit: 0x4b) */
{ 0x00, '1' }, /* 1 */
{ 0x01, '2' }, /* 2 */
{ 0x02, '3' }, /* 3 */
{ 0x03, '4' }, /* 4 */
{ 0x04, '5' }, /* 5 */
{ 0x05, '6' }, /* 6 */
{ 0x06, '7' }, /* 7 */
{ 0x07, '8' }, /* 8 */
{ 0x08, '9' }, /* 9 */
{ 0x09, 'a' }, /* 10 */
{ 0x0a, 'b' }, /* 11 */
{ 0x0b, 'c' }, /* 12 */
{ 0x10, 'd' }, /* CH+ */
{ 0x11, 'd' }, /* CH- */
{ 0x12, 'f' }, /* Vol+ */
{ 0x13, 'g' }, /* Vol- */
{ 0x14, 'h' }, /* Mute */
{ 0xa4, 'i' }, /* BLUE (16-bit: 0x4b) */
{ 0xa5, 'j' }, /* RED (16-bit: 0x4b) */
{ 0xa6, 'k' }, /* GREEN (16-bit: 0x4b) */
{ 0xa7, 'l' }, /* YELLOW (16-bit: 0x4b) */
{ 0x3a, 'm' }, /* DISPLAY control (gamen hyouji) */
{ 0x3d, 'n' }, /* Display Wide (waido kirikae) */
{ 0x74, 'o' }, /* UP */
{ 0x75, 'p' }, /* DOWN */
{ 0x33, 'q' }, /* RIGHT */
{ 0x34, 'r' }, /* LEFT */
{ 0x65, CH_RETURN }, /* Commit (kettei) */
{ 0xa3, CH_BACKSPACE }, /* Back (modoru) (16-bit: 0x4b) */
{ 0xac, 's' }, /* BS (16-bit: 0x4b) */
{ 0xab, 't' }, /* CS (16-bit: 0x4b) */
{ 0x5b, 'u' }, /* Program table (bangumi hyou) (16-bit: 0x52) */
{ 0x17, 'v' }, /* Sound channel (onsei kirikae) */
{ 0xa8, 'w' }, /* subtitle (jimaku) (16-bit: 0x4b) */
{ 0x5c, 'x' }, /* hold (memo) */
{ 0xb6, 'y' }, /* Tool (16-bit: 0x4b) */
{ 0x8c, 'z' }, /* 10 key input (10ki-) (16-bit: 0x4b) */
{ 0x60, '!' }, /* Menu */
{ 0xae, '@' }, /* Analog (16-bit: 0x4b) */
{ 0xb2, '#' }, /* Digital (16-bit: 0x4b) */
{ 0x25, '$' }, /* Input (nyuuryoku kirikae) */
{0, 0} /* <<END>> */,
};
static int
ch_is_backspace (int ch)
{
return ch == CH_BACKSPACE;
}
static int
ch_is_enter (int ch)
{
return ch == CH_RETURN;
}
/* liner search is good enough for this small amount of data */
static uint8_t
find_char_codetable (uint32_t cir_code, const struct codetable *ctp)
{
while (ctp->cir_code != 0x0000 || ctp->char_code != 0x00)
if (ctp->cir_code == cir_code)
return ctp->char_code;
else
ctp++;
/* Not found */
return cir_code & 0xff;
}
static int
hex (int x)
{
if (x < 10)
return x + '0';
else
return (x - 10) + 'a';
}
static int
cir_getchar (systime_t timeout)
{
uint16_t cir_addr;
eventmask_t m;
#if defined(DEBUG_CIR)
uint16_t *p;
#endif
#if defined(DEBUG_CIR)
cirinput_p = cirinput;
#endif
chEvtClear (ALL_EVENTS);
cir_init ();
m = chEvtWaitOneTimeout (ALL_EVENTS, timeout);
if (m == 0)
return -1;
#if defined(DEBUG_CIR)
DEBUG_INFO ("****\r\n");
DEBUG_SHORT (intr_ext);
DEBUG_SHORT (intr_trg);
DEBUG_SHORT (intr_ovf);
DEBUG_INFO ("----\r\n");
for (p = cirinput; p < cirinput_p; p++)
DEBUG_SHORT (*p);
DEBUG_INFO ("====\r\n");
cirinput_p = cirinput;
DEBUG_INFO ("**** CIR data:");
DEBUG_WORD (cir_data);
if (cir_seq > 48)
DEBUG_SHORT (cir_data_more);
DEBUG_BYTE (cir_seq);
#endif
switch (cir_proto)
{
case CIR_PROTO_RC5:
cir_data &= 0x003f;
goto err;
case CIR_PROTO_RC6:
cir_addr = cir_data >> 8; /* in case of cir_seq == 16. 32??? */
cir_data &= 0x00ff;
return find_char_codetable (cir_data, cir_codetable_dell_mr425);
case CIR_PROTO_NEC:
cir_addr = cir_data&0xffff;
if (cir_addr == CIR_ADDR_TOSHIBA_REGZA)
{
cir_data = (cir_data >> 16) & 0x00ff;
return find_char_codetable (cir_data, cir_codetable_regza);
}
else
goto err;
case CIR_PROTO_SHARP:
cir_addr = cir_data&0x0fff;
if (cir_addr == CIR_ADDR_SHARP_AQUOS)
{
cir_data = (cir_data>>16)&0x0fff;
return find_char_codetable (cir_data, cir_codetable_aquos);
}
else
goto err;
case CIR_PROTO_SONY:
/* Remove ADDRESS bits and filter COMMAND bits */
if (cir_seq == 1 + 12)
{
cir_addr = cir_data >> 7;
cir_data = cir_data & 0x007f;
/* ADDRESS = 0x01 (5-bit) */
}
else
{
cir_addr = cir_data >> 8;
cir_data = cir_data & 0x00ff;
/* ADDRESS = 0x4b or 0x52 (7-bit) */
}
return find_char_codetable (cir_data, cir_codetable_bravia);
err:
default:
/* encode debug information */
pin_input_len = 16;
pin_input_buffer[0] = hex (cir_proto >> 4);
pin_input_buffer[1] = hex (cir_proto & 0x0f);
pin_input_buffer[2] = ':';
pin_input_buffer[3] = hex ((cir_data >> 28) & 0x0f);
pin_input_buffer[4] = hex ((cir_data >> 24) & 0x0f);
pin_input_buffer[5] = hex ((cir_data >> 20) & 0x0f);
pin_input_buffer[6] = hex ((cir_data >> 16) & 0x0f);
pin_input_buffer[7] = hex ((cir_data >> 12) & 0x0f);
pin_input_buffer[8] = hex ((cir_data >> 8) & 0x0f);
pin_input_buffer[9] = hex ((cir_data >> 4) & 0x0f);
pin_input_buffer[10] = hex (cir_data & 0x0f);
pin_input_buffer[11] = ':';
pin_input_buffer[12] = hex ((cir_data_more >> 12) & 0x0f);
pin_input_buffer[13] = hex ((cir_data_more >> 8) & 0x0f);
pin_input_buffer[14] = hex ((cir_data_more >> 4) & 0x0f);
pin_input_buffer[15] = hex (cir_data_more & 0x0f);
return CH_RETURN;
}
}
/* /*
* RC-5 protocol doesn't have a start bit, while any other protocols * RC-5 protocol doesn't have a start bit, while any other protocols
* have the one. * have the one.
@@ -207,125 +594,56 @@ static systime_t cir_input_last;
#define CIR_BIT_PERIOD 1500 #define CIR_BIT_PERIOD 1500
#define CIR_BIT_SIRC_PERIOD_ON 1000 #define CIR_BIT_SIRC_PERIOD_ON 1000
static void
cir_init (void)
{
cir_data = 0;
cir_seq = 0;
/* Don't touch cir_proto here */
cir_ext_enable ();
}
static Thread *pin_thread; static Thread *pin_thread;
static int /*
cir_key_is_backspace (void) * Let user input PIN string.
* Return length of the string.
* The string itself is in PIN_INPUT_BUFFER.
*/
int
pinpad_getline (int msg_code, systime_t timeout)
{ {
return (cir_proto == CIR_PROTO_RC6 && cir_data == CIR_KEY_RC6_BACKSPACE)
|| (cir_proto == CIR_PROTO_NEC && cir_data == CIR_KEY_NEC_BACKSPACE)
|| (cir_proto == CIR_PROTO_SONY && cir_data == CIR_KEY_SONY_BACKSPACE)
|| (cir_proto == CIR_PROTO_SHARP && cir_data == CIR_KEY_SHARP_BACKSPACE);
}
static int
cir_key_is_enter (void)
{
return (cir_proto == CIR_PROTO_RC6 && cir_data == CIR_KEY_RC6_ENTER)
|| (cir_proto == CIR_PROTO_NEC && cir_data == CIR_KEY_NEC_ENTER)
|| (cir_proto == CIR_PROTO_SONY && cir_data == CIR_KEY_SONY_ENTER)
|| (cir_proto == CIR_PROTO_SHARP && cir_data == CIR_KEY_SHARP_ENTER);
}
msg_t
pin_main (void *arg)
{
uint8_t s = 0;
int msg_code = (int)arg;
(void)msg_code; (void)msg_code;
pin_thread = chThdSelf (); pin_thread = chThdSelf ();
#if defined(DEBUG_CIR) DEBUG_INFO (">>>\r\n");
cirinput_p = cirinput;
#endif
pin_input_len = 0; pin_input_len = 0;
chEvtClear (ALL_EVENTS); while (1)
cir_init ();
while (!chThdShouldTerminate ())
{ {
eventmask_t m; int ch;
m = chEvtWaitOneTimeout (ALL_EVENTS, PINDISP_TIMEOUT_INTERVAL1); ch = cir_getchar (timeout);
if (ch < 0)
return 0; /* timeout */
if (m) if (ch_is_backspace (ch))
{ {
#if defined(DEBUG_CIR) led_blink (2);
uint16_t *p; if (pin_input_len > 0)
pin_input_len--;
DEBUG_INFO ("****\r\n");
DEBUG_SHORT (intr_ext);
DEBUG_SHORT (intr_trg);
DEBUG_SHORT (intr_ovf);
DEBUG_INFO ("----\r\n");
for (p = cirinput; p < cirinput_p; p++)
DEBUG_SHORT (*p);
DEBUG_INFO ("====\r\n");
cirinput_p = cirinput;
#endif
DEBUG_INFO ("**** CIR data:");
DEBUG_WORD (cir_data);
if (cir_seq > 48)
{
DEBUG_SHORT (cir_data_more);
}
DEBUG_BYTE (cir_seq);
if (cir_key_is_backspace ())
{
if (pin_input_len > 0)
pin_input_len--;
}
else if (cir_key_is_enter ())
{
pindisp (' ');
chThdExit (0);
}
else if (pin_input_len < MAX_PIN_CHARS)
pin_input_buffer[pin_input_len++] = (uint8_t)cir_data;
cir_init ();
} }
else if (ch_is_enter (ch))
switch (s++) break;
else if (pin_input_len < MAX_PIN_CHARS)
{ {
case 0: led_blink (0);
pindisp ('G'); pin_input_buffer[pin_input_len++] = ch;
break;
case 1:
pindisp ('P');
break;
case 2:
pindisp ('G');
break;
case 3:
pindisp ('.');
break;
default:
pindisp (' ');
s = 0;
break;
} }
chThdSleep (PINDISP_TIMEOUT_INTERVAL0);
} }
cir_ext_disable (); cir_ext_disable ();
return 0;
return pin_input_len;
} }
/**
* @brief Interrupt handler of EXTI.
* @note This handler will be invoked at the beginning of signal.
* Setup timer to measure period and duty using PWM input mode.
*/
void void
cir_ext_interrupt (void) cir_ext_interrupt (void)
{ {
@@ -340,29 +658,33 @@ cir_ext_interrupt (void)
} }
#endif #endif
TIM3->EGR = TIM_EGR_UG; /* Generate UEV to load PSC and ARR */ TIMx->EGR = TIM_EGR_UG; /* Generate UEV to load PSC and ARR */
/* Enable Timer */ /* Enable Timer */
TIM3->SR &= ~(TIM_SR_UIF TIMx->SR &= ~(TIM_SR_UIF
| TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC1IF | TIM_SR_CC2IF
| TIM_SR_TIF | TIM_SR_TIF
| TIM_SR_CC1OF | TIM_SR_CC2OF); | TIM_SR_CC1OF | TIM_SR_CC2OF);
TIM3->DIER = TIM_DIER_UIE /*overflow*/ | TIM_DIER_TIE /*trigger*/; TIMx->DIER = TIM_DIER_UIE /*overflow*/ | TIM_DIER_TIE /*trigger*/;
TIM3->CR1 |= TIM_CR1_CEN; TIMx->CR1 |= TIM_CR1_CEN;
} }
#define CIR_PERIOD_ON_RC5_OR_RC6 (((cir_proto == CIR_PROTO_RC5) ? 2 : 1) \ #define CIR_PERIOD_ON_RC5_OR_RC6 (((cir_proto == CIR_PROTO_RC5) ? 2 : 1) \
* CIR_BIT_PERIOD_RC6 * 3 / 2) * CIR_BIT_PERIOD_RC6 * 3 / 2)
/**
* @brief Interrupt handler of timer.
* @note Timer is PWM input mode, this handler will be invoked on each cycle
*/
void void
cir_timer_interrupt (void) cir_timer_interrupt (void)
{ {
uint16_t period, on, off; uint16_t period, on, off;
period = TIM3->CCR1; period = TIMx->CCR1;
on = TIM3->CCR2; on = TIMx->CCR2;
off = period - on; off = period - on;
if ((TIM3->SR & TIM_SR_TIF)) if ((TIMx->SR & TIM_SR_TIF))
{ {
if (cir_seq == 0) if (cir_seq == 0)
{ {
@@ -477,23 +799,23 @@ cir_timer_interrupt (void)
intr_trg++; intr_trg++;
#endif #endif
TIM3->EGR = TIM_EGR_UG; /* Generate UEV */ TIMx->EGR = TIM_EGR_UG; /* Generate UEV */
TIM3->SR &= ~TIM_SR_TIF; TIMx->SR &= ~TIM_SR_TIF;
} }
else else
/* overflow occurred */ /* overflow occurred */
{ {
systime_t now = chTimeNow (); systime_t now = chTimeNow ();
TIM3->SR &= ~TIM_SR_UIF; TIMx->SR &= ~TIM_SR_UIF;
if (on > 0) if (on > 0)
{ {
uint8_t ignore_input = 0; uint8_t ignore_input = 0;
/* Disable the timer */ /* Disable the timer */
TIM3->CR1 &= ~TIM_CR1_CEN; TIMx->CR1 &= ~TIM_CR1_CEN;
TIM3->DIER = 0; TIMx->DIER = 0;
if (cir_seq == 12 || cir_seq == 15) if (cir_seq == 12 || cir_seq == 15)
{ {
@@ -536,14 +858,9 @@ cir_timer_interrupt (void)
cir_input_last = now; cir_input_last = now;
ignore_input = 1; ignore_input = 1;
} }
/* Remove ADDRESS bits and filter COMMAND bits */
else if (cir_proto == CIR_PROTO_SONY) else if (cir_proto == CIR_PROTO_SONY)
{ {
if (cir_seq == 1 + 12) if (cir_seq != 1 + 12 && cir_seq != 1 + 15)
cir_data = cir_data & 0x007f;
else if (cir_seq == 1 + 15)
cir_data = cir_data & 0x00ff;
else
ignore_input = 1; ignore_input = 1;
} }
else if (cir_proto == CIR_PROTO_OTHER) else if (cir_proto == CIR_PROTO_OTHER)
@@ -551,10 +868,7 @@ cir_timer_interrupt (void)
if (cir_seq == 1 + 32) if (cir_seq == 1 + 32)
{ {
if (((cir_data >> 16) & 0xff) == ((cir_data >> 24) ^ 0xff)) if (((cir_data >> 16) & 0xff) == ((cir_data >> 24) ^ 0xff))
{ cir_proto = CIR_PROTO_NEC;
cir_proto = CIR_PROTO_NEC;
cir_data = (cir_data >> 16) & 0x00ff;
}
else else
ignore_input = 1; ignore_input = 1;
} }
@@ -569,10 +883,7 @@ cir_timer_interrupt (void)
^ ((cir_data >> 20) & 0x0f) ^ ((cir_data >> 16) & 0x0f) ^ ((cir_data >> 20) & 0x0f) ^ ((cir_data >> 16) & 0x0f)
^ ((cir_data >> 12) & 0x0f) ^ ((cir_data >> 8) & 0x0f) ^ ((cir_data >> 12) & 0x0f) ^ ((cir_data >> 8) & 0x0f)
^ ((cir_data >> 4) & 0x0f) ^ (cir_data & 0x0f))) ^ ((cir_data >> 4) & 0x0f) ^ (cir_data & 0x0f)))
{ cir_proto = CIR_PROTO_SHARP;
cir_proto = CIR_PROTO_SHARP;
cir_data = (cir_data >> 16) & 0x0fff;
}
else else
ignore_input = 1; ignore_input = 1;
} }
@@ -581,16 +892,12 @@ cir_timer_interrupt (void)
} }
else if (cir_proto == CIR_PROTO_RC6) else if (cir_proto == CIR_PROTO_RC6)
{ {
if (cir_seq == 16 || cir_seq == 32) if (cir_seq != 16 && cir_seq != 32)
cir_data &= 0x00ff;
else
ignore_input = 1; ignore_input = 1;
} }
else if (cir_proto == CIR_PROTO_RC5) else if (cir_proto == CIR_PROTO_RC5)
{ {
if (cir_seq == 14) if (cir_seq != 14)
cir_data &= 0x003f;
else
ignore_input = 1; ignore_input = 1;
} }
else else
@@ -603,7 +910,8 @@ cir_timer_interrupt (void)
{ {
cir_input_last = now; cir_input_last = now;
/* Notify thread */ /* Notify thread */
chEvtSignal (pin_thread, (eventmask_t)1); if (pin_thread)
chEvtSignalI (pin_thread, (eventmask_t)1);
} }
#if defined(DEBUG_CIR) #if defined(DEBUG_CIR)

View File

@@ -120,8 +120,14 @@ gnuk_device_SetConfiguration (void)
DEVICE_INFO *pInfo = &Device_Info; DEVICE_INFO *pInfo = &Device_Info;
if (pInfo->Current_Configuration != 0) if (pInfo->Current_Configuration != 0)
/* Device configured */ { /* Device configured */
bDeviceState = CONFIGURED; extern void *main_thread;
extern void chEvtSignalI (void *, unsigned long);
#define LED_STATUS_MODE (8)
bDeviceState = CONFIGURED;
chEvtSignalI (main_thread, LED_STATUS_MODE);
}
} }
static void static void