Skip to content

Commit feed962

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

File tree

2 files changed

+249
-0
lines changed

2 files changed

+249
-0
lines changed

app/include/user_modules.h

Lines changed: 1 addition & 0 deletions
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

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

0 commit comments

Comments
 (0)