diff --git a/ChangeLog b/ChangeLog index 93136de..71de366 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,30 @@ 2011-11-01 Niibe Yutaka + * 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). * src/ac.c (calc_md): Fix comparison. diff --git a/boards/STBEE/board.h b/boards/STBEE/board.h index 6e2e74d..a947f06 100644 --- a/boards/STBEE/board.h +++ b/boards/STBEE/board.h @@ -40,6 +40,10 @@ #if defined(PINPAD_SUPPORT) #define HAVE_7SEGLED 1 +/* + * Timer assignment for CIR + */ +#define TIMx TIM3 #endif /* diff --git a/boards/STBEE_MINI/board.h b/boards/STBEE_MINI/board.h index 8238c91..a256510 100644 --- a/boards/STBEE_MINI/board.h +++ b/boards/STBEE_MINI/board.h @@ -41,6 +41,10 @@ #if defined(PINPAD_SUPPORT) #define HAVE_7SEGLED 1 +/* + * Timer assignment for CIR + */ +#define TIMx TIM3 #endif /* diff --git a/boards/STM8S_DISCOVERY/board.h b/boards/STM8S_DISCOVERY/board.h index e0a2a5e..562dd55 100644 --- a/boards/STM8S_DISCOVERY/board.h +++ b/boards/STM8S_DISCOVERY/board.h @@ -56,6 +56,11 @@ */ #define GPIOA_LED 8 +/* + * Timer assignment for CIR + */ +#define TIMx TIM3 + /* * I/O ports initial setup, this configuration is established soon after reset * in the initialization code. diff --git a/src/gnuk.h b/src/gnuk.h index 196e4ed..5e3d4f7 100644 --- a/src/gnuk.h +++ b/src/gnuk.h @@ -348,5 +348,16 @@ extern void dial_sw_enable (void); extern uint8_t pin_input_buffer[MAX_PIN_CHARS]; 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 diff --git a/src/main.c b/src/main.c index 9344ee2..655aa59 100644 --- a/src/main.c +++ b/src/main.c @@ -1,7 +1,7 @@ /* * 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 * * 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; +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. * @@ -210,6 +365,8 @@ main (int argc, char **argv) (void)argc; (void)argv; + main_thread = chThdSelf (); + flash_unlock (); device_initialize_once (); usb_lld_init (); @@ -231,105 +388,47 @@ main (int argc, char **argv) while (1) { + eventmask_t m; + count++; - - if (fatal_code != 0) + m = chEvtWaitOneTimeout (ALL_EVENTS, LED_TIMEOUT_INTERVAL); + 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); - chThdSleep (LED_TIMEOUT_ZERO); + chThdSleep (MS2ST (400)); 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); - } + break; + default: + break; + } - if (bDeviceState != CONFIGURED) + switch (main_mode) { + case GNUK_FATAL: + display_fatal_code (); + break; + case GNUK_INIT: set_led (1); chThdSleep (LED_TIMEOUT_ZERO); set_led (0); chThdSleep (LED_TIMEOUT_STOP * 3); - } - else - /* Device configured */ - 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); - } - } + break; + case GNUK_INPUT_WAIT: + display_interaction (); + break; + case GNUK_RUNNING: + default: + display_status_code (); + break; + } #ifdef DEBUG_MORE if (bDeviceState == CONFIGURED && (count % 10) == 0) @@ -349,6 +448,7 @@ void fatal (uint8_t code) { fatal_code = code; + chEvtSignal (main_thread, LED_FATAL_MODE); _write ("fatal\r\n", 7); for (;;); } diff --git a/src/openpgp.c b/src/openpgp.c index 172bf22..1738363 100644 --- a/src/openpgp.c +++ b/src/openpgp.c @@ -97,24 +97,19 @@ gpg_fini (void) #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. * The string itself is in PIN_INPUT_BUFFER. */ static int get_pinpad_input (int msg_code) { - Thread *t; + int r; - t = chThdCreateFromHeap (NULL, THD_WA_SIZE (128), - NORMALPRIO, pin_main, (void *)msg_code); - if (t == NULL) - return -1; - else - { - chThdWait (t); - return pin_input_len; - } + chEvtSignal (main_thread, LED_INPUT_MODE); + r = pinpad_getline (msg_code, MS2ST (8000)); + chEvtSignal (main_thread, LED_STATUS_MODE); + return r; } #endif diff --git a/src/pin-cir.c b/src/pin-cir.c index f512b94..75e84ef 100644 --- a/src/pin-cir.c +++ b/src/pin-cir.c @@ -27,13 +27,41 @@ #include "board.h" #include "gnuk.h" -#if 0 +#ifdef DEBUG #define DEBUG_CIR 1 #endif uint8_t pin_input_buffer[MAX_PIN_CHARS]; 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) * @@ -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 - * * Prescaler = 72 * * 1us * - * - * TIM3_CR1 - * CKD = 10 (sampling x4) - * ARPE = 0 (not buffered) + * TIMx_CR1 + * CKD = 00 (tDTS = tCK_INT) + * ARPE = 1 (buffered) * CMS = 00 (up counter) * DIR = 0 (up counter) * OPM = 0 (up counter) @@ -88,13 +124,13 @@ uint8_t pin_input_len; * UDIS = 0 (UEV (update event) enabled) * CEN = 1 (counter enable) * - * TIM3_CR2 + * TIMx_CR2 * TI1S = 1 (TI1 is XOR of ch1, ch2, ch3) * MMS = 000 (TRGO at Reset) * CCDS = 0 (DMA on capture) * RSVD = 000 * - * TIM3_SMCR + * TIMx_SMCR * ETP = 0 * ECE = 0 * ETPS = 00 @@ -104,60 +140,37 @@ uint8_t pin_input_len; * RSVD = 0 * SMS = 100 (Reset-mode) * - * TIM3_DIER + * TIMx_DIER * - * TIM3_SR + * TIMx_SR * - * TIM3_EGR + * TIMx_EGR * - * TIM3_CCMR1 + * TIMx_CCMR1 * CC1S = 01 (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) * CC2E = 1 * CC1P = 0 (polarity = rising edge: TI1FP1) * CC1E = 1 * - * TIM3_CNT - * TIM3_PSC = 71 - * TIM3_ARR = 18000 + * TIMx_CNT + * TIMx_PSC = 71 + * TIMx_ARR = 18000 * - * TIM3_CCR1 period - * TIM3_CCR2 duty + * TIMx_CCR1 period + * TIMx_CCR2 duty * - * TIM3_DCR - * TIM3_DMAR + * TIMx_DCR + * 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) static uint16_t intr_ext; @@ -179,14 +192,6 @@ static uint8_t cir_proto; #define CIR_PROTO_NEC 5 #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 */ static uint8_t cir_data_zero; @@ -196,6 +201,388 @@ static uint8_t cir_seq; static systime_t cir_input_last; #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} /* <> */ +}; + +#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} /* <> */ +}; + +#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} /* <> */ +}; + +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} /* <> */, +}; + +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 * have the one. @@ -207,125 +594,56 @@ static systime_t cir_input_last; #define CIR_BIT_PERIOD 1500 #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 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; + pin_thread = chThdSelf (); -#if defined(DEBUG_CIR) - cirinput_p = cirinput; -#endif + DEBUG_INFO (">>>\r\n"); pin_input_len = 0; - chEvtClear (ALL_EVENTS); - cir_init (); - - while (!chThdShouldTerminate ()) + while (1) { - 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) - uint16_t *p; - - 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 (); + led_blink (2); + if (pin_input_len > 0) + pin_input_len--; } - - switch (s++) + else if (ch_is_enter (ch)) + break; + else if (pin_input_len < MAX_PIN_CHARS) { - case 0: - pindisp ('G'); - break; - case 1: - pindisp ('P'); - break; - case 2: - pindisp ('G'); - break; - case 3: - pindisp ('.'); - break; - default: - pindisp (' '); - s = 0; - break; + led_blink (0); + pin_input_buffer[pin_input_len++] = ch; } - - chThdSleep (PINDISP_TIMEOUT_INTERVAL0); } 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 cir_ext_interrupt (void) { @@ -340,29 +658,33 @@ cir_ext_interrupt (void) } #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 */ - TIM3->SR &= ~(TIM_SR_UIF + TIMx->SR &= ~(TIM_SR_UIF | TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_TIF | TIM_SR_CC1OF | TIM_SR_CC2OF); - TIM3->DIER = TIM_DIER_UIE /*overflow*/ | TIM_DIER_TIE /*trigger*/; - TIM3->CR1 |= TIM_CR1_CEN; + TIMx->DIER = TIM_DIER_UIE /*overflow*/ | TIM_DIER_TIE /*trigger*/; + TIMx->CR1 |= TIM_CR1_CEN; } #define CIR_PERIOD_ON_RC5_OR_RC6 (((cir_proto == CIR_PROTO_RC5) ? 2 : 1) \ * 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 cir_timer_interrupt (void) { uint16_t period, on, off; - period = TIM3->CCR1; - on = TIM3->CCR2; + period = TIMx->CCR1; + on = TIMx->CCR2; off = period - on; - if ((TIM3->SR & TIM_SR_TIF)) + if ((TIMx->SR & TIM_SR_TIF)) { if (cir_seq == 0) { @@ -477,23 +799,23 @@ cir_timer_interrupt (void) intr_trg++; #endif - TIM3->EGR = TIM_EGR_UG; /* Generate UEV */ - TIM3->SR &= ~TIM_SR_TIF; + TIMx->EGR = TIM_EGR_UG; /* Generate UEV */ + TIMx->SR &= ~TIM_SR_TIF; } else /* overflow occurred */ { systime_t now = chTimeNow (); - TIM3->SR &= ~TIM_SR_UIF; + TIMx->SR &= ~TIM_SR_UIF; if (on > 0) { uint8_t ignore_input = 0; /* Disable the timer */ - TIM3->CR1 &= ~TIM_CR1_CEN; - TIM3->DIER = 0; + TIMx->CR1 &= ~TIM_CR1_CEN; + TIMx->DIER = 0; if (cir_seq == 12 || cir_seq == 15) { @@ -536,14 +858,9 @@ cir_timer_interrupt (void) cir_input_last = now; ignore_input = 1; } - /* Remove ADDRESS bits and filter COMMAND bits */ else if (cir_proto == CIR_PROTO_SONY) { - if (cir_seq == 1 + 12) - cir_data = cir_data & 0x007f; - else if (cir_seq == 1 + 15) - cir_data = cir_data & 0x00ff; - else + if (cir_seq != 1 + 12 && cir_seq != 1 + 15) ignore_input = 1; } else if (cir_proto == CIR_PROTO_OTHER) @@ -551,10 +868,7 @@ cir_timer_interrupt (void) if (cir_seq == 1 + 32) { if (((cir_data >> 16) & 0xff) == ((cir_data >> 24) ^ 0xff)) - { - cir_proto = CIR_PROTO_NEC; - cir_data = (cir_data >> 16) & 0x00ff; - } + cir_proto = CIR_PROTO_NEC; else ignore_input = 1; } @@ -569,10 +883,7 @@ cir_timer_interrupt (void) ^ ((cir_data >> 20) & 0x0f) ^ ((cir_data >> 16) & 0x0f) ^ ((cir_data >> 12) & 0x0f) ^ ((cir_data >> 8) & 0x0f) ^ ((cir_data >> 4) & 0x0f) ^ (cir_data & 0x0f))) - { - cir_proto = CIR_PROTO_SHARP; - cir_data = (cir_data >> 16) & 0x0fff; - } + cir_proto = CIR_PROTO_SHARP; else ignore_input = 1; } @@ -581,16 +892,12 @@ cir_timer_interrupt (void) } else if (cir_proto == CIR_PROTO_RC6) { - if (cir_seq == 16 || cir_seq == 32) - cir_data &= 0x00ff; - else + if (cir_seq != 16 && cir_seq != 32) ignore_input = 1; } else if (cir_proto == CIR_PROTO_RC5) { - if (cir_seq == 14) - cir_data &= 0x003f; - else + if (cir_seq != 14) ignore_input = 1; } else @@ -603,7 +910,8 @@ cir_timer_interrupt (void) { cir_input_last = now; /* Notify thread */ - chEvtSignal (pin_thread, (eventmask_t)1); + if (pin_thread) + chEvtSignalI (pin_thread, (eventmask_t)1); } #if defined(DEBUG_CIR) diff --git a/src/usb_prop.c b/src/usb_prop.c index 1abef3e..f9b06ef 100644 --- a/src/usb_prop.c +++ b/src/usb_prop.c @@ -120,8 +120,14 @@ gnuk_device_SetConfiguration (void) DEVICE_INFO *pInfo = &Device_Info; if (pInfo->Current_Configuration != 0) - /* Device configured */ - bDeviceState = CONFIGURED; + { /* Device 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