{
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);
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);
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)
{
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;
}
}
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("==> 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("==> %08x\n", (uint)ir_code);
+ ir_bits = IR_ERR;
+ }
+ } else {
+ ir_bits = IR_ERR;
}
- ir_last_pulse = 0;
}
}
display_test();
}
+ ir_decode();
+
if (usb_event_pending) {
usbd_poll(usbd_dev);
usb_event_pending = 0;
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();
}