aboutsummaryrefslogtreecommitdiff
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
parenta5923b21e48fcfe660c1e7d586fe0c6a5b79e421 (diff)
downloadstm32l4-5f1763ec87503527583cb1a7c6deb73604db0dfc.tar.gz
stm32l4-5f1763ec87503527583cb1a7c6deb73604db0dfc.tar.bz2
stm32l4-5f1763ec87503527583cb1a7c6deb73604db0dfc.zip
Can read from the A/C remote control!test_ir
-rw-r--r--include/drv/ir/control.h14
-rw-r--r--include/drv/ir/ir.h34
-rw-r--r--include/drv/ir/lg_remote_codes.h17
-rw-r--r--include/shared/avl_tree.h3
-rw-r--r--src/drv/ir/control.c43
-rw-r--r--src/drv/ir/ir.c160
-rw-r--r--src/kern/lib.c5
-rw-r--r--src/kern/main.c145
-rw-r--r--src/kern/stdlibrepl.c7
9 files changed, 308 insertions, 120 deletions
diff --git a/include/drv/ir/control.h b/include/drv/ir/control.h
new file mode 100644
index 0000000..11e3604
--- /dev/null
+++ b/include/drv/ir/control.h
@@ -0,0 +1,14 @@
+#ifndef _DRV_IR_CONTROL_H_
+#define _DRV_IR_CONTROL_H_
+
+#include "kern/common.h"
+
+#define add_ir_code_callback(code, fn, closure) \
+ add_ir_code_callback_(code, (void (*)(uint32_t, void*))(fn), closure)
+
+void add_ir_code_callback_(
+ uint32_t code, void (*fn)(uint32_t code, void* closure), void* closure);
+
+void enable_ir_control();
+
+#endif /* _DRV_IR_CONTROL_H_ */
diff --git a/include/drv/ir/ir.h b/include/drv/ir/ir.h
new file mode 100644
index 0000000..0a747e8
--- /dev/null
+++ b/include/drv/ir/ir.h
@@ -0,0 +1,34 @@
+#ifndef _DRV_IR_IR_H_
+#define _DRV_IR_IR_H_
+
+#include "kern/common.h"
+
+typedef struct {
+ uint16_t ts[64]; /* Timestamps. Microseconds. */
+ uint8_t n;
+} ir_code_t;
+
+typedef struct {
+ uint32_t c;
+} decoded_ir;
+
+/*
+ * Attempt to decode the provided ir code.
+ *
+ * The generic ir is:
+ *
+ * The frame starts out as really-long, half(ish) as long, short. If
+ * this basic frame header does not exist decoding cannot continue.
+ *
+ * A short code followed by a short code = 0
+ * A long code followed by a short code = 1
+ *
+ * returns non-zero on successful decode.
+ */
+int ir_generic_decode(const ir_code_t* code, uint32_t* out);
+
+void add_ir_callback(void(*callback)(const ir_code_t*));
+
+void ir_begin_listen();
+
+#endif /* _DRV_IR_IR_H_ */
diff --git a/include/drv/ir/lg_remote_codes.h b/include/drv/ir/lg_remote_codes.h
new file mode 100644
index 0000000..77cbb45
--- /dev/null
+++ b/include/drv/ir/lg_remote_codes.h
@@ -0,0 +1,17 @@
+#ifndef _DRV_IR_LG_REMOTE_CODES_H_
+#define _DRV_IR_LG_REMOTE_CODES_H_
+
+#define RC_HIGH 0x08e76800
+#define RC_TEMP_UP 0x08e7a800
+#define RC_DRY 0x08e72800
+#define RC_LOW 0x08e77000
+#define RC_TEMP_DOWN 0x08e7b000
+#define RC_COOL 0x08e73000
+#define RC_CONTINUOUS 0x08e75000
+#define RC_FAN 0x08e71000
+#define RC_SLEEP 0x08e76000
+#define RC_UNITS 0x08e72000
+#define RC_TIMER 0x08e78000
+#define RC_POWER 0x08e70080
+
+#endif /* _DRV_IR_LG_REMOTE_CODES_H_ */
diff --git a/include/shared/avl_tree.h b/include/shared/avl_tree.h
index 98151f2..2b174d3 100644
--- a/include/shared/avl_tree.h
+++ b/include/shared/avl_tree.h
@@ -7,6 +7,7 @@
#include <assert.h>
#include <stdio.h>
+#include "kern/common.h"
#include "kern/mem.h"
#include "shared/stdmacro.h"
@@ -29,8 +30,6 @@
#define null_dtor(a)
-typedef unsigned int bool;
-
#define AVL_TREE_DECL(T) \
typedef struct CONCAT(AVL_TREE_NODE_, T) { \
T value; \
diff --git a/src/drv/ir/control.c b/src/drv/ir/control.c
new file mode 100644
index 0000000..6be2cf1
--- /dev/null
+++ b/src/drv/ir/control.c
@@ -0,0 +1,43 @@
+#include "drv/ir/control.h"
+
+#include "drv/ir/ir.h"
+#include "shared/map.h"
+
+typedef struct {
+ void* closure;
+ void (*fn)(uint32_t code, void* closure);
+} ir_code_listener_t;
+
+#define integer_cmp_(a, b) (a - b)
+MAP_DECL(uint32_t, ir_code_listener_t);
+MAP_IMPL(uint32_t, ir_code_listener_t, integer_cmp_, null_dtor);
+
+static map_t(uint32_t, ir_code_listener_t) * listeners;
+
+static void ir_callback(const ir_code_t* ir)
+{
+ uint32_t code;
+ if (ir_generic_decode(ir, &code)) {
+ ir_code_listener_t* l =
+ map_get(uint32_t, ir_code_listener_t)(listeners, code);
+
+ if (l) {
+ l->fn(code, l->closure);
+ }
+ }
+}
+
+void add_ir_code_callback_(
+ uint32_t code, void (*fn)(uint32_t, void*), void* closure)
+{
+ ir_code_listener_t l;
+ l.fn = fn;
+ l.closure = closure;
+ map_put(uint32_t, ir_code_listener_t)(listeners, code, l);
+}
+
+void enable_ir_control()
+{
+ listeners = map_new(uint32_t, ir_code_listener_t)();
+ add_ir_callback(ir_callback);
+}
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);
+ }
+}
diff --git a/src/kern/lib.c b/src/kern/lib.c
index 24e1658..e0d3e23 100644
--- a/src/kern/lib.c
+++ b/src/kern/lib.c
@@ -37,6 +37,11 @@ void decimalify(int v, char* into)
*into = 0;
return;
} else {
+ if (v < 0) {
+ v = -v;
+ *(into++) = '-';
+ }
+
while (v > 0) {
*(into++) = 0x30 + (v % 10);
v /= 10;
diff --git a/src/kern/main.c b/src/kern/main.c
index 082d450..208f5d9 100644
--- a/src/kern/main.c
+++ b/src/kern/main.c
@@ -2,13 +2,16 @@
#include "arch/arm/cortex-m4/mpu.h"
#include "arch/stm32l4xxx/peripherals/clock.h"
#include "arch/stm32l4xxx/peripherals/dma.h"
-#include "arch/stm32l4xxx/peripherals/tim.h"
#include "arch/stm32l4xxx/peripherals/exti.h"
#include "arch/stm32l4xxx/peripherals/irq.h"
#include "arch/stm32l4xxx/peripherals/rcc.h"
#include "arch/stm32l4xxx/peripherals/spi.h"
#include "arch/stm32l4xxx/peripherals/syscfg.h"
#include "arch/stm32l4xxx/peripherals/system.h"
+#include "arch/stm32l4xxx/peripherals/tim.h"
+#include "drv/ir/control.h"
+#include "drv/ir/ir.h"
+#include "drv/ir/lg_remote_codes.h"
#include "drv/ws2812B/ws2812b.h"
#include "kern/delay.h"
#include "kern/dma/dma_manager.h"
@@ -23,15 +26,7 @@
#include "kern/spi/spi_manager.h"
#include "kern/systick/systick_manager.h"
#include "user/syscall.h"
-
-void on_exti9_5()
-{
- klogf("Exit Interrupt!\n");
- klogf("Pending Reg_again: %p\n", EXTI.p_r1);
- klogf("Write: %p\n", (1 << 6));
- EXTI.p_r1 |= 1 << 6;
- klogf("Pending Reg_again: %p\n", EXTI.p_r1);
-}
+#include <assert.h>
void on_hard_fault()
{
@@ -40,120 +35,34 @@ void on_hard_fault()
#ifdef ARCH_STM32L4
-void configure_gpio()
+void printit(uint32_t code, const char* str)
{
- int ec = 0;
-
- gpio_enable_alternate_function(
- GPIO_ALTERNATE_FUNCTION_SPI1_MOSI, GPIO_PIN_PA7, &ec);
- if (ec) {
- panic("Unable to set pin PA7 (ec=%d)\n", ec);
- }
- gpio_enable_alternate_function(
- GPIO_ALTERNATE_FUNCTION_SPI1_NSS, GPIO_PIN_PA4, &ec);
- if (ec) {
- panic("Unable to set pin PA4 (ec=%d)\n", ec);
- }
- gpio_enable_alternate_function(
- GPIO_ALTERNATE_FUNCTION_SPI1_SCK, GPIO_PIN_PA5, &ec);
- if (ec) {
- panic("Unable to set pin PA5 (ec=%d)\n", ec);
- }
-}
-
-static uint8_t* compiled;
-static size_t compiled_len;
-
-extern uint8_t sintable[256];
-
-static uint32_t time;
-
-static void on_systick(void* nil)
-{
- ++time;
-}
-
-#define min(a, b) (a) < (b) ? (a) : (b)
-
-static uint8_t amp(uint8_t in)
-{
- uint32_t out = in;
-
- for (int i = 0; i < 20; ++i) {
- out = (out * in) / 256;
- }
-
- return min(out, 255);
-}
-
-static uint32_t bytescale(uint32_t n, uint32_t sc)
-{
- return n * sc / 255;
-}
-
-void on_tim2()
-{
- if (regget(TIM2.s_r, tim_uif)) {
- regset(TIM2.s_r, tim_uif, 0);
- }
-
- klogf("Tim2 Update\n");
+ (void)code;
+ klogf("%s\n", str);
}
/* Main function. This gets executed from the interrupt vector defined above. */
int main()
{
- regset(RCC.apb2en_r, rcc_syscfgen, 1);
-
- klogf("Entering main\n");
-
- klogf("Enable ir\n");
- enable_interrupt(IRQ_TIM2);
- klogf("Enable clock\n");
- regset(RCC.apb1en1_r, rcc_tim2en, 1);
- klogf("psc\n");
- TIM2.psc = 39999; /* Counts every half millisecond. */
- klogf("ar_r\n");
- TIM2.ar_r = 1000;
- klogf("die_r\n");
- regset(TIM2.die_r, tim_uie, 1);
- klogf("eg_r\n");
- regset(TIM2.eg_r, tim_ug, 1);
- klogf("c_r1\n");
- regset(TIM2.c_r1, tim_cen, 1);
-
- int ec;
- gpio_reserved_pin_t sysled = get_sysled();
-
- 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);
-
- if (ec) {
- panic("Unable to reserve GPIO pin ec=%d\n", ec);
- }
-
- // while (1) {
- // if (get_gpio_pin_input_state(pb6)) {
- // set_gpio_pin_high(sysled);
- // } else {
- // set_gpio_pin_low(sysled);
- // }
- // // klogf("GPIO is set? %d\n", get_gpio_pin_input_state(pb6));
- // }
-
- 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. */
- enable_interrupt(IRQ_EXTI9_5);
- enable_interrupt(IRQ_EXTI0_IRQ);
- enable_interrupt(IRQ_EXTI1_IRQ);
- enable_interrupt(IRQ_EXTI2_IRQ);
- enable_interrupt(IRQ_EXTI3_IRQ);
- enable_interrupt(IRQ_EXTI4_IRQ);
-
- for(;;);
+ klogf("Ir begin listening\n");
+ ir_begin_listen();
+ enable_ir_control();
+
+ add_ir_code_callback(RC_HIGH, printit, "RC_HIGH");
+ add_ir_code_callback(RC_TEMP_UP, printit, "RC_TEMP_UP");
+ add_ir_code_callback(RC_DRY, printit, "RC_DRY");
+ add_ir_code_callback(RC_LOW, printit, "RC_LOW");
+ add_ir_code_callback(RC_TEMP_DOWN, printit, "RC_TEMP_DOWN");
+ add_ir_code_callback(RC_COOL, printit, "RC_COOL");
+ add_ir_code_callback(RC_CONTINUOUS, printit, "RC_CONTINUOUS");
+ add_ir_code_callback(RC_FAN, printit, "RC_FAN");
+ add_ir_code_callback(RC_SLEEP, printit, "RC_SLEEP");
+ add_ir_code_callback(RC_UNITS, printit, "RC_UNITS");
+ add_ir_code_callback(RC_TIMER, printit, "RC_TIMER");
+ add_ir_code_callback(RC_POWER, printit, "RC_POWER");
+
+ for (;;)
+ ;
}
#endif
diff --git a/src/kern/stdlibrepl.c b/src/kern/stdlibrepl.c
index 38b8477..676b820 100644
--- a/src/kern/stdlibrepl.c
+++ b/src/kern/stdlibrepl.c
@@ -1,4 +1,5 @@
#include "arch.h"
+#include "kern/panic.h"
/*
* Replacement for common stdlib functions that don't exist
* on the ARM bare-metal compilation environment.
@@ -48,4 +49,10 @@ int memcmp(const void* s1_, const void* s2_, size_t size)
return 0;
}
+void __assert_func(
+ const char* file, int line, const char* func, const char* failedexpr)
+{
+ panic("Assertion failed: %s:%d in %s at %s\n", file, line, func, failedexpr);
+}
+
#endif