Skip to content

Commit

Permalink
Add IR module
Browse files Browse the repository at this point in the history
  • Loading branch information
ecrips committed May 8, 2020
1 parent 88a33af commit feed962
Show file tree
Hide file tree
Showing 2 changed files with 249 additions and 0 deletions.
1 change: 1 addition & 0 deletions app/include/user_modules.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
//#define LUA_USE_MODULES_HTTP
//#define LUA_USE_MODULES_HX711
#define LUA_USE_MODULES_I2C
//#define LUA_USE_MODULES_IR
//#define LUA_USE_MODULES_L3G4200D
//#define LUA_USE_MODULES_MCP4725
//#define LUA_USE_MODULES_MDNS
Expand Down
248 changes: 248 additions & 0 deletions app/modules/ir.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
//#define NODE_DEBUG

#include "module.h"
#include "lauxlib.h"
#include "lmem.h"
#include "platform.h"
#include "user_interface.h"
#include <stdint.h>
#include <string.h>
#include "gpio.h"
#include "hw_timer.h"

/* Must be a power of 2 (max 128 without changing types) */
#define RAWBUF_SIZE 128
#define RAWBUF_MASK (RAWBUF_SIZE - 1)

#define CB_RAW 0
#define CB_RC5 1

static task_handle_t tasknumber;
static ETSTimer timer;
static struct {
int cb[2];
uint32_t last_time;
uint16_t rawbuf[RAWBUF_SIZE];
uint16_t rc5_data;
uint8_t rc5_state;
uint8_t rawbuf_read;
uint8_t rawbuf_write;
uint8_t pin, pin_num;
uint8_t setup;
} data;

static uint32_t ICACHE_RAM_ATTR lir_interrupt(uint32_t gpio_status)
{
uint32_t bits = GPIO_REG_READ(GPIO_IN_ADDRESS);
uint32_t now = system_get_time();
uint32_t pin = data.pin_num;

/* Ack the interrupt */
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(pin));

uint32_t duration = now - data.last_time;
if (duration > 0xffff)
duration = 0xffff;

duration = (duration & ~1) | !(bits & BIT(pin));

data.last_time = now;

uint8_t pos = data.rawbuf_write;
uint8_t max = data.rawbuf_read;

if (max <= pos)
max += RAWBUF_SIZE;
max--;
if (pos < max) {
data.rawbuf[pos] = duration;
data.rawbuf_write = (pos + 1) & RAWBUF_MASK;
}

task_post_low(tasknumber, 0);

return gpio_status & ~BIT(pin);
}

// Lua: setup([pin])
static int lir_setup( lua_State *L )
{
if (data.setup) {
platform_gpio_unregister_intr_hook(lir_interrupt);
gpio_pin_intr_state_set(GPIO_ID_PIN(data.pin_num), GPIO_PIN_INTR_DISABLE);
platform_gpio_mode(data.pin, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_PULLUP);
data.setup = 0;
}
if (lua_gettop(L) == 0)
return 0;

data.pin = luaL_checkinteger( L, 1 );
luaL_argcheck(L, platform_gpio_exists(data.pin), 1, "Invalid pin");
data.pin_num = pin_num[data.pin];

uint32_t bits = (1 << data.pin_num);

platform_gpio_mode(data.pin, PLATFORM_GPIO_INT, PLATFORM_GPIO_FLOAT);
gpio_pin_intr_state_set(GPIO_ID_PIN(data.pin_num), GPIO_PIN_INTR_ANYEDGE);
platform_gpio_register_intr_hook(bits, lir_interrupt);

data.setup = 1;

return 0;
}

// Lua: on(event[, cb])
static int lir_on( lua_State *L )
{
static const char * const opts[] = {"raw", "rc5"};
int type = luaL_checkoption(L, 1, NULL, opts);

if (data.cb[type] != LUA_NOREF) {
luaL_unref(L, LUA_REGISTRYINDEX, data.cb[type]);
data.cb[type] = LUA_NOREF;
}

if (lua_gettop(L) < 2)
return 0;

luaL_argcheck(L, lua_type(L, 2) == LUA_TFUNCTION ||
lua_type(L, 2) == LUA_TLIGHTFUNCTION, 2, "Invalid callback");

lua_pushvalue(L, 2);
data.cb[type] = luaL_ref(L, LUA_REGISTRYINDEX);

return 0;
}

static void rc5_cb()
{
lua_State *L = lua_getstate();
lua_rawgeti(L, LUA_REGISTRYINDEX, data.cb[CB_RC5]);
lua_newtable(L);
lua_pushnumber(L, data.rc5_data);
lua_setfield(L, -2, "code");
lua_pushboolean(L, (data.rc5_data >> 11) & 1);
lua_setfield(L, -2, "toggle");
lua_pushnumber(L, (data.rc5_data >> 6) & 0x1f);
lua_setfield(L, -2, "device");
lua_pushnumber(L, data.rc5_data & 0x3f);
lua_setfield(L, -2, "command");
lua_call(L, 1, 0);
}

#define RC5_STATE_END 0x80
#define RC5_STATE_START 0x81
#define RC5_STATE_ERROR 0x82
#define RC5_SECOND 0x10

static void rc5_break()
{
data.rc5_state = RC5_STATE_START;
data.rc5_data = 0;
}

static void rc5_data(int bit)
{
NODE_DBG("rc5_state=0x%x bit=%d rc5_data=0x%x\n",
data.rc5_state, bit, data.rc5_data);

if (data.rc5_state == RC5_STATE_START) {
if (bit)
data.rc5_state = 12;
else
data.rc5_state = RC5_STATE_END;
return;
} else if (data.rc5_state & RC5_STATE_END) {
return;
}

int offset = (data.rc5_state & 0xf);

if (!(data.rc5_state & RC5_SECOND)) {
if (!bit) {
data.rc5_data |= 1 << offset;
}
if (!offset) {
rc5_cb();
}
data.rc5_state |= RC5_SECOND;
} else {
int old_bit = (data.rc5_data >> offset) & 1;
if (old_bit ^ bit)
data.rc5_state = RC5_STATE_ERROR;
else if (offset > 0)
data.rc5_state = offset - 1;
else
data.rc5_state = RC5_STATE_END;
}
}

static void lir_task(os_param_t param, uint8_t prio)
{
uint8_t pos = data.rawbuf_read;
uint8_t max = data.rawbuf_write;
if (max < pos)
max += RAWBUF_SIZE;

if (data.cb[CB_RC5] != LUA_NOREF) {
uint8_t cb5_pos = pos;
for(; cb5_pos < max; cb5_pos++) {
uint16_t v = data.rawbuf[cb5_pos & RAWBUF_MASK];
NODE_DBG("cb5_pos=%u length:%u\n",
cb5_pos, v);
if (v > 2000) {
rc5_break();
} else if (v > 1000) {
rc5_data(!(v & 1));
rc5_data(!(v & 1));
} else {
rc5_data(!(v & 1));
}
}
}
if (data.cb[CB_RAW] != LUA_NOREF) {
lua_State *L = lua_getstate();
lua_rawgeti(L, LUA_REGISTRYINDEX, data.cb[CB_RAW]);

lua_newtable(L);
for(int i = 1; pos < max; pos++, i++) {
uint16_t v = data.rawbuf[pos & RAWBUF_MASK];
lua_pushnumber(L, v);
lua_rawseti(L, -2, i);
}

lua_call(L, 1, 0);
}
data.rawbuf_read = max & RAWBUF_MASK;
}

#ifdef NODE_DEBUG
static int lir_info( lua_State *L )
{
char buf[255];
sprintf(buf, "cb:(raw:%d,rc5:%d) last_time:%u rawbuf:(read:%u,write:%u) pin:%u setup:%u\n",
data.cb[CB_RAW], data.cb[CB_RC5], data.last_time,
data.rawbuf_read, data.rawbuf_write, data.pin, data.setup);
lua_pushfstring(L, buf);
return 1;
}
#endif

static int ir_open( lua_State *L )
{
tasknumber = task_get_id( lir_task );
data.cb[CB_RAW] = LUA_NOREF;
data.cb[CB_RC5] = LUA_NOREF;

return 0;
}

LROT_BEGIN(ir)
LROT_FUNCENTRY( setup, lir_setup )
LROT_FUNCENTRY( on, lir_on )
#ifdef NODE_DEBUG
LROT_FUNCENTRY( info, lir_info )
#endif
LROT_END( ir, NULL, 0 )

NODEMCU_MODULE(IR, "ir", ir, ir_open);

0 comments on commit feed962

Please sign in to comment.