X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=test-display2%2Fmain.c;h=e12ee0284966be5b8ad190895fa68fad6deaa5b8;hb=a9d52ef421c6de4507ec8d294665e55fc83bfe49;hp=3c8049869c7abefc182d595129327af8507d7f2c;hpb=9f545c433a380389eb6ed78bdb47501c879ab192;p=home-hw.git diff --git a/test-display2/main.c b/test-display2/main.c index 3c80498..e12ee02 100644 --- a/test-display2/main.c +++ b/test-display2/main.c @@ -21,6 +21,8 @@ #include +static void ep82_send(u32 key_code); + /*** Hardware init ***/ static void clock_init(void) @@ -122,9 +124,29 @@ static void delay_ms(uint ms) static byte disp[4]; static byte ctrl = 0x56; +static const byte disp_font[] = { + [0] = 0xee, + [1] = 0x82, + [2] = 0xdc, + [3] = 0xd6, + [4] = 0xb2, + [5] = 0x76, + [6] = 0x7e, + [7] = 0xc2, + [8] = 0xfe, + [9] = 0xf6, + [10] = 0xea, + [11] = 0x3e, + [12] = 0x6c, + [13] = 0x9e, + [14] = 0x7c, + [15] = 0x78, +}; + static void display_update(void) { // debug_puts("Display update\n"); + byte cmds[4]; cmds[0] = 0; cmds[1] = ctrl; @@ -146,63 +168,20 @@ static void display_init(void) i2c_set_speed(I2C1, i2c_speed_sm_100k, rcc_apb1_frequency / 1000000); i2c_peripheral_enable(I2C1); - disp[0] = 0x82; - disp[1] = 0xdc; - disp[2] = 0xd6; - disp[3] = 0xb2; - display_update(); -} - -static void display_test(void) -{ - static byte mode; - - disp[0] ^= 0x01; + disp[0] = 0x10; + disp[1] = 0x10; + disp[2] = 0x10; + disp[3] = 0x10; display_update(); - -#if 0 - byte cmds[] = { 0x00, mode ? 0x77 : 0x77 }; - i2c_transfer7(I2C1, 0x70/2, (byte *) cmds, sizeof(cmds), NULL, 0); -#endif - -#if 0 - byte disp[] = { 0xff, 0xff, mode ? 0xff : 0x00, mode ? 0xff : 0xff }; - byte cmds[] = { 0x00, 0x77, 0, 0, 0, 0 }; - cmds[2] = (disp[0] & 0xf0) | (disp[2] >> 4); - cmds[3] = (disp[1] & 0xf0) | (disp[3] >> 4); - cmds[4] = (disp[2] & 0x0f) | (disp[0] << 4); - cmds[5] = (disp[3] & 0x0f) | (disp[1] << 4); - i2c_transfer7(I2C1, 0x70/2, (byte *) cmds, sizeof(cmds), NULL, 0); -#endif - - mode = !mode; } -static const byte lcd_font[] = { - [0] = 0xee, - [1] = 0x82, - [2] = 0xdc, - [3] = 0xd6, - [4] = 0xb2, - [5] = 0x76, - [6] = 0x7e, - [7] = 0xc2, - [8] = 0xfe, - [9] = 0xf6, - [10] = 0xea, - [11] = 0x3e, - [12] = 0x6c, - [13] = 0x9e, - [14] = 0x7c, - [15] = 0x78, -}; - /*** Infrared Remote Control ***/ static void ir_init(void) { debug_puts("IR init\n"); + // TIM1 will measure pulses and spaces between them with 1μs resolution timer_set_prescaler(TIM1, 71); // 72 MHz / 72 = 1 MHz timer_set_mode(TIM1, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); timer_set_period(TIM1, 65535); @@ -217,7 +196,7 @@ static void ir_init(void) timer_ic_set_input(TIM1, TIM_IC2, TIM_IC_IN_TI1); timer_set_oc_polarity_high(TIM1, TIM_OC2); - // CH3 will trigger on a break longer than 50 ms + // OC3 will trigger on a break longer than 50 ms timer_set_oc_mode(TIM1, TIM_OC3, TIM_OCM_ACTIVE); timer_set_oc_value(TIM1, TIM_OC3, 30000); @@ -237,10 +216,33 @@ static void ir_init(void) timer_enable_counter(TIM1); } -#define IR_MAX_PULSES 64 -static u16 ir_pulses[IR_MAX_PULSES]; -static uint ir_num_pulses; +// Circular queue of pulse durations +#define IR_MAX_PULSES 32 +static u32 ir_pulses[IR_MAX_PULSES]; // Top 16 bits = mark, bottom 16 bits = space static u16 ir_last_pulse; +static uint ir_pulses_rx, ir_pulses_tx; + +#define IR_INF 0xffff + +#define IR_MARK(x) (uint)((x) >> 16) +#define IR_SPACE(x) (uint)((x) & 0xffff) + +static inline bool between(uint x, uint min, uint max) +{ + return x >= min && x <= max; +} + +static void ir_record_pulse(uint mark, uint space) +{ + uint i = ir_pulses_tx; + ir_pulses_tx = (i + 1) % IR_MAX_PULSES; + if (ir_pulses_tx != ir_pulses_rx) { + ir_pulses[i] = (mark << 16) | space; + } else { + // Overflow detected + ir_pulses[i] = (IR_INF << 16) | IR_INF; + } +} void tim1_cc_isr(void) { @@ -248,8 +250,7 @@ void tim1_cc_isr(void) TIM_SR(TIM1) &= ~TIM_SR_CC1IF; u16 now = TIM_CCR1(TIM1); if (ir_last_pulse) { - ir_pulses[ir_num_pulses++] = ir_last_pulse; - ir_pulses[ir_num_pulses++] = now - ir_last_pulse; + ir_record_pulse(ir_last_pulse, now - ir_last_pulse); ir_last_pulse = 0; } } @@ -260,10 +261,83 @@ void tim1_cc_isr(void) if (TIM_SR(TIM1) & TIM_SR_CC3IF) { TIM_SR(TIM1) &= ~TIM_SR_CC3IF; if (ir_last_pulse) { - ir_pulses[ir_num_pulses++] = ir_last_pulse; - ir_pulses[ir_num_pulses++] = 0xffff; + ir_record_pulse(ir_last_pulse, IR_INF); + ir_last_pulse = 0; + } + } +} + +static u32 ir_get_pulse(void) +{ + u32 out = 0; + + cm_disable_interrupts(); + if (ir_pulses_rx != ir_pulses_tx) { + out = ir_pulses[ir_pulses_rx]; + ir_pulses_rx = (ir_pulses_rx + 1) % IR_MAX_PULSES; + } + cm_enable_interrupts(); + return out; +} + +// Decoder for Onkyo RC-748S + +static void ir_decode(void) +{ + u32 pulse = ir_get_pulse(); + if (!pulse) + return; + + uint mark = IR_MARK(pulse); + uint space = IR_SPACE(pulse); + +#ifdef IR_TEST + debug_printf("IR: %d %d\n", mark, space); + return; +#endif + + static u16 ir_bits; + static u32 ir_code; +#define IR_ERR 0xff + + // debug_printf("IR(%d): %d %d\n", ir_bits, mark, space); + + if (space == IR_INF) { + ir_bits = 0; + } else if (ir_bits == IR_ERR) { + // Error state + } else if (ir_bits == 0) { + // Start? + if (between(mark, 8900, 9200)) { + if (between(space, 4200, 4600)) { + ir_bits = 1; + ir_code = 0; + } else if (between(space, 2000, 2300)) { + debug_printf("IR: => REP\n"); + ir_bits = IR_ERR; + } + } + } else { + if (between(mark, 500, 700)) { + ir_bits++; + if (between(space, 400, 700)) { + // 0 + } else if (between(space, 1500, 1800)) { + // 1 + ir_code |= 1U << (33 - ir_bits); + } else { + ir_bits = IR_ERR; + } + if (ir_bits == 33) { + debug_printf("IR: => %08x\n", (uint)ir_code); + disp[3] ^= 0x01; + display_update(); + ir_bits = IR_ERR; + ep82_send(ir_code); + } + } else { + ir_bits = IR_ERR; } - ir_last_pulse = 0; } } @@ -310,6 +384,14 @@ static const struct usb_endpoint_descriptor endpoints[] = {{ .bmAttributes = USB_ENDPOINT_ATTR_BULK, .wMaxPacketSize = 64, .bInterval = 1, +}, { + // Bulk end-point for receiving remote control keys + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x82, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = 4, + .bInterval = 1, }}; static const struct usb_interface_descriptor iface = { @@ -317,7 +399,7 @@ static const struct usb_interface_descriptor iface = { .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = 0, .bAlternateSetting = 0, - .bNumEndpoints = 1, + .bNumEndpoints = 2, .bInterfaceClass = 0xFF, .bInterfaceSubClass = 0, .bInterfaceProtocol = 0, @@ -369,9 +451,14 @@ static const struct usb_config_descriptor config = { .interface = ifaces, }; -static byte usb_configured; +static bool usb_configured; static uint8_t usbd_control_buffer[64]; +static bool usb_tx_in_flight; +static byte ep82_tx_buffer[4]; + +static byte disp_alive; + static void dfu_detach_complete(usbd_device *dev UNUSED, struct usb_setup_data *req UNUSED) { // Reset to bootloader, which implements the rest of DFU @@ -401,15 +488,36 @@ static void ep01_cb(usbd_device *dev, uint8_t ep UNUSED) debug_printf("USB: Host sent %u bytes\n", len); if (len >= 5) { for (uint i=0; i<4; i++) { + disp[i] &= 0x01; if (buf[i] < 16) - disp[i] = lcd_font[buf[i]]; - else - disp[i] = 0; + disp[i] |= disp_font[buf[i]]; } + disp[1] &= 0xfe; if (buf[4]) - disp[1] |= 1; + disp[1] |= 0x01; display_update(); + disp_alive = 10; + } +} + +static void ep82_send(u32 key_code) +{ + if (usb_tx_in_flight) { + debug_printf("USB: Send overrun!\n"); + return; } + + debug_printf("USB: Sending key to host\n"); + put_u32_be(ep82_tx_buffer, key_code); + usbd_ep_write_packet(usbd_dev, 0x82, ep82_tx_buffer, 4); + usb_tx_in_flight = true; +} + +static void ep82_cb(usbd_device *dev UNUSED, uint8_t ep UNUSED) +{ + // We completed sending a frame to the USB host + usb_tx_in_flight = false; + debug_printf("USB: Key sending complete\n"); } static void set_config_cb(usbd_device *dev, uint16_t wValue UNUSED) @@ -420,13 +528,14 @@ static void set_config_cb(usbd_device *dev, uint16_t wValue UNUSED) USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, dfu_control_cb); usbd_ep_setup(dev, 0x01, USB_ENDPOINT_ATTR_BULK, 64, ep01_cb); - usb_configured = 1; + usbd_ep_setup(dev, 0x82, USB_ENDPOINT_ATTR_BULK, 4, ep82_cb); + usb_configured = true; } static void reset_cb(void) { debug_printf("USB: Reset\n"); - usb_configured = 0; + usb_configured = false; } static volatile bool usb_event_pending; @@ -489,9 +598,20 @@ int main(void) if (ms_ticks - last_blink >= 500) { debug_led_toggle(); last_blink = ms_ticks; - display_test(); + if (disp_alive) { + if (!--disp_alive) { + disp[0] = (disp[0] & 0x01) | 0x10; + disp[1] = (disp[1] & 0x01) | 0x10; + disp[2] = (disp[2] & 0x01) | 0x10; + disp[3] = (disp[3] & 0x01) | 0x10; + } + } + disp[0] ^= 0x01; + display_update(); } + ir_decode(); + if (usb_event_pending) { usbd_poll(usbd_dev); usb_event_pending = 0; @@ -499,22 +619,6 @@ int main(void) nvic_enable_irq(NVIC_USB_LP_CAN_RX0_IRQ); } - static u16 pulses[IR_MAX_PULSES]; - uint np; - - cm_disable_interrupts(); - np = ir_num_pulses; - memcpy(pulses, ir_pulses, 2*np); - ir_num_pulses = 0; - cm_enable_interrupts(); - - if (np) { - debug_printf("IR:"); - for (uint i=0; i < np; i++) - debug_printf(" %u", pulses[i]); - debug_putc('\n'); - } - wait_for_interrupt(); }