Skip to content

Commit b2175a2

Browse files
committed
Add IR module
1 parent 88a33af commit b2175a2

File tree

2 files changed

+270
-0
lines changed

2 files changed

+270
-0
lines changed

app/include/user_modules.h

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
//#define LUA_USE_MODULES_HTTP
3535
//#define LUA_USE_MODULES_HX711
3636
#define LUA_USE_MODULES_I2C
37+
//#define LUA_USE_MODULES_IR
3738
//#define LUA_USE_MODULES_L3G4200D
3839
//#define LUA_USE_MODULES_MCP4725
3940
//#define LUA_USE_MODULES_MDNS

app/modules/ir.c

+269
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
//#define NODE_DEBUG
2+
3+
#include <stdint.h>
4+
#include <string.h>
5+
6+
#include "module.h"
7+
#include "lauxlib.h"
8+
#include "task/task.h"
9+
10+
#include "gpio.h"
11+
#include "hw_timer.h"
12+
#include "lmem.h"
13+
#include "platform.h"
14+
#include "user_interface.h"
15+
16+
/* Must be a power of 2 (max 128 without changing types) */
17+
#define RAWBUF_SIZE 128
18+
#define RAWBUF_MASK (RAWBUF_SIZE - 1)
19+
20+
#define CB_RAW 0
21+
#define CB_RC5 1
22+
23+
static task_handle_t tasknumber;
24+
static ETSTimer timer;
25+
26+
static struct ir_device {
27+
int cb[2];
28+
uint32_t last_time;
29+
int16_t rawbuf[RAWBUF_SIZE];
30+
uint16_t rc5_data;
31+
uint8_t rc5_state;
32+
uint8_t rawbuf_read;
33+
uint8_t rawbuf_write;
34+
uint8_t pin, pin_num;
35+
} *the_ir_device;
36+
37+
#define abs(x) ((x > 0) ? (x) : -(x))
38+
39+
static uint32_t ICACHE_RAM_ATTR lir_interrupt(uint32_t gpio_status)
40+
{
41+
struct ir_device *dev = the_ir_device;
42+
if (!dev)
43+
return gpio_status;
44+
uint32_t bits = GPIO_REG_READ(GPIO_IN_ADDRESS);
45+
uint32_t now = system_get_time();
46+
uint32_t pin = dev->pin_num;
47+
48+
/* Ack the interrupt */
49+
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(pin));
50+
51+
int32_t duration = now - dev->last_time;
52+
if (duration > 0x7fff || duration < 0)
53+
duration = 0x7fff;
54+
55+
/* Sign of duration is used to encode HIGH/LOW */
56+
if (bits & BIT(pin))
57+
duration = -duration;
58+
59+
dev->last_time = now;
60+
61+
uint8_t pos = dev->rawbuf_write;
62+
uint8_t max = dev->rawbuf_read;
63+
64+
if (max <= pos)
65+
max += RAWBUF_SIZE;
66+
max--;
67+
if (pos < max) {
68+
dev->rawbuf[pos] = duration;
69+
dev->rawbuf_write = (pos + 1) & RAWBUF_MASK;
70+
}
71+
72+
task_post_low(tasknumber, 0);
73+
74+
return gpio_status & ~BIT(pin);
75+
}
76+
77+
// Lua: setup([pin])
78+
static int lir_setup( lua_State *L )
79+
{
80+
if (the_ir_device)
81+
return luaL_error(L, "No support for multiple IR devices");
82+
83+
if (lua_gettop(L) == 0)
84+
return 0;
85+
86+
int pin = luaL_checkinteger( L, 1 );
87+
luaL_argcheck(L, platform_gpio_exists(pin), 1, "Invalid pin");
88+
89+
struct ir_device *dev = lua_newuserdata(L, sizeof(*dev));
90+
memset(dev, 0, sizeof(*dev));
91+
dev->cb[CB_RAW] = LUA_NOREF;
92+
dev->cb[CB_RC5] = LUA_NOREF;
93+
luaL_getmetatable(L, "ir.device");
94+
lua_setmetatable(L, -2);
95+
96+
the_ir_device = dev;
97+
98+
dev->pin = pin;
99+
dev->pin_num = pin_num[pin];
100+
101+
uint32_t bits = (1 << dev->pin_num);
102+
103+
platform_gpio_mode(dev->pin, PLATFORM_GPIO_INT, PLATFORM_GPIO_FLOAT);
104+
gpio_pin_intr_state_set(GPIO_ID_PIN(dev->pin_num), GPIO_PIN_INTR_ANYEDGE);
105+
platform_gpio_register_intr_hook(bits, lir_interrupt);
106+
107+
return 1;
108+
}
109+
110+
// Lua: on(event[, cb])
111+
static int lir_on( lua_State *L )
112+
{
113+
struct ir_device *dev = luaL_checkudata(L, 1, "ir.device");
114+
luaL_argcheck(L, dev, 1, "ir.device expected");
115+
static const char * const opts[] = {"raw", "rc5"};
116+
int type = luaL_checkoption(L, 2, NULL, opts);
117+
118+
if (dev->cb[type] != LUA_NOREF) {
119+
luaL_unref(L, LUA_REGISTRYINDEX, dev->cb[type]);
120+
dev->cb[type] = LUA_NOREF;
121+
}
122+
123+
if (lua_gettop(L) < 3)
124+
return 0;
125+
126+
luaL_argcheck(L, lua_type(L, 3) == LUA_TFUNCTION ||
127+
lua_type(L, 3) == LUA_TLIGHTFUNCTION, 3, "Invalid callback");
128+
129+
lua_pushvalue(L, 3);
130+
dev->cb[type] = luaL_ref(L, LUA_REGISTRYINDEX);
131+
132+
return 0;
133+
}
134+
135+
static void rc5_cb(struct ir_device *dev)
136+
{
137+
lua_State *L = lua_getstate();
138+
lua_rawgeti(L, LUA_REGISTRYINDEX, dev->cb[CB_RC5]);
139+
lua_newtable(L);
140+
lua_pushnumber(L, dev->rc5_data);
141+
lua_setfield(L, -2, "code");
142+
lua_pushboolean(L, (dev->rc5_data >> 11) & 1);
143+
lua_setfield(L, -2, "toggle");
144+
lua_pushnumber(L, (dev->rc5_data >> 6) & 0x1f);
145+
lua_setfield(L, -2, "device");
146+
lua_pushnumber(L, dev->rc5_data & 0x3f);
147+
lua_setfield(L, -2, "command");
148+
lua_call(L, 1, 0);
149+
}
150+
151+
#define RC5_STATE_END 0x80
152+
#define RC5_STATE_START 0x81
153+
#define RC5_STATE_ERROR 0x82
154+
#define RC5_SECOND 0x10
155+
156+
static void rc5_break(struct ir_device *dev)
157+
{
158+
dev->rc5_state = RC5_STATE_START;
159+
dev->rc5_data = 0;
160+
}
161+
162+
static void rc5_data(struct ir_device *dev, int bit)
163+
{
164+
NODE_DBG("rc5_state=0x%x bit=%d rc5_data=0x%x\n",
165+
dev->rc5_state, bit, dev->rc5_data);
166+
167+
if (dev->rc5_state == RC5_STATE_START) {
168+
if (bit)
169+
dev->rc5_state = 12;
170+
else
171+
dev->rc5_state = RC5_STATE_END;
172+
return;
173+
} else if (dev->rc5_state & RC5_STATE_END) {
174+
return;
175+
}
176+
177+
int offset = (dev->rc5_state & 0xf);
178+
179+
if (!(dev->rc5_state & RC5_SECOND)) {
180+
if (!bit)
181+
dev->rc5_data |= 1 << offset;
182+
if (!offset)
183+
rc5_cb(dev);
184+
dev->rc5_state |= RC5_SECOND;
185+
} else {
186+
int old_bit = (dev->rc5_data >> offset) & 1;
187+
if (old_bit ^ bit)
188+
dev->rc5_state = RC5_STATE_ERROR;
189+
else if (offset > 0)
190+
dev->rc5_state = offset - 1;
191+
else
192+
dev->rc5_state = RC5_STATE_END;
193+
}
194+
}
195+
196+
static void lir_task(os_param_t param, uint8_t prio)
197+
{
198+
struct ir_device *dev = the_ir_device;
199+
if (!dev)
200+
return;
201+
uint8_t pos = dev->rawbuf_read;
202+
uint8_t max = dev->rawbuf_write;
203+
if (max < pos)
204+
max += RAWBUF_SIZE;
205+
206+
if (dev->cb[CB_RC5] != LUA_NOREF) {
207+
uint8_t cb5_pos = pos;
208+
for(; cb5_pos < max; cb5_pos++) {
209+
int16_t v = dev->rawbuf[cb5_pos & RAWBUF_MASK];
210+
NODE_DBG("cb5_pos=%u length:%d\n",
211+
cb5_pos, v);
212+
if (abs(v) > 2000) {
213+
rc5_break(dev);
214+
} else if (abs(v) > 1000) {
215+
rc5_data(dev, v < 0);
216+
rc5_data(dev, v < 0);
217+
} else {
218+
rc5_data(dev, v < 0);
219+
}
220+
}
221+
}
222+
if (dev->cb[CB_RAW] != LUA_NOREF) {
223+
lua_State *L = lua_getstate();
224+
lua_rawgeti(L, LUA_REGISTRYINDEX, dev->cb[CB_RAW]);
225+
226+
lua_newtable(L);
227+
for(int i = 1; pos < max; pos++, i++) {
228+
int16_t v = dev->rawbuf[pos & RAWBUF_MASK];
229+
lua_pushnumber(L, v);
230+
lua_rawseti(L, -2, i);
231+
}
232+
233+
lua_call(L, 1, 0);
234+
}
235+
dev->rawbuf_read = max & RAWBUF_MASK;
236+
}
237+
238+
static int lir_gc(lua_State *L)
239+
{
240+
struct ir_device *dev = luaL_checkudata(L, 1, "ir.device");
241+
luaL_argcheck(L, dev, 1, "ir.device expected");
242+
243+
platform_gpio_unregister_intr_hook(lir_interrupt);
244+
gpio_pin_intr_state_set(GPIO_ID_PIN(dev->pin_num), GPIO_PIN_INTR_DISABLE);
245+
platform_gpio_mode(dev->pin, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_PULLUP);
246+
247+
the_ir_device = NULL;
248+
}
249+
250+
LROT_BEGIN( ir_device, NULL, LROT_MASK_GC_INDEX )
251+
LROT_FUNCENTRY( __gc, lir_gc )
252+
LROT_TABENTRY( __index, ir_device )
253+
LROT_FUNCENTRY( on, lir_on )
254+
LROT_END( ir_device, NULL, LROT_MASK_GC_INDEX )
255+
256+
static int ir_open( lua_State *L )
257+
{
258+
tasknumber = task_get_id( lir_task );
259+
260+
luaL_rometatable(L, "ir.device", LROT_TABLEREF(ir_device));
261+
262+
return 0;
263+
}
264+
265+
LROT_BEGIN( ir, NULL, 0 )
266+
LROT_FUNCENTRY( setup, lir_setup )
267+
LROT_END( ir, NULL, 0 )
268+
269+
NODEMCU_MODULE(IR, "ir", ir, ir_open);

0 commit comments

Comments
 (0)