diff --git a/app/include/lwip/app/ping.h b/app/include/lwip/app/ping.h index 21e26e9101..161b7aba6b 100644 --- a/app/include/lwip/app/ping.h +++ b/app/include/lwip/app/ping.h @@ -75,6 +75,7 @@ struct ping_resp{ uint32 bytes; uint32 total_bytes; uint32 total_time; + uint8 ttl; sint8 ping_err; }; diff --git a/app/include/user_modules.h b/app/include/user_modules.h index 0b28dbe757..c3d7affa0d 100644 --- a/app/include/user_modules.h +++ b/app/include/user_modules.h @@ -38,6 +38,7 @@ //#define LUA_USE_MODULES_MDNS #define LUA_USE_MODULES_MQTT #define LUA_USE_MODULES_NET +#define LUA_USE_MODULES_NET_INFO #define LUA_USE_MODULES_NODE #define LUA_USE_MODULES_OW //#define LUA_USE_MODULES_PCM diff --git a/app/lwip/app/ping.c b/app/lwip/app/ping.c index 38045c5b69..25ac72c5b5 100644 --- a/app/lwip/app/ping.c +++ b/app/lwip/app/ping.c @@ -165,6 +165,7 @@ ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *addr) pingresp.seqno = ntohs(iecho->seqno); pingresp.ping_err = 0; pingmsg->ping_opt->recv_function(pingmsg->ping_opt,(void*) &pingresp); + pingresp.ttl = iphdr->_ttl; } } seqno = iecho->seqno; diff --git a/app/modules/hx711.c b/app/modules/hx711.c index cd871504c4..a517a288d2 100644 --- a/app/modules/hx711.c +++ b/app/modules/hx711.c @@ -8,6 +8,7 @@ #include #include #include "user_interface.h" +#include "task/task.h" static uint8_t data_pin; static uint8_t clk_pin; // The fields below are after the pin_num conversion diff --git a/app/modules/net_info.c b/app/modules/net_info.c new file mode 100644 index 0000000000..18442eb7e7 --- /dev/null +++ b/app/modules/net_info.c @@ -0,0 +1,228 @@ +// *************************************************************************** +// net_info module for ESP8266 with nodeMCU +// +// adopted jan 2017 for commit to nodeMCU by Wolfgang Rosner +// re-worked by Lukas Voborsky, @voborsky +// *************************************************************************** + +/** + * 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 + */ + +#define NODE_DEBUG + +#include "module.h" +#include "lauxlib.h" +#include "platform.h" + +// #include +// #include +// #include +// #include +#include "mem.h" +#include "task/task.h" + +#include "lwip/ip_addr.h" +#include "espconn.h" +#include "lwip/dns.h" +#include "lwip/app/ping.h" +#include "lwip/raw.h" + +typedef struct { + struct ping_option ping_opt; // ping_opt needs to be the first element of the structure + sint32_t ping_callback_ref; + sint32_t self_ref; /* Reference to this structure as userdata */ + uint8_t ping_host_count; + ip_addr_t ping_host_ip; + } net_info_ping_t; +typedef net_info_ping_t* ping_t; + +static ping_t nip_get( lua_State *L, int stack ) { + ping_t nip = (ping_t)luaL_checkudata(L, stack, "net_info.ping"); + if (nip == NULL) + return (ping_t)luaL_error(L, "ping object expected"); + return nip; +} + +void ping_received(void *arg, void *data) { + NODE_DBG("[ping_received] "); + // struct ping_option *pingopt = (struct ping_option*)arg; + ping_t nip = (ping_t)arg; + struct ping_resp *pingresp = (struct ping_resp*)data; + + char ipaddrstr[16]; + ip_addr_t source_ip; + + source_ip.addr = nip->ping_opt.ip; + ipaddr_ntoa_r(&source_ip, ipaddrstr, sizeof(ipaddrstr)); + + if (nip->ping_callback_ref != LUA_NOREF) { + lua_State *L = lua_getstate(); + lua_rawgeti(L, LUA_REGISTRYINDEX, nip->ping_callback_ref); + lua_pushinteger(L, pingresp->bytes); + lua_pushstring(L, ipaddrstr); + lua_pushinteger(L, pingresp->seqno); + lua_pushinteger(L, pingresp->ttl); + lua_pushinteger(L, pingresp->resp_time); + lua_call(L, 5, 0); + } +} + +// static void ping_by_hostname(const char *name, ip_addr_t *ipaddr, void *arg) { + // if (!ping_opt) { + // ping_opt = (struct ping_option *)os_zalloc(sizeof(struct ping_option)); + // } else { + // os_memset (ping_opt, 0, sizeof(struct ping_option)); + // } + + // if (ipaddr == NULL) { + // lua_State *L = lua_getstate(); + // luaL_error(L, "SEVERE problem resolving hostname - network and DNS accessible?\n"); + // return; + // } + // if (ipaddr->addr == IPADDR_NONE) { + // lua_State *L = lua_getstate(); + // luaL_error(L, "problem resolving hostname - maybe nonexistent host?\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); +// } + +// struct ping_option{ + // uint32 count; + // uint32 ip; + // uint32 coarse_time; + // ping_recv_function recv_function; + // ping_sent_function sent_function; + // void* reverse; + // struct ping_msg *parent_msg; +// }; + +static int net_info_ping(lua_State *L) +{ + NODE_DBG("[net_info_ping]"); + ping_t nip = nip_get(L, 1); + + if (nip->self_ref != LUA_REFNIL) { + luaL_unref(L, LUA_REGISTRYINDEX, nip->self_ref); + nip->self_ref = LUA_NOREF; + } + + const char *ping_target; + unsigned count = 4; + + // retrieve address arg (mandatory) + if (lua_isstring(L, 2)) { + ping_target = luaL_checkstring(L, 1); + } else { + return luaL_error(L, "no address specified"); + } + + // retrieve count arg (optional) + if (lua_isnumber(L, 3)) { + count = luaL_checkinteger(L, 2); + } + + // retrieve callback arg (optional) + if (nip->ping_callback_ref != LUA_NOREF) + luaL_unref(L, LUA_REGISTRYINDEX, nip->ping_callback_ref); + nip->ping_callback_ref = LUA_NOREF; + + if (lua_type(L, 4) == LUA_TFUNCTION || lua_type(L, 4) == LUA_TLIGHTFUNCTION) + nip->ping_callback_ref = luaL_ref(L, LUA_REGISTRYINDEX); + + // attempt to parse ping target as IP + uint32 ip = ipaddr_addr(ping_target); + + if (ip != IPADDR_NONE) { + nip->ping_opt.count = count; + nip->ping_opt.ip = ip; + nip->ping_opt.coarse_time = 0; + nip->ping_opt.recv_function = &ping_received; + + NODE_DBG("[net_info_ping] calling ping_start"); + ping_start(&(nip->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; +} + + +static int net_info_create( lua_State *L ) { + NODE_DBG("[net_info_create]"); + ping_t nip = (ping_t)lua_newuserdata(L, sizeof(net_info_ping_t)); + if (!nip) return luaL_error(L, "not enough memory"); + luaL_getmetatable(L, "net_info.ping"); + lua_setmetatable(L, -2); + nip->ping_callback_ref = LUA_NOREF; + nip->self_ref = LUA_NOREF; + return 1; +} + +static int net_info_unregister(lua_State* L){ + NODE_DBG("[net_info_unregister]"); + ping_t nip = nip_get(L, 1); + + if (nip->self_ref != LUA_REFNIL) { + luaL_unref(L, LUA_REGISTRYINDEX, nip->self_ref); + nip->self_ref = LUA_NOREF; + } + + if(nip->ping_callback_ref != LUA_NOREF) + luaL_unref(L, LUA_REGISTRYINDEX, nip->ping_callback_ref); + nip->ping_callback_ref = LUA_NOREF; + return 0; +} + + +// Module function map +LROT_BEGIN(net_info_dyn) + LROT_FUNCENTRY( ping, net_info_ping ) + LROT_FUNCENTRY( __gc, net_info_unregister ) + LROT_TABENTRY( __index, net_info_dyn ) +LROT_END( net_info_dyn, net_info_dyn, LROT_MASK_GC_INDEX ) + + +LROT_BEGIN(net_info) + LROT_FUNCENTRY( create, net_info_create ) +LROT_END( net_ifo, NULL, 0 ) + +int luaopen_net_info( lua_State *L ){ + NODE_DBG("[luaopen_net_info]"); + luaL_rometatable(L, "net_info.ping", LROT_TABLEREF(net_info)); + return 0; +} + +NODEMCU_MODULE(NET_INFO, "net_info", net_info, NULL); diff --git a/docs/modules/net_info.md b/docs/modules/net_info.md new file mode 100644 index 0000000000..d095dcc446 --- /dev/null +++ b/docs/modules/net_info.md @@ -0,0 +1,79 @@ +# net_info Module +| Since | Origin / Contributor | Maintainer | Source | +| :----- | :-------------------- | :---------- | :------ | +| 2017-01-21 | [smcl](http://blog.mclemon.io/esp8266-contributing-to-the-nodemcu-ecosystem) | [wolfgangr](https://github.com/wolfgangr/nodemcu-firmware) | [net_info.c](../../../app/modules/net_info.c) + + +This module is a stub to collect common network diagnostic and analysis tools. + +##net_info.ping() + send ICMP ECHO_REQUEST to network hosts + +**Synopsis:**: +``` +net_info.ping(host [, count [, callback]]) +``` + +**Usage example:** +``` +=net_info.ping("www.google.de",2) +> 32 bytes from 172.217.20.195, icmp_seq=25 ttl=53 time=37ms +32 bytes from 172.217.20.195, icmp_seq=26 ttl=53 time=38ms +ping 2, timeout 0, total payload 64 bytes, 1946 ms +``` + + +**Description:** (from *linux man 8 ping*) + +> `ping` uses the ICMP protocol's mandatory ECHO_REQUEST datagram to elicit an ICMP ECHO_RESPONSE from a host or gateway. ECHO_REQUEST datagrams (''pings'') have an IP and ICMP header, followed by a struct timeval and then an arbitrary number of ''pad'' bytes used to fill out the packet. + + +**Usage variants** + +ping host **by IP-Adress:** +``` +net_info.ping("1.2.3.4") +``` +Enter IP-Adress in commonly known dotted quad-decimal notation, enclosed in string quotes. + +!!! Note + There is only limited error checking on the validity of IP adresses in lwIP. Check twice! + + +Use **DNS resolver** to get IP adress for ping: +``` +net_info.ping("hostname") +``` + +!!! Note + This only works with Network access and DNS resolution properly configured. + + +Custom **ping count**: +``` +net_info.ping(host, count) +``` +* `host` can be given by IP or hostname as above. +* `count` number of repetitive pings - default is 4 if omitted. + + +Ping **callback function**: +``` +net_info.ping(host, count, callback) +``` +Instead of printing ping results on the console, the given callback function ist called each time a ECHO_RESPONSE is received. + +The callback receives the following arguments: +``` +function ping_recv(bytes, ipaddr, seqno, ttl, ping) +``` +* length of message +* ip-address of pinged host +* icmp_seq number +* time-to-live-value +* ping time in ms + +!!! Caution + The callback functionality is still untested. Use at even more your own risk! + +For further reference to callback functionality, see smcl origin link provided on top of this page. \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 4d704d1751..fc5dc2a934 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -83,6 +83,7 @@ pages: - 'mdns': 'modules/mdns.md' - 'mqtt': 'modules/mqtt.md' - 'net': 'modules/net.md' + - 'net_info': 'modules/net_info.md' - 'node': 'modules/node.md' - 'ow (1-Wire)': 'modules/ow.md' - 'pcm' : 'modules/pcm.md'