Skip to content

Commit

Permalink
walkthrough for creating a new module for NodeMCU
Browse files Browse the repository at this point in the history
  • Loading branch information
smcl committed Mar 20, 2016
1 parent 6822116 commit cc04aaf
Show file tree
Hide file tree
Showing 4 changed files with 191 additions and 2 deletions.
1 change: 1 addition & 0 deletions app/include/lwip/app/ping.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ struct ping_resp{
uint32 bytes;
uint32 total_bytes;
uint32 total_time;
uint8 ttl;
sint8 ping_err;
};

Expand Down
1 change: 1 addition & 0 deletions app/include/user_modules.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
//#define LUA_USE_MODULES_WS2801
//#define LUA_USE_MODULES_WS2812

#define LUA_USE_MODULES_TEST

#endif /* LUA_CROSS_COMPILER */
#endif /* __USER_MODULES_H__ */
5 changes: 3 additions & 2 deletions app/lwip/app/ping.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,8 @@ ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *addr)
pingresp.resp_time = delay;
pingresp.seqno = ntohs(iecho->seqno);
pingresp.ping_err = 0;
pingmsg->ping_opt->recv_function(pingmsg->ping_opt,(void*) &pingresp);
pingresp.ttl = iphdr->_ttl;
pingmsg->ping_opt->recv_function(pingmsg, (void*) &pingresp);
}
}
seqno = iecho->seqno;
Expand Down Expand Up @@ -240,7 +241,7 @@ ping_coarse_tmr(void *arg)
} else {
uint32 delay = system_relative_time(pingmsg->ping_start);
delay /= PING_COARSE;
// ping_seq_num = 0;
ping_seq_num = 0;
if (ping_opt->sent_function == NULL){
os_printf("ping %d, timeout %d, total payload %d bytes, %d ms\n",
pingmsg->max_count, pingmsg->timeout_count, PING_DATA_SIZE*(pingmsg->max_count - pingmsg->timeout_count),delay);
Expand Down
186 changes: 186 additions & 0 deletions app/modules/test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
// test.c - simple lua for playing about with
#include "module.h"
#include "lauxlib.h"
#include "platform.h"
#include "c_stdlib.h"

#include "lwip/ip_addr.h"
#include "espconn.h"
#include "lwip/dns.h"
#include "lwip/app/ping.h"
#include "lwip/raw.h"
#include "c_stdio.h"

static lua_State *gL = NULL;
static int ping_callback_ref;
static int ping_host_count;
static ip_addr_t ping_host_ip;


// test.identity() - takes a single value, returns it
static int test_identity(lua_State *L) {
return 1;
}

// test.add(x,y) - take two values and add them
static int test_add(lua_State *L) {
double x = lua_tonumber(L, 1);
double y = lua_tonumber(L, 2);
lua_pushnumber(L, x+y);
return 1;
}

// test.add2(x,y) - take two values and add them, or take two strings and concat them
static int test_add2(lua_State *L) {
if (lua_isnumber(L, 1) && lua_isnumber(L, 2)) {
double x = lua_tonumber(L, 1);
double y = lua_tonumber(L, 2);
lua_pushnumber(L, x+y);
} else if (lua_isstring(L, 1) && lua_isstring(L, 2)) {
const char *s1 = lua_tostring(L, 1);
const char *s2 = lua_tostring(L, 2);
char *s = c_zalloc(strlen(s1) + strlen(s2));
c_sprintf(s, "%s%s", s1, s2);
lua_pushstring(L, s);
} else {
lua_pushnil(L);
}
return 1;
}


void ping_received(void *arg, void *data) {
struct ping_msg *pingmsg = (struct ping_msg*)arg;
struct ping_option *pingopt = pingmsg->ping_opt;
struct ping_resp *pingresp = (struct ping_resp*)data;

char ipaddrstr[16];
ip_addr_t source_ip;

source_ip.addr = pingopt->ip;
ipaddr_ntoa_r(&source_ip, ipaddrstr, sizeof(ipaddrstr));

// if we've registered a lua callback function, retrieve
// it from registry + call it, otherwise just print the ping
// response in a similar way to the standard iputils ping util
if (ping_callback_ref != LUA_NOREF) {
lua_rawgeti(gL, LUA_REGISTRYINDEX, ping_callback_ref);
lua_pushinteger(gL, pingresp->bytes);
lua_pushstring(gL, ipaddrstr);
lua_pushinteger(gL, pingresp->seqno);
lua_pushinteger(gL, pingresp->ttl);
lua_pushinteger(gL, pingresp->resp_time);
lua_call(gL, 5, 0);
} else {
c_printf("%d bytes from %s, icmp_seq=%d ttl=%d time=%dms\n",
pingresp->bytes,
ipaddrstr,
pingresp->seqno,
pingresp->ttl,
pingresp->resp_time);
}
}

static void ping_by_hostname(const char *name, ip_addr_t *ipaddr, void *arg) {
struct ping_option *ping_opt = (struct ping_option *)c_zalloc(sizeof(struct ping_option));

if (ipaddr->addr == IPADDR_NONE) {
c_printf("problem resolving hostname\n");
return;
}

ping_opt->count = ping_host_count;
ping_opt->ip = ipaddr->addr;
ping_opt->coarse_time = 0;
ping_opt->recv_function = &ping_received;

ping_start(ping_opt);
}

/**
* test.ping()
* Description:
* Send ICMP ping request to address, optionally call callback when response received
* Syntax:
* wifi.sta.getconfig(ssid, password) --Set STATION configuration, Auto-connect by default, Connects to any BSSID
* test.ping(address) -- send 4 ping requests to target address
* test.ping(address, n) -- send n ping requests to target address
* test.ping(address, n, callback) -- send n ping requests to target address
* Parameters:
* address: string
* n: number of requests to send
* callback:
* Returns:
* Nothing.
*
* Example:
* test.ping("192.168.0.1") -- send 4 pings to 192.168.0.1
* test.ping("192.168.0.1", 10) -- send 10 pings to 192.168.0.1
* test.ping("192.168.0.1", 10, got_ping) -- send 10 pings to 192.168.0.1, call got_ping() with the
* -- ping results
*/
static int test_ping(lua_State *L)
{
const char *ping_target;
unsigned count = 4;

// retrieve address arg (mandatory)
if (lua_isstring(L, 1)) {
ping_target = luaL_checkstring(L, 1);
} else {
return luaL_error(L, "no address specified");
}

// retrieve count arg (optional)
if (lua_isnumber(L, 2)) {
count = luaL_checkinteger(L, 2);
}

// retrieve callback arg (optional)
if (ping_callback_ref != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, ping_callback_ref);
ping_callback_ref = LUA_NOREF;

if (lua_type(L, 3) == LUA_TFUNCTION || lua_type(L, 3) == LUA_TLIGHTFUNCTION)
ping_callback_ref = luaL_ref(L, LUA_REGISTRYINDEX);

gL = L; // global L

// attempt to parse ping target as IP
uint32 ip = ipaddr_addr(ping_target);

if (ip != IPADDR_NONE) {
struct ping_option *ping_opt = (struct ping_option *)c_zalloc(sizeof(struct ping_option));

ping_opt->count = count;
ping_opt->ip = ip;
ping_opt->coarse_time = 0;
ping_opt->recv_function = &ping_received;

ping_start(ping_opt);
} else {
ping_host_count = count;

struct espconn *ping_dns_lookup;
espconn_create(ping_dns_lookup);
espconn_gethostbyname(ping_dns_lookup, ping_target, &ping_host_ip, ping_by_hostname);
}

return 0;
}

// Module function map
static const LUA_REG_TYPE test_map[] = {
{ LSTRKEY( "identity" ), LFUNCVAL( test_identity ) },
{ LSTRKEY( "add" ), LFUNCVAL( test_add ) },
{ LSTRKEY( "add2" ), LFUNCVAL( test_add2 ) },
{ LSTRKEY( "ping" ), LFUNCVAL( test_ping ) },
{ LSTRKEY( "__metatable" ), LROVAL( test_map ) },
{ LNILKEY, LNILVAL }
};

int luaopen_test(lua_State *L ) {
return 0;
}

NODEMCU_MODULE(TEST, "test", test_map, luaopen_test);

0 comments on commit cc04aaf

Please sign in to comment.