aboutsummaryrefslogtreecommitdiff
path: root/src/drv/ir/ir.c
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2020-12-09 23:15:14 -0700
committerJosh Rahm <joshuarahm@gmail.com>2020-12-09 23:15:14 -0700
commit5f1763ec87503527583cb1a7c6deb73604db0dfc (patch)
tree0892ddf94b614db2d879f7bc993961af5ac25bb2 /src/drv/ir/ir.c
parenta5923b21e48fcfe660c1e7d586fe0c6a5b79e421 (diff)
downloadstm32l4-test_ir.tar.gz
stm32l4-test_ir.tar.bz2
stm32l4-test_ir.zip
Can read from the A/C remote control!test_ir
Diffstat (limited to 'src/drv/ir/ir.c')
-rw-r--r--src/drv/ir/ir.c160
1 files changed, 160 insertions, 0 deletions
diff --git a/src/drv/ir/ir.c b/src/drv/ir/ir.c
new file mode 100644
index 0000000..c84417d
--- /dev/null
+++ b/src/drv/ir/ir.c
@@ -0,0 +1,160 @@
+#include "drv/ir/ir.h"
+
+#include "arch/stm32l4xxx/peripherals/exti.h"
+#include "arch/stm32l4xxx/peripherals/irq.h"
+#include "arch/stm32l4xxx/peripherals/rcc.h"
+#include "arch/stm32l4xxx/peripherals/syscfg.h"
+#include "arch/stm32l4xxx/peripherals/tim.h"
+#include "kern/gpio/gpio_manager.h"
+#include "kern/mem.h"
+#include "kern/log.h"
+#include "kern/panic.h"
+#include "shared/linked_list.h"
+
+typedef void (*ir_callback_t)(const ir_code_t*);
+
+LINKED_LIST_DECL(ir_callback_t);
+LINKED_LIST_IMPL(ir_callback_t);
+
+static linked_list_t(ir_callback_t) callbacks;
+static ir_code_t read_into;
+
+void on_exti9_5()
+{
+ EXTI.p_r1 |= 1 << 6;
+ /* The IR pin has been activated. */
+
+ if (read_into.n == 0) {
+ /* Starting fresh, start the timer. */
+ regset(TIM2.c_r1, tim_cen, 1);
+ read_into.ts[read_into.n ++] = 0;
+ } else {
+ uint32_t ts = TIM2.cnt;
+ if (read_into.n < 64) {
+ read_into.ts[read_into.n++] = ts;
+ }
+ }
+}
+
+typedef enum {
+ PARITY_LOW = 0,
+ PARITY_HIGH = 1
+} ir_parity_t;
+
+static ir_parity_t ir_discover_parity(const ir_code_t* code)
+{
+ uint32_t max_even = 0;
+ uint32_t min_even = (uint32_t) -1;
+
+ uint32_t max_odd = 0;
+ uint32_t min_odd = (uint32_t) -1;
+
+ for (int i = 3; i < code->n; ++ i) {
+ uint32_t n = code->ts[i] - code->ts[i-1];
+ if (i % 2 == 0) {
+ if (n < min_even) {
+ min_even = n;
+ } else if (n > max_even) {
+ max_even = n;
+ }
+ } else {
+ if (n < min_odd) {
+ min_odd = n;
+ } else if (n > max_odd) {
+ max_odd = n;
+ }
+ }
+ }
+
+ if (max_even - min_even > max_odd - min_odd) {
+ return PARITY_LOW;
+ } else {
+ return PARITY_HIGH;
+ }
+}
+
+int ir_generic_decode(
+ const ir_code_t* code, uint32_t* out_)
+{
+ if (code->n < 5) {
+ return 0;
+ }
+
+ uint32_t min = (uint32_t) -1;
+ uint32_t max = 0;
+
+ uint32_t start = 4 + ir_discover_parity(code);
+
+ for (int i = start; i < code->n; i += 2) {
+ uint32_t n = code->ts[i] - code->ts[i-1];
+
+ if (n > max) {
+ max = n;
+ } else if (n < min) {
+ min = n;
+ }
+ }
+
+ uint32_t mid = (max + min) / 2;
+
+ uint32_t out = 0;
+ uint32_t mask = 0x80000000;
+
+ for (int i = start; i < code->n; i += 2) {
+ if ((code->ts[i] - code->ts[i-1]) >= mid) {
+ out |= mask;
+ }
+ mask >>= 1;
+ }
+
+ *out_ = out;
+ return 1;
+}
+
+void on_tim2()
+{
+ if (regget(TIM2.s_r, tim_uif)) {
+ regset(TIM2.s_r, tim_uif, 0);
+ }
+
+ /* The timer has run out. */
+ linked_list_foreach(callbacks, cb) { cb(&read_into); }
+
+ read_into.n = 0;
+}
+
+void add_ir_callback(ir_callback_t callback)
+{
+ linked_list_push_front(ir_callback_t)(&callbacks, callback);
+}
+
+void ir_begin_listen()
+{
+ int ec;
+
+ gpio_pin_opts_t opts = DEFAULT_GPIO_OPTS_INPUT;
+ opts.pull_dir = GPIO_PULL_DIR_NONE;
+ gpio_reserved_pin_t pb6 = reserve_gpio_pin(GPIO_PIN_PB6, &opts, &ec);
+
+ regset(RCC.apb1en1_r, rcc_tim2en, 1);
+ regset(RCC.apb2en_r, rcc_syscfgen, 1);
+
+ enable_interrupt(IRQ_TIM2);
+ enable_interrupt(IRQ_EXTI9_5);
+
+ /* Configure the timer. */
+ TIM2.psc = 80; /* Counts every microsecond. */
+ TIM2.ar_r = 50000; /* Stop after 50ms. */
+ regset(TIM2.die_r, tim_uie, 1); /* Enable interrupts. */
+ regset(TIM2.c_r1, tim_opm, 1); /* Set one-pulse-mode. */
+
+ /* Configure the external interrupts. */
+ regset(SYSCFG.extic_r2, syscfg_exti6, 1 /* Port B. */);
+ regset(EXTI.im_r1, exti_im_n(6), 1); /* Enable the EXTI interrupt. */
+ regset(EXTI.fts_r1, exti_ft_n(6), 1); /* Enable for falling edge. */
+ regset(EXTI.rts_r1, exti_rt_n(6), 1); /* Enable for rising edge. */
+
+ if (ec) {
+ panic("Unable to reserve GPIO pin ec=%d\n", ec);
+ }
+}