diff options
-rw-r--r-- | include/drv/ir/control.h | 14 | ||||
-rw-r--r-- | include/drv/ir/ir.h | 34 | ||||
-rw-r--r-- | include/drv/ir/lg_remote_codes.h | 17 | ||||
-rw-r--r-- | include/shared/avl_tree.h | 3 | ||||
-rw-r--r-- | src/drv/ir/control.c | 43 | ||||
-rw-r--r-- | src/drv/ir/ir.c | 160 | ||||
-rw-r--r-- | src/kern/lib.c | 5 | ||||
-rw-r--r-- | src/kern/main.c | 145 | ||||
-rw-r--r-- | src/kern/stdlibrepl.c | 7 |
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 |