From 63e0954d8deea8f5a18e95b8faed2c5754e914b7 Mon Sep 17 00:00:00 2001
From: schneider <schneider@blinkenlichts.net>
Date: Thu, 11 Aug 2022 00:00:51 +0200
Subject: [PATCH] hack: nec IR stuff

---
 epicardium/drivers/ir.c        | 80 ++++++++++++++++++++++++++++++++++
 epicardium/drivers/meson.build |  1 +
 epicardium/epicardium.h        |  3 +-
 pycardium/modules/qstrdefs.h   |  1 +
 pycardium/modules/ws2812.c     | 15 +++++++
 5 files changed, 99 insertions(+), 1 deletion(-)
 create mode 100644 epicardium/drivers/ir.c

diff --git a/epicardium/drivers/ir.c b/epicardium/drivers/ir.c
new file mode 100644
index 000000000..c17922da2
--- /dev/null
+++ b/epicardium/drivers/ir.c
@@ -0,0 +1,80 @@
+#include "leds.h"
+#include "pmic.h"
+#include "FreeRTOS.h"
+#include "task.h"
+#include "epicardium.h"
+#include "max32665.h"
+#include "gpio.h"
+#include "modules/modules.h"
+#include "drivers/drivers.h"
+
+#include <stdbool.h>
+
+//#define KHZ38_PERIOD (340)
+#define KHZ38_PERIOD (310)
+
+static const uint32_t NEC_LEAD_IN = 38e3 * 9e-3;
+static const uint32_t NEC_SPACE = 38e3 * 4.5e-3;
+
+static const uint32_t NEC_ONE_T1 = 38e3 * 562.5e-6;
+static const uint32_t NEC_ONE_T2 = 38e3 * 1687.5e-6;
+
+static const uint32_t NEC_ZERO_T1 = 38e3 * 562.5e-6;
+static const uint32_t NEC_ZERO_T2 = 38e3 * 562.5e-6;
+
+static const uint32_t NEC_LEAD_OUT = 38e3 * 562.5e-6;
+
+static inline __attribute__((always_inline)) void
+delay_ticks(uint32_t ticks)
+{
+	volatile uint32_t counter = ticks;
+	while (--counter) {
+	};
+}
+
+static inline __attribute__((always_inline)) void
+epic_ir_transmit_wave(gpio_cfg_t *pin, uint32_t half_period, uint32_t count)
+{
+	while(count--) {
+		GPIO_OutSet(pin);
+		delay_ticks(half_period);
+		GPIO_OutClr(pin);
+		delay_ticks(half_period);
+	}
+}
+
+static void ir_transmit_nec_bit(gpio_cfg_t *pin,uint8_t bit)
+{
+	if(bit) {
+		epic_ir_transmit_wave(pin, KHZ38_PERIOD/2, NEC_ONE_T1);
+		delay_ticks(NEC_ONE_T2 * KHZ38_PERIOD);
+	} else {
+		epic_ir_transmit_wave(pin, KHZ38_PERIOD/2, NEC_ZERO_T1);
+		delay_ticks(NEC_ZERO_T2 * KHZ38_PERIOD);
+	}
+}
+
+static void ir_transmit_nec_byte(gpio_cfg_t *pin, uint8_t byte)
+{
+	for(uint32_t i = 0; i < 8; i++) {
+		ir_transmit_nec_bit(pin, byte & (1<<i));
+	}
+}
+
+void epic_ir_transmit_nec(uint8_t pin, uint8_t address, uint8_t command)
+{
+	gpio_cfg_t *pin_cfg = &gpio_configs[pin];
+
+	//if ((epic_gpio_get_pin_mode(pin) & EPIC_GPIO_MODE_OUT) == 0) {
+	//	epic_gpio_set_pin_mode(pin, EPIC_GPIO_MODE_OUT);
+	//}
+
+	epic_ir_transmit_wave(pin_cfg, KHZ38_PERIOD/2, NEC_LEAD_IN);
+	delay_ticks(NEC_SPACE * KHZ38_PERIOD);
+	ir_transmit_nec_byte(pin_cfg, address);
+	ir_transmit_nec_byte(pin_cfg, ~address);
+	ir_transmit_nec_byte(pin_cfg, command);
+	ir_transmit_nec_byte(pin_cfg, ~command);
+	epic_ir_transmit_wave(pin_cfg, KHZ38_PERIOD/2, NEC_LEAD_OUT);
+}
+
diff --git a/epicardium/drivers/meson.build b/epicardium/drivers/meson.build
index 3ad236783..90f6216d3 100644
--- a/epicardium/drivers/meson.build
+++ b/epicardium/drivers/meson.build
@@ -4,6 +4,7 @@ driver_sources = files(
   'bme680.c',
   'buttons.c',
   'gpio.c',
+  'ir.c',
   'leds.c',
   'light_sensor.c',
   'max86150.c',
diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h
index bc32e5cab..0a79764a9 100644
--- a/epicardium/epicardium.h
+++ b/epicardium/epicardium.h
@@ -148,6 +148,7 @@ typedef _Bool bool;
 #define API_USB_CDCACM             0x112
 
 #define API_WS2812_WRITE           0x0120
+#define API_IR_TRANSMIT_NEC        0x0121
 
 #define API_CONFIG_GET_STRING      0x130
 #define API_CONFIG_GET_INTEGER     0x131
@@ -2314,7 +2315,7 @@ API(API_USB_CDCACM, int epic_usb_cdcacm(void));
  * .. versionadded:: 1.10
  */
 API(API_WS2812_WRITE, void epic_ws2812_write(uint8_t pin, uint8_t *pixels, uint32_t n_bytes));
-
+API(API_IR_TRANSMIT_NEC, void epic_ir_transmit_nec(uint8_t pin, uint8_t address, uint8_t command));
 
 /**
  * Configuration
diff --git a/pycardium/modules/qstrdefs.h b/pycardium/modules/qstrdefs.h
index 01f32c679..2edc369b6 100644
--- a/pycardium/modules/qstrdefs.h
+++ b/pycardium/modules/qstrdefs.h
@@ -193,6 +193,7 @@ Q(MAX86150_PROX)
 /* ws2812 */
 Q(ws2812)
 Q(set_all)
+Q(transmit_nec)
 
 /* config */
 Q(config)
diff --git a/pycardium/modules/ws2812.c b/pycardium/modules/ws2812.c
index 4df1d84a0..180ded36c 100644
--- a/pycardium/modules/ws2812.c
+++ b/pycardium/modules/ws2812.c
@@ -36,10 +36,25 @@ static mp_obj_t mp_ws2812_set_all(mp_obj_t pin, mp_obj_t color_in)
 }
 static MP_DEFINE_CONST_FUN_OBJ_2(ws2812_set_all_obj, mp_ws2812_set_all);
 
+static mp_obj_t mp_ws2812_transmit_nec(mp_obj_t pin, mp_obj_t address, mp_obj_t command)
+{
+	mp_int_t pin_int     = mp_obj_get_int(pin);
+	mp_int_t address_int = mp_obj_get_int(address);
+	mp_int_t command_int = mp_obj_get_int(command);
+
+	/* call epicardium to be fast enough */
+	epic_ir_transmit_nec(pin_int, address_int, command_int);
+
+	return mp_const_none;
+}
+static MP_DEFINE_CONST_FUN_OBJ_3(ws2812_transmit_nec_obj, mp_ws2812_transmit_nec);
+
+
 /* The globals table for this module */
 static const mp_rom_map_elem_t ws2812_module_globals_table[] = {
 	{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ws2812) },
 	{ MP_ROM_QSTR(MP_QSTR_set_all), MP_ROM_PTR(&ws2812_set_all_obj) },
+	{ MP_ROM_QSTR(MP_QSTR_transmit_nec), MP_ROM_PTR(&ws2812_transmit_nec_obj) },
 };
 static MP_DEFINE_CONST_DICT(ws2812_module_globals, ws2812_module_globals_table);
 
-- 
GitLab