Commit 4911d2db authored by Arnim Läuger's avatar Arnim Läuger
Browse files

Merge pull request #1336 from nodemcu/dev

1.5.1 master drop
parents c8037568 2e109686
......@@ -820,6 +820,31 @@ static void lu8g_digital_write( u8g_t *u8g, uint8_t pin_index, uint8_t value )
platform_gpio_write( pin, value );
}
void u8g_Delay(u8g_t *u8g, uint16_t msec)
{
const uint16_t chunk = 50;
if (u8g->use_delay == 0)
return;
while (msec > chunk)
{
os_delay_us( chunk*1000 );
msec -= chunk;
}
if (msec > 0)
os_delay_us( msec*1000 );
}
void u8g_MicroDelay(void)
{
os_delay_us( 1 );
}
void u8g_10MicroDelay(void)
{
os_delay_us( 10 );
}
uint8_t u8g_com_esp8266_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
{
switch(msg)
......@@ -972,6 +997,7 @@ static int lu8g_close_display( lua_State *L )
static int lu8g_ ## device( lua_State *L ) \
{ \
unsigned addr = luaL_checkinteger( L, 1 ); \
unsigned del = luaL_optinteger( L, 2, 0 ); \
\
if (addr == 0) \
return luaL_error( L, "i2c address required" ); \
......@@ -979,6 +1005,7 @@ static int lu8g_close_display( lua_State *L )
lu8g_userdata_t *lud = (lu8g_userdata_t *) lua_newuserdata( L, sizeof( lu8g_userdata_t ) ); \
\
lud->u8g.i2c_addr = (uint8_t)addr; \
lud->u8g.use_delay = del > 0 ? 1 : 0; \
\
u8g_InitI2C( LU8G, &u8g_dev_ ## device, U8G_I2C_OPT_NONE); \
\
......@@ -1006,9 +1033,12 @@ U8G_DISPLAY_TABLE_I2C
if (dc == 0) \
return luaL_error( L, "D/C pin required" ); \
unsigned res = luaL_optinteger( L, 3, U8G_PIN_NONE ); \
unsigned del = luaL_optinteger( L, 4, 0 ); \
\
lu8g_userdata_t *lud = (lu8g_userdata_t *) lua_newuserdata( L, sizeof( lu8g_userdata_t ) ); \
\
lud->u8g.use_delay = del > 0 ? 1 : 0; \
\
u8g_InitHWSPI( LU8G, &u8g_dev_ ## device, cs, dc, res ); \
\
/* set its metatable */ \
......
......@@ -6,6 +6,7 @@
#include "c_types.h"
#include "c_string.h"
#include "rom.h"
static lua_State *gL = NULL;
static int uart_receive_rf = LUA_NOREF;
......
......@@ -6,33 +6,33 @@
#include "c_string.h"
#include "c_stdlib.h"
#include "ctype.h"
#include "c_types.h"
#include "user_interface.h"
#include "wifi_common.h"
#ifdef WIFI_SMART_ENABLE
#include "smart.h"
#include "smartconfig.h"
static int wifi_smart_succeed = LUA_NOREF;
#endif
static uint8 getap_output_format=0;
#define INVALID_MAC_STR "MAC:FF:FF:FF:FF:FF:FF"
//wifi.sleep variables
#define FPM_SLEEP_MAX_TIME 0xFFFFFFF
static bool FLAG_wifi_force_sleep_enabled=0;
//variables for wifi event monitor
static sint32_t wifi_status_cb_ref[6] = {LUA_NOREF,LUA_NOREF,LUA_NOREF,LUA_NOREF,LUA_NOREF,LUA_NOREF};
static volatile os_timer_t wifi_sta_status_timer;
static uint8 prev_wifi_status=0;
#if defined( NODE_SMART_OLDSTYLE )
#else
static lua_State* smart_L = NULL;
#endif
#ifdef WIFI_SMART_ENABLE
static void wifi_smart_succeed_cb(sc_status status, void *pdata){
NODE_DBG("wifi_smart_succeed_cb is called.\n");
lua_State* L = lua_getstate();
if (status == SC_STATUS_LINK_OVER)
{
smartconfig_stop();
......@@ -62,21 +62,20 @@ static void wifi_smart_succeed_cb(sc_status status, void *pdata){
if(wifi_smart_succeed != LUA_NOREF)
{
lua_rawgeti(smart_L, LUA_REGISTRYINDEX, wifi_smart_succeed);
lua_rawgeti(L, LUA_REGISTRYINDEX, wifi_smart_succeed);
lua_pushstring(smart_L, sta_conf->ssid);
lua_pushstring(smart_L, sta_conf->password);
lua_call(smart_L, 2, 0);
lua_pushstring(L, sta_conf->ssid);
lua_pushstring(L, sta_conf->password);
lua_call(L, 2, 0);
luaL_unref(smart_L, LUA_REGISTRYINDEX, wifi_smart_succeed);
wifi_smart_succeed = LUA_NOREF;
unregister_lua_cb(L, &wifi_smart_succeed);
}
#endif // defined( NODE_SMART_OLDSTYLE )
}
#endif // WIFI_SMART_ENABLE
static int wifi_scan_succeed = LUA_NOREF;
static lua_State* gL = NULL;
/**
* @brief Wifi ap scan over callback to display.
* @param arg: contain the aps information
......@@ -85,20 +84,20 @@ static lua_State* gL = NULL;
*/
static void wifi_scan_done(void *arg, STATUS status)
{
lua_State* L = lua_getstate();
uint8 ssid[33];
char temp[128];
char temp[sizeof("11:22:33:44:55:66")];
if(wifi_scan_succeed == LUA_NOREF)
return;
if(arg == NULL)
return;
lua_rawgeti(gL, LUA_REGISTRYINDEX, wifi_scan_succeed);
lua_rawgeti(L, LUA_REGISTRYINDEX, wifi_scan_succeed);
if (status == OK)
{
struct bss_info *bss_link = (struct bss_info *)arg;
bss_link = bss_link->next.stqe_next;//ignore first
lua_newtable( gL );
lua_newtable( L );
while (bss_link != NULL)
{
......@@ -113,18 +112,16 @@ static void wifi_scan_done(void *arg, STATUS status)
}
if(getap_output_format==1) //use new format(BSSID : SSID, RSSI, Authmode, Channel)
{
c_sprintf(temp,"%s,%d,%d,%d", ssid, bss_link->rssi, bss_link->authmode, bss_link->channel);
lua_pushstring(gL, temp);
NODE_DBG(MACSTR" : %s\n",MAC2STR(bss_link->bssid) , temp);
c_sprintf(temp,MACSTR, MAC2STR(bss_link->bssid));
lua_setfield( gL, -2, temp);
wifi_add_sprintf_field(L, temp, "%s,%d,%d,%d",
ssid, bss_link->rssi, bss_link->authmode, bss_link->channel);
NODE_DBG(MACSTR" : %s\n",MAC2STR(bss_link->bssid) , temp);//00 00 00 00 00 00
}
else//use old format(SSID : Authmode, RSSI, BSSID, Channel)
{
c_sprintf(temp,"%d,%d,"MACSTR",%d", bss_link->authmode, bss_link->rssi, MAC2STR(bss_link->bssid),bss_link->channel);
lua_pushstring(gL, temp);
lua_setfield( gL, -2, ssid );
NODE_DBG("%s : %s\n", ssid, temp);
wifi_add_sprintf_field(L, ssid, "%d,%d,"MACSTR",%d",
bss_link->authmode, bss_link->rssi, MAC2STR(bss_link->bssid),bss_link->channel);
NODE_DBG("%s : %s\n", ssid, temp);
}
bss_link = bss_link->next.stqe_next;
......@@ -132,16 +129,13 @@ static void wifi_scan_done(void *arg, STATUS status)
}
else
{
lua_newtable( gL );
}
lua_call(gL, 1, 0);
if(wifi_scan_succeed != LUA_NOREF)
{
luaL_unref(gL, LUA_REGISTRYINDEX, wifi_scan_succeed);
wifi_scan_succeed = LUA_NOREF;
lua_newtable( L );
}
lua_call(L, 1, 0);
unregister_lua_cb(L, &wifi_scan_succeed);
}
#ifdef WIFI_SMART_ENABLE
// Lua: smart(channel, function succeed_cb)
// Lua: smart(type, function succeed_cb)
static int wifi_start_smart( lua_State* L )
......@@ -184,7 +178,6 @@ static int wifi_start_smart( lua_State* L )
}
uint8_t smart_type = 0;
int stack = 1;
smart_L = L;
if ( lua_isnumber(L, stack) )
{
smart_type = lua_tointeger(L, stack);
......@@ -194,9 +187,7 @@ static int wifi_start_smart( lua_State* L )
if (lua_type(L, stack) == LUA_TFUNCTION || lua_type(L, stack) == LUA_TLIGHTFUNCTION)
{
lua_pushvalue(L, stack); // copy argument (func) to the top of stack
if(wifi_smart_succeed != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, wifi_smart_succeed);
wifi_smart_succeed = luaL_ref(L, LUA_REGISTRYINDEX);
register_lua_cb(L, &wifi_smart_succeed);
}
if ( smart_type > 1 )
......@@ -219,11 +210,10 @@ static int wifi_exit_smart( lua_State* L )
smartconfig_stop();
#endif // defined( NODE_SMART_OLDSTYLE )
if(wifi_smart_succeed != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, wifi_smart_succeed);
wifi_smart_succeed = LUA_NOREF;
unregister_lua_cb(L, &wifi_smart_succeed);
return 0;
}
#endif // WIFI_SMART_ENABLE
// Lua: realmode = setmode(mode)
static int wifi_setmode( lua_State* L )
......@@ -232,7 +222,7 @@ static int wifi_setmode( lua_State* L )
mode = luaL_checkinteger( L, 1 );
if ( mode != STATION_MODE && mode != SOFTAP_MODE && mode != STATIONAP_MODE )
if ( mode != STATION_MODE && mode != SOFTAP_MODE && mode != STATIONAP_MODE && mode != NULL_MODE )
return luaL_error( L, "wrong arg type" );
wifi_set_opmode( (uint8_t)mode);
mode = (unsigned)wifi_get_opmode();
......@@ -399,9 +389,7 @@ static int wifi_setmac( lua_State* L, uint8_t mode )
uint8_t mac[6];
unsigned len = 0;
const char *macaddr = luaL_checklstring( L, 1, &len );
if(len!=17)
return luaL_error( L, "wrong arg type" );
luaL_argcheck(L, len==17, 1, INVALID_MAC_STR);
ets_str2macaddr(mac, macaddr);
lua_pushboolean(L,wifi_set_macaddr(mode, (uint8 *)mac));
return 1;
......@@ -624,7 +612,7 @@ static int wifi_station_config( lua_State* L )
if (sl>32 || ssid == NULL)
return luaL_error( L, "ssid:<32" );
const char *password = luaL_checklstring( L, 2, &pl );
if (pl!=0 && (pl<8 || pl>64) || password == NULL)
if ((pl!=0 && (pl<8 || pl>64)) || password == NULL)
return luaL_error( L, "pwd:0,8~64" );
if(lua_isnumber(L, 3))
......@@ -657,8 +645,7 @@ static int wifi_station_config( lua_State* L )
if (lua_isstring(L, 4))
{
const char *macaddr = luaL_checklstring( L, 4, &ml );
if (ml!=17)
return luaL_error( L, "MAC:FF:FF:FF:FF:FF:FF" );
luaL_argcheck(L, ml==17, 1, INVALID_MAC_STR);
c_memset(sta_conf.bssid, 0, 6);
ets_str2macaddr(sta_conf.bssid, macaddr);
sta_conf.bssid_set = 1;
......@@ -684,8 +671,8 @@ static int wifi_station_config( lua_State* L )
NODE_DBG("\n");
wifi_station_set_config(&sta_conf);
wifi_station_disconnect();
wifi_station_set_config(&sta_conf);
if(auto_connect==0)
{
......@@ -721,13 +708,8 @@ static int wifi_station_setauto( lua_State* L )
unsigned a;
a = luaL_checkinteger( L, 1 );
if ( a != 0 && a != 1 )
return luaL_error( L, "wrong arg type" );
luaL_argcheck(L, ( a == 0 || a == 1 ), 1, "0 or 1");
wifi_station_set_auto_connect(a);
if(a){
// station_check_connect(0);
}
return 0;
}
......@@ -773,7 +755,6 @@ static int wifi_station_listap( lua_State* L )
{
return luaL_error( L, "Can't list ap in SOFTAP mode" );
}
gL = L;
struct scan_config scan_cfg;
getap_output_format=0;
......@@ -809,8 +790,7 @@ static int wifi_station_listap( lua_State* L )
if( lua_isstring(L, -1) ) // deal with the ssid string
{
const char *macaddr = luaL_checklstring( L, -1, &len );
if(len!=17)
return luaL_error( L, "bssid: FF:FF:FF:FF:FF:FF" );
luaL_argcheck(L, len==17, 1, INVALID_MAC_STR);
c_memset(bssid, 0, 6);
ets_str2macaddr(bssid, macaddr);
scan_cfg.bssid=bssid;
......@@ -900,9 +880,8 @@ static int wifi_station_listap( lua_State* L )
if (lua_type(L, 3) == LUA_TFUNCTION || lua_type(L, 3) == LUA_TLIGHTFUNCTION)
{
lua_pushvalue(L, 3); // copy argument (func) to the top of stack
if(wifi_scan_succeed != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, wifi_scan_succeed);
wifi_scan_succeed = luaL_ref(L, LUA_REGISTRYINDEX);
register_lua_cb(L, &wifi_scan_succeed);
if (lua_type(L, 1)==LUA_TTABLE)
{
wifi_station_scan(&scan_cfg,wifi_scan_done);
......@@ -914,183 +893,86 @@ static int wifi_station_listap( lua_State* L )
}
else
{
if(wifi_scan_succeed != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, wifi_scan_succeed);
wifi_scan_succeed = LUA_NOREF;
unregister_lua_cb(L, &wifi_scan_succeed);
}
}
// Lua: wifi.sta.status()
static int wifi_station_status( lua_State* L )
// Lua: wifi.sta.gethostname()
static int wifi_sta_gethostname( lua_State* L )
{
uint8_t status = wifi_station_get_connect_status();
lua_pushinteger( L, status );
return 1;
char* hostname = wifi_station_get_hostname();
lua_pushstring(L, hostname);
return 1;
}
/**
* wifi.sta.eventMonStop()
* Description:
* Stop wifi station event monitor
* Syntax:
* wifi.sta.eventMonStop()
* wifi.sta.eventMonStop("unreg all")
* Parameters:
* "unreg all": unregister all previously registered functions
* Returns:
* Nothing.
*
* Example:
--stop wifi event monitor
wifi.sta.eventMonStop()
--stop wifi event monitor and unregister all callbacks
wifi.sta.eventMonStop("unreg all")
*/
static void wifi_station_event_mon_stop(lua_State* L)
static bool wifi_sta_sethostname(const char *hostname, size_t len)
{
os_timer_disarm(&wifi_sta_status_timer);
if(lua_isstring(L,1))
//this function follows RFC 952 & RFC 1123 host name standards.
//the hostname must be 32 chars or less and first and last char must be alphanumeric
if (!isalnum(hostname[0]) || !isalnum(hostname[len-1]) || len > 32)
{
return false;
}
if (c_strcmp(luaL_checkstring(L, 1), "unreg all")==0)
for (int i=1; i<len; i++)
{
//characters in the middle of the host name can be alphanumeric or a hyphen(-) only
if (!(isalnum(hostname[i]) || hostname[i]=='-'))
{
int i;
for (i=0;i<6;i++)
{
if(wifi_status_cb_ref[i] != LUA_NOREF)
{
luaL_unref(L, LUA_REGISTRYINDEX, wifi_status_cb_ref[i]);
wifi_status_cb_ref[i] = LUA_NOREF;
}
}
return false;
}
}
return wifi_station_set_hostname((char*)hostname);
}
static void wifi_status_cb(int arg)
static int wifi_sta_sethostname_lua( lua_State* L )
{
if (wifi_get_opmode()==2)
{
os_timer_disarm(&wifi_sta_status_timer);
return;
}
int wifi_status=wifi_station_get_connect_status();
if (wifi_status!=prev_wifi_status)
{
if(wifi_status_cb_ref[wifi_status]!=LUA_NOREF)
{
lua_rawgeti(gL, LUA_REGISTRYINDEX, wifi_status_cb_ref[wifi_status]);
lua_call(gL, 0, 0);
}
}
prev_wifi_status=wifi_status;
size_t len;
const char *hostname = luaL_checklstring(L, 1, &len);
luaL_argcheck(L, wifi_sta_sethostname(hostname, len), 1, "Invalid hostname");
return 0;
}
/**
* wifi.sta.eventMonReg()
* Description:
* Register callback for wifi station status event
* Syntax:
* wifi.sta.eventMonReg(wifi_status, function)
* wifi.sta.eventMonReg(wifi.status, "unreg") //unregister callback
* Parameters:
* wifi_status: wifi status you would like to set callback for
* Valid wifi states:
* wifi.STA_IDLE
* wifi.STA_CONNECTING
* wifi.STA_WRONGPWD
* wifi.STA_APNOTFOUND
* wifi.STA_FAIL
* wifi.STA_GOTIP
* function: function to perform
* "unreg": unregister previously registered function
* Returns:
* Nothing.
*
* Example:
--register callback
wifi.sta.eventMonReg(0, function() print("STATION_IDLE") end)
wifi.sta.eventMonReg(1, function() print("STATION_CONNECTING") end)
wifi.sta.eventMonReg(2, function() print("STATION_WRONG_PASSWORD") end)
wifi.sta.eventMonReg(3, function() print("STATION_NO_AP_FOUND") end)
wifi.sta.eventMonReg(4, function() print("STATION_CONNECT_FAIL") end)
wifi.sta.eventMonReg(5, function() print("STATION_GOT_IP") end)
--unregister callback
wifi.sta.eventMonReg(0, "unreg")
*/
static int wifi_station_event_mon_reg(lua_State* L)
// Lua: wifi.sta.status()
static int wifi_station_status( lua_State* L )
{
gL=L;
uint8 id=luaL_checknumber(L, 1);
if (!(id >= 0 && id <=5))
{
return luaL_error( L, "valid wifi status:0-5" );
}
uint8_t status = wifi_station_get_connect_status();
lua_pushinteger( L, status );
return 1;
}
if (lua_type(L, 2) == LUA_TFUNCTION || lua_type(L, 2) == LUA_TLIGHTFUNCTION)
// Lua: wifi.sta.getrssi()
static int wifi_station_getrssi( lua_State* L ){
sint8 rssival=wifi_station_get_rssi();
NODE_DBG("\n\tRSSI is %i\n", rssival);
if (rssival<10)
{
lua_pushvalue(L, 2); // copy argument (func) to the top of stack
if(wifi_status_cb_ref[id] != LUA_NOREF)
{
luaL_unref(L, LUA_REGISTRYINDEX, wifi_status_cb_ref[id]);
}
wifi_status_cb_ref[id] = luaL_ref(L, LUA_REGISTRYINDEX);
lua_pushinteger(L, rssival);
}
else if (c_strcmp(luaL_checkstring(L, 2), "unreg")==0)
else
{
if(wifi_status_cb_ref[id] != LUA_NOREF)
{
luaL_unref(L, LUA_REGISTRYINDEX, wifi_status_cb_ref[id]);
wifi_status_cb_ref[id] = LUA_NOREF;
}
lua_pushnil(L);
}
return 0;
return 1;
}
/**
* wifi.sta.eventMonStart()
* Description:
* Start wifi station event monitor
* Syntax:
* wifi.sta.eventMonStart()
* wifi.sta.eventMonStart(mS)
* Parameters:
* mS:interval between checks in milliseconds. defaults to 150 mS if not provided
* Returns:
* Nothing.
*
* Example:
--start wifi event monitor with default interval
wifi.sta.eventMonStart()
--start wifi event monitor with 100 mS interval
wifi.sta.eventMonStart(100)
*/
static int wifi_station_event_mon_start(lua_State* L)
//Lua: wifi.ap.deauth()
static int wifi_ap_deauth( lua_State* L )
{
if(wifi_get_opmode() == SOFTAP_MODE)
{
return luaL_error( L, "Can't monitor station in SOFTAP mode" );
}
if (wifi_status_cb_ref[0]==LUA_NOREF && wifi_status_cb_ref[1]==LUA_NOREF &&
wifi_status_cb_ref[2]==LUA_NOREF && wifi_status_cb_ref[3]==LUA_NOREF &&
wifi_status_cb_ref[4]==LUA_NOREF && wifi_status_cb_ref[5]==LUA_NOREF )
uint8_t mac[6];
unsigned len = 0;
if(lua_isstring(L, 1))
{
return luaL_error( L, "No callbacks defined" );
const char *macaddr = luaL_checklstring( L, 1, &len );
luaL_argcheck(L, len==17, 1, INVALID_MAC_STR);
ets_str2macaddr(mac, macaddr);
}
uint32 ms=150;
if(lua_isnumber(L, 1))
else
{
ms=luaL_checknumber(L, 1);
c_memset(&mac, 0xFF, sizeof(mac));
}
os_timer_disarm(&wifi_sta_status_timer);
os_timer_setfn(&wifi_sta_status_timer, (os_timer_func_t *)wifi_status_cb, NULL);
os_timer_arm(&wifi_sta_status_timer, ms, 1);
return 0;
lua_pushboolean(L,wifi_softap_deauth(mac));
return 1;
}
// Lua: wifi.ap.getmac()
......@@ -1271,12 +1153,8 @@ static int wifi_ap_listclient( lua_State* L )
struct station_info * next_station;
while (station != NULL)
{
c_sprintf(temp, IPSTR, IP2STR(&station->ip));
lua_pushstring(L, temp);
c_sprintf(temp, MACSTR, MAC2STR(station->bssid));
lua_setfield(L, -2, temp);
wifi_add_sprintf_field(L, temp, IPSTR, IP2STR(&station->ip));
next_station = STAILQ_NEXT(station, next);
c_free(station);
station = next_station;
......@@ -1349,10 +1227,15 @@ static const LUA_REG_TYPE wifi_station_map[] = {
{ LSTRKEY( "getmac" ), LFUNCVAL( wifi_station_getmac ) },
{ LSTRKEY( "setmac" ), LFUNCVAL( wifi_station_setmac ) },
{ LSTRKEY( "getap" ), LFUNCVAL( wifi_station_listap ) },
{ LSTRKEY( "sethostname" ), LFUNCVAL( wifi_sta_sethostname_lua ) },
{ LSTRKEY( "gethostname" ), LFUNCVAL( wifi_sta_gethostname ) },
{ LSTRKEY( "getrssi" ), LFUNCVAL( wifi_station_getrssi ) },
{ LSTRKEY( "status" ), LFUNCVAL( wifi_station_status ) },
{ LSTRKEY( "eventMonReg" ), LFUNCVAL( wifi_station_event_mon_reg ) },
{ LSTRKEY( "eventMonStart" ), LFUNCVAL( wifi_station_event_mon_start ) },
{ LSTRKEY( "eventMonStop" ), LFUNCVAL( wifi_station_event_mon_stop ) },
#if defined(WIFI_STATION_STATUS_MONITOR_ENABLE)
{ LSTRKEY( "eventMonReg" ), LFUNCVAL( wifi_station_event_mon_reg ) }, //declared in wifi_eventmon.c
{ LSTRKEY( "eventMonStart" ), LFUNCVAL( wifi_station_event_mon_start ) }, //declared in wifi_eventmon.c
{ LSTRKEY( "eventMonStop" ), LFUNCVAL( wifi_station_event_mon_stop ) }, //declared in wifi_eventmon.c
#endif
{ LNILKEY, LNILVAL }
};
......@@ -1365,6 +1248,7 @@ static const LUA_REG_TYPE wifi_ap_dhcp_map[] = {
static const LUA_REG_TYPE wifi_ap_map[] = {
{ LSTRKEY( "config" ), LFUNCVAL( wifi_ap_config ) },
{ LSTRKEY( "deauth" ), LFUNCVAL( wifi_ap_deauth ) },
{ LSTRKEY( "getip" ), LFUNCVAL( wifi_ap_getip ) },
{ LSTRKEY( "setip" ), LFUNCVAL( wifi_ap_setip ) },
{ LSTRKEY( "getbroadcast" ), LFUNCVAL( wifi_ap_getbroadcast) },
......@@ -1384,13 +1268,17 @@ static const LUA_REG_TYPE wifi_map[] = {
{ LSTRKEY( "setphymode" ), LFUNCVAL( wifi_setphymode ) },
{ LSTRKEY( "getphymode" ), LFUNCVAL( wifi_getphymode ) },
{ LSTRKEY( "sleep" ), LFUNCVAL( wifi_sleep ) },
#ifdef WIFI_SMART_ENABLE
{ LSTRKEY( "startsmart" ), LFUNCVAL( wifi_start_smart ) },
{ LSTRKEY( "stopsmart" ), LFUNCVAL( wifi_exit_smart ) },
#endif
{ LSTRKEY( "sleeptype" ), LFUNCVAL( wifi_sleeptype ) },
{ LSTRKEY( "sta" ), LROVAL( wifi_station_map ) },
{ LSTRKEY( "ap" ), LROVAL( wifi_ap_map ) },
#if defined(WIFI_SDK_EVENT_MONITOR_ENABLE)
{ LSTRKEY( "eventmon" ), LROVAL( wifi_event_monitor_map ) }, //declared in wifi_eventmon.c
#endif
{ LSTRKEY( "NULLMODE" ), LNUMVAL( NULL_MODE ) },
{ LSTRKEY( "STATION" ), LNUMVAL( STATION_MODE ) },
{ LSTRKEY( "SOFTAP" ), LNUMVAL( SOFTAP_MODE ) },
......@@ -1421,4 +1309,45 @@ static const LUA_REG_TYPE wifi_map[] = {
{ LNILKEY, LNILVAL }
};
NODEMCU_MODULE(WIFI, "wifi", wifi_map, NULL);
void wifi_change_default_host_name(void)
{
#ifndef WIFI_STA_HOSTNAME
char temp[32];
uint8_t mac[6];
wifi_get_macaddr(STATION_IF, mac);
c_sprintf(temp, "NODE-%X%X%X", (mac)[3], (mac)[4], (mac)[5]);
wifi_sta_sethostname((const char*)temp, strlen(temp));
#elif defined(WIFI_STA_HOSTNAME) && !defined(WIFI_STA_HOSTNAME_APPEND_MAC)
if(!wifi_sta_sethostname(WIFI_STA_HOSTNAME, strlen(WIFI_STA_HOSTNAME)))
{
char temp[32];
uint8_t mac[6];
wifi_get_macaddr(STATION_IF, mac);
c_sprintf(temp, "NODE-%X%X%X", (mac)[3], (mac)[4], (mac)[5]);
wifi_sta_sethostname((const char*)temp, strlen(temp));
}
#elif defined(WIFI_STA_HOSTNAME) && defined(WIFI_STA_HOSTNAME_APPEND_MAC)
char temp[32];
uint8_t mac[6];
wifi_get_macaddr(STATION_IF, mac);
c_sprintf(temp, "%s%X%X%X", WIFI_STA_HOSTNAME, (mac)[3], (mac)[4], (mac)[5]);
if(!wifi_sta_sethostname(temp, strlen(temp)))
{
c_sprintf(temp, "NODE-%X%X%X", (mac)[3], (mac)[4], (mac)[5]);
wifi_sta_sethostname((const char*)temp, strlen(temp));
}
#endif
}
int luaopen_wifi( lua_State *L )
{
#if defined(WIFI_SDK_EVENT_MONITOR_ENABLE)
wifi_eventmon_init();
#endif
return 0;
}
NODEMCU_MODULE(WIFI, "wifi", wifi_map, luaopen_wifi);
#include "wifi_common.h"
void wifi_add_int_field(lua_State* L, char* name, lua_Integer integer)
{
lua_pushinteger(L, integer);
lua_setfield(L, -2, name);
}
void wifi_add_sprintf_field(lua_State* L, char* name, char* string, ...)
{
char buffer[256];
va_list arglist;
va_start( arglist, string );
c_vsprintf( buffer, string, arglist );
va_end( arglist );
lua_pushstring(L, buffer);
lua_setfield(L, -2, name);
}
#ifndef APP_MODULES_WIFI_COMMON_H_
#define APP_MODULES_WIFI_COMMON_H_
#include "module.h"
#include "lauxlib.h"
#include "platform.h"
#include "c_string.h"
#include "c_stdlib.h"
#include "c_types.h"
#include "user_interface.h"
#include "user_config.h"
#include "c_stdio.h"
#include "task/task.h"
void wifi_add_sprintf_field(lua_State* L, char* name, char* string, ...);
void wifi_add_int_field(lua_State* L, char* name, lua_Integer integer);
static inline void register_lua_cb(lua_State* L,int* cb_ref)
{
int ref=luaL_ref(L, LUA_REGISTRYINDEX);
if( *cb_ref != LUA_NOREF)
{
luaL_unref(L, LUA_REGISTRYINDEX, *cb_ref);
}
*cb_ref = ref;
}
static inline void unregister_lua_cb(lua_State* L, int* cb_ref)
{
if(*cb_ref != LUA_NOREF)
{
luaL_unref(L, LUA_REGISTRYINDEX, *cb_ref);
*cb_ref = LUA_NOREF;
}
}
void wifi_change_default_host_name(void);
#ifdef NODE_DEBUG
#define EVENT_DBG(...) c_printf(__VA_ARGS__)
#else
#define EVENT_DBG(...) //c_printf(__VA_ARGS__)
#endif
#ifdef WIFI_SDK_EVENT_MONITOR_ENABLE
extern const LUA_REG_TYPE wifi_event_monitor_map[];
void wifi_eventmon_init();
#endif
#ifdef WIFI_STATION_STATUS_MONITOR_ENABLE
int wifi_station_event_mon_start(lua_State* L);
int wifi_station_event_mon_reg(lua_State* L);
void wifi_station_event_mon_stop(lua_State* L);
#endif
#endif /* APP_MODULES_WIFI_COMMON_H_ */
// WiFi Event Monitor
#include "module.h"
#include "lauxlib.h"
#include "platform.h"
#include "c_string.h"
#include "c_stdlib.h"
#include "c_types.h"
#include "user_interface.h"
#include "smart.h"
#include "smartconfig.h"
#include "user_config.h"
#include "wifi_common.h"
#if defined(LUA_USE_MODULES_WIFI)
#ifdef WIFI_STATION_STATUS_MONITOR_ENABLE
//variables for wifi event monitor
static int wifi_station_status_cb_ref[6] = {[0 ... 6-1] = LUA_NOREF};
static os_timer_t wifi_sta_status_timer;
static uint8 prev_wifi_status=0;
// wifi.sta.eventMonStop()
void wifi_station_event_mon_stop(lua_State* L)
{
os_timer_disarm(&wifi_sta_status_timer);
if(lua_isstring(L,1))
{
int i;
for (i=0; i<6; i++)
{
unregister_lua_cb(L, &wifi_station_status_cb_ref[i]);
}
}
return;
}
static void wifi_status_cb(int arg)
{
lua_State* L = lua_getstate();
if (wifi_get_opmode() == SOFTAP_MODE)
{
os_timer_disarm(&wifi_sta_status_timer);
return;
}
int wifi_status = wifi_station_get_connect_status();
if (wifi_status != prev_wifi_status)
{
if(wifi_station_status_cb_ref[wifi_status] != LUA_NOREF)
{
lua_rawgeti(L, LUA_REGISTRYINDEX, wifi_station_status_cb_ref[wifi_status]);
lua_pushnumber(L, prev_wifi_status);
lua_call(L, 1, 0);
}
}
prev_wifi_status = wifi_status;
}
// wifi.sta.eventMonReg()
int wifi_station_event_mon_reg(lua_State* L)
{
uint8 id=(uint8)luaL_checknumber(L, 1);
if ((id > 5)) // verify user specified a valid wifi status
{
return luaL_error( L, "valid wifi status:0-5" );
}
if (lua_type(L, 2) == LUA_TFUNCTION || lua_type(L, 2) == LUA_TLIGHTFUNCTION) //check if 2nd item on stack is a function
{
lua_pushvalue(L, 2); //push function to top of stack
register_lua_cb(L, &wifi_station_status_cb_ref[id]);//pop function from top of the stack, register it in the LUA_REGISTRY, then assign returned lua_ref to wifi_station_status_cb_ref[id]
}
else
{
unregister_lua_cb(L, &wifi_station_status_cb_ref[id]); // unregister user's callback
}
return 0;
}
// wifi.sta.eventMonStart()
int wifi_station_event_mon_start(lua_State* L)
{
if(wifi_get_opmode() == SOFTAP_MODE) //Verify ESP is in either Station mode or StationAP mode
{
return luaL_error( L, "Can't monitor in SOFTAP mode" );
}
if (wifi_station_status_cb_ref[0] == LUA_NOREF && wifi_station_status_cb_ref[1] == LUA_NOREF &&
wifi_station_status_cb_ref[2] == LUA_NOREF && wifi_station_status_cb_ref[3] == LUA_NOREF &&
wifi_station_status_cb_ref[4] == LUA_NOREF && wifi_station_status_cb_ref[5] == LUA_NOREF )
{ //verify user has registered callbacks
return luaL_error( L, "No callbacks defined" );
}
uint32 ms = 150; //set default timer interval
if(lua_isnumber(L, 1)) // check if user has specified a different timer interval
{
ms=luaL_checknumber(L, 1); // retrieve user-defined interval
}
os_timer_disarm(&wifi_sta_status_timer);
os_timer_setfn(&wifi_sta_status_timer, (os_timer_func_t *)wifi_status_cb, NULL);
os_timer_arm(&wifi_sta_status_timer, ms, 1);
return 0;
}
#endif
#ifdef WIFI_SDK_EVENT_MONITOR_ENABLE
//variables for wifi event monitor
static task_handle_t wifi_event_monitor_task_id; //variable to hold task id for task handler(process_event_queue)
typedef struct evt_queue{
System_Event_t *evt;
struct evt_queue * next;
}evt_queue_t; //structure to hold pointers to event info and next item in queue
static evt_queue_t *wifi_event_queue_head; //pointer to beginning of queue
static evt_queue_t *wifi_event_queue_tail; //pointer to end of queue
static int wifi_event_cb_ref[EVENT_MAX+1] = { [0 ... EVENT_MAX] = LUA_NOREF}; //holds references to registered Lua callbacks
// wifi.eventmon.register()
static int wifi_event_monitor_register(lua_State* L)
{
uint8 id = (uint8)luaL_checknumber(L, 1);
if ( id > EVENT_MAX ) //Check if user is trying to register a callback for a valid event.
{
return luaL_error( L, "valid wifi events:0-%d", EVENT_MAX );
}
else
{
if (lua_type(L, 2) == LUA_TFUNCTION || lua_type(L, 2) == LUA_TLIGHTFUNCTION) //check if 2nd item on stack is a function
{
lua_pushvalue(L, 2); // copy argument (func) to the top of stack
register_lua_cb(L, &wifi_event_cb_ref[id]); //pop function from top of the stack, register it in the LUA_REGISTRY, then assign lua_ref to wifi_event_cb_ref[id]
}
else // unregister user's callback
{
unregister_lua_cb(L, &wifi_event_cb_ref[id]);
}
return 0;
}
}
static void wifi_event_monitor_handle_event_cb(System_Event_t *evt)
{
EVENT_DBG("\n\twifi_event_monitor_handle_event_cb is called\n");
if((wifi_event_cb_ref[evt->event] != LUA_NOREF) || ((wifi_event_cb_ref[EVENT_MAX] != LUA_NOREF) &&
!(evt->event == EVENT_STAMODE_CONNECTED || evt->event == EVENT_STAMODE_DISCONNECTED ||
evt->event == EVENT_STAMODE_AUTHMODE_CHANGE||evt->event==EVENT_STAMODE_GOT_IP ||
evt->event == EVENT_STAMODE_DHCP_TIMEOUT||evt->event==EVENT_SOFTAPMODE_STACONNECTED ||
evt->event == EVENT_SOFTAPMODE_STADISCONNECTED||evt->event==EVENT_SOFTAPMODE_PROBEREQRECVED)))
{
evt_queue_t *temp = (evt_queue_t*)c_malloc(sizeof(evt_queue_t)); //allocate memory for new queue item
temp->evt = (System_Event_t*)c_malloc(sizeof(System_Event_t)); //allocate memory to hold event structure
if(!temp || !temp->evt)
{
luaL_error(lua_getstate(), "wifi.eventmon malloc: out of memory");
return;
}
c_memcpy(temp->evt, evt, sizeof(System_Event_t)); //copy event data to new struct
if(wifi_event_queue_head == NULL && wifi_event_queue_tail == NULL)// if queue is empty add item to queue
{
wifi_event_queue_head = wifi_event_queue_tail = temp;
EVENT_DBG("\n\tqueue empty, adding event and posting task\n");
task_post_low(wifi_event_monitor_task_id, false);
}
else //if queue is not empty append item to end of queue
{
wifi_event_queue_tail->next=temp;
wifi_event_queue_tail=temp;
EVENT_DBG("\n\tqueue not empty, appending queue\n");
}
}
}
static void wifi_event_monitor_process_event_queue(task_param_t param, uint8 priority)
{
lua_State* L = lua_getstate();
evt_queue_t *temp = wifi_event_queue_head; //copy event_queue_head pointer to temporary pointer
System_Event_t *evt = temp->evt; //copy event data pointer to temporary pointer
EVENT_DBG("\t\tevent %u\n", evt->event);
if(wifi_event_cb_ref[evt->event] != LUA_NOREF) // check if user has registered a callback
{
lua_rawgeti(L, LUA_REGISTRYINDEX, wifi_event_cb_ref[evt->event]); //get user's callback
}
else if((wifi_event_cb_ref[EVENT_MAX]!=LUA_NOREF) &&
!(evt->event==EVENT_STAMODE_CONNECTED||evt->event==EVENT_STAMODE_DISCONNECTED||
evt->event==EVENT_STAMODE_AUTHMODE_CHANGE||evt->event==EVENT_STAMODE_GOT_IP||
evt->event==EVENT_STAMODE_DHCP_TIMEOUT||evt->event==EVENT_SOFTAPMODE_STACONNECTED||
evt->event==EVENT_SOFTAPMODE_STADISCONNECTED||evt->event==EVENT_SOFTAPMODE_PROBEREQRECVED))
{ //if user has registered an EVENT_MAX(default) callback and event is not implemented...
lua_rawgeti(L, LUA_REGISTRYINDEX, wifi_event_cb_ref[EVENT_MAX]); //get user's callback
}
lua_newtable( L );
switch (evt->event)
{
case EVENT_STAMODE_CONNECTED:
EVENT_DBG("\n\tSTAMODE_CONNECTED\n");
wifi_add_sprintf_field(L, "SSID", (char*)evt->event_info.connected.ssid);
wifi_add_sprintf_field(L, "BSSID", MACSTR, MAC2STR(evt->event_info.connected.bssid));
wifi_add_int_field(L, "channel", evt->event_info.connected.channel);
EVENT_DBG("\tConnected to SSID %s, Channel %d\n",
evt->event_info.connected.ssid,
evt->event_info.connected.channel);
break;
case EVENT_STAMODE_DISCONNECTED:
EVENT_DBG("\n\tSTAMODE_DISCONNECTED\n");
wifi_add_sprintf_field(L, "SSID", (char*)evt->event_info.disconnected.ssid);
wifi_add_int_field(L, "reason", evt->event_info.disconnected.reason);
wifi_add_sprintf_field(L, "BSSID", MACSTR, MAC2STR(evt->event_info.disconnected.bssid));
EVENT_DBG("\tDisconnect from SSID %s, reason %d\n",
evt->event_info.disconnected.ssid,
evt->event_info.disconnected.reason);
break;
case EVENT_STAMODE_AUTHMODE_CHANGE:
EVENT_DBG("\n\tSTAMODE_AUTHMODE_CHANGE\n");
wifi_add_int_field(L, "old_auth_mode", evt->event_info.auth_change.old_mode);
wifi_add_int_field(L, "new_auth_mode", evt->event_info.auth_change.new_mode);
EVENT_DBG("\tAuthmode: %u -> %u\n",
evt->event_info.auth_change.old_mode,
evt->event_info.auth_change.new_mode);
break;
case EVENT_STAMODE_GOT_IP:
EVENT_DBG("\n\tGOT_IP\n");
wifi_add_sprintf_field(L, "IP", IPSTR, IP2STR(&evt->event_info.got_ip.ip));
wifi_add_sprintf_field(L, "netmask", IPSTR, IP2STR(&evt->event_info.got_ip.mask));
wifi_add_sprintf_field(L, "gateway", IPSTR, IP2STR(&evt->event_info.got_ip.gw));
EVENT_DBG("\tIP:" IPSTR ",Mask:" IPSTR ",GW:" IPSTR "\n",
IP2STR(&evt->event_info.got_ip.ip),
IP2STR(&evt->event_info.got_ip.mask),
IP2STR(&evt->event_info.got_ip.gw));
break;
case EVENT_STAMODE_DHCP_TIMEOUT:
EVENT_DBG("\n\tSTAMODE_DHCP_TIMEOUT\n");
break;
case EVENT_SOFTAPMODE_STACONNECTED:
EVENT_DBG("\n\tSOFTAPMODE_STACONNECTED\n");
wifi_add_sprintf_field(L, "MAC", MACSTR, MAC2STR(evt->event_info.sta_connected.mac));
wifi_add_int_field(L, "AID", evt->event_info.sta_connected.aid);
EVENT_DBG("\tStation: " MACSTR "join, AID = %d\n",
MAC2STR(evt->event_info.sta_connected.mac),
evt->event_info.sta_connected.aid);
break;
case EVENT_SOFTAPMODE_STADISCONNECTED:
EVENT_DBG("\n\tSOFTAPMODE_STADISCONNECTED\n");
wifi_add_sprintf_field(L, "MAC", MACSTR, MAC2STR(evt->event_info.sta_disconnected.mac));
wifi_add_int_field(L, "AID", evt->event_info.sta_disconnected.aid);
EVENT_DBG("\tstation: " MACSTR "leave, AID = %d\n",
MAC2STR(evt->event_info.sta_disconnected.mac),
evt->event_info.sta_disconnected.aid);
break;
case EVENT_SOFTAPMODE_PROBEREQRECVED:
EVENT_DBG("\n\tSOFTAPMODE_PROBEREQRECVED\n");
wifi_add_sprintf_field(L, "MAC", MACSTR, MAC2STR(evt->event_info.ap_probereqrecved.mac));
wifi_add_int_field(L, "RSSI", evt->event_info.ap_probereqrecved.rssi);
EVENT_DBG("Station PROBEREQ: " MACSTR " RSSI = %d\n",
MAC2STR(evt->event_info.ap_probereqrecved.mac),
evt->event_info.ap_probereqrecved.rssi);
break;
default://if event is not implemented, push table with userdata containing event data
EVENT_DBG("\n\tswitch/case default\n");
wifi_add_sprintf_field(L, "info", "event %u not implemented", evt->event);
break;
}
lua_call(L, 1, 0); //execute user's callback and pass Lua table
if (wifi_event_queue_head == wifi_event_queue_tail) //if queue is empty..
{
wifi_event_queue_head = wifi_event_queue_tail = NULL; //set queue pointers to NULL
EVENT_DBG("\n\tQueue empty\n");
}
else //if queue is not empty...
{
wifi_event_queue_head = wifi_event_queue_head->next; //append item to end of queue
EVENT_DBG("\n\tmore in queue, posting task...\n");
task_post_low(wifi_event_monitor_task_id, false); //post task to process next item in queue
}
c_free(evt); //free memory used by event structure
c_free(temp); //free memory used by queue structure
}
#ifdef WIFI_EVENT_MONITOR_DISCONNECT_REASON_LIST_ENABLE
static const LUA_REG_TYPE wifi_event_monitor_reason_map[] =
{
{ LSTRKEY( "UNSPECIFIED" ), LNUMVAL( REASON_UNSPECIFIED ) },
{ LSTRKEY( "AUTH_EXPIRE" ), LNUMVAL( REASON_AUTH_EXPIRE ) },
{ LSTRKEY( "AUTH_LEAVE" ), LNUMVAL( REASON_AUTH_LEAVE ) },
{ LSTRKEY( "ASSOC_EXPIRE" ), LNUMVAL( REASON_ASSOC_EXPIRE ) },
{ LSTRKEY( "ASSOC_TOOMANY" ), LNUMVAL( REASON_ASSOC_TOOMANY ) },
{ LSTRKEY( "NOT_AUTHED" ), LNUMVAL( REASON_NOT_AUTHED ) },
{ LSTRKEY( "NOT_ASSOCED" ), LNUMVAL( REASON_NOT_ASSOCED ) },
{ LSTRKEY( "ASSOC_LEAVE" ), LNUMVAL( REASON_ASSOC_LEAVE ) },
{ LSTRKEY( "ASSOC_NOT_AUTHED" ), LNUMVAL( REASON_ASSOC_NOT_AUTHED ) },
{ LSTRKEY( "DISASSOC_PWRCAP_BAD" ), LNUMVAL( REASON_DISASSOC_PWRCAP_BAD ) },
{ LSTRKEY( "DISASSOC_SUPCHAN_BAD" ), LNUMVAL( REASON_DISASSOC_SUPCHAN_BAD ) },
{ LSTRKEY( "IE_INVALID" ), LNUMVAL( REASON_IE_INVALID ) },
{ LSTRKEY( "MIC_FAILURE" ), LNUMVAL( REASON_MIC_FAILURE ) },
{ LSTRKEY( "4WAY_HANDSHAKE_TIMEOUT" ), LNUMVAL( REASON_4WAY_HANDSHAKE_TIMEOUT ) },
{ LSTRKEY( "GROUP_KEY_UPDATE_TIMEOUT" ), LNUMVAL( REASON_GROUP_KEY_UPDATE_TIMEOUT ) },
{ LSTRKEY( "IE_IN_4WAY_DIFFERS" ), LNUMVAL( REASON_IE_IN_4WAY_DIFFERS ) },
{ LSTRKEY( "GROUP_CIPHER_INVALID" ), LNUMVAL( REASON_GROUP_CIPHER_INVALID ) },
{ LSTRKEY( "PAIRWISE_CIPHER_INVALID" ), LNUMVAL( REASON_PAIRWISE_CIPHER_INVALID ) },
{ LSTRKEY( "AKMP_INVALID" ), LNUMVAL( REASON_AKMP_INVALID ) },
{ LSTRKEY( "UNSUPP_RSN_IE_VERSION" ), LNUMVAL( REASON_UNSUPP_RSN_IE_VERSION ) },
{ LSTRKEY( "INVALID_RSN_IE_CAP" ), LNUMVAL( REASON_INVALID_RSN_IE_CAP ) },
{ LSTRKEY( "802_1X_AUTH_FAILED" ), LNUMVAL( REASON_802_1X_AUTH_FAILED ) },
{ LSTRKEY( "CIPHER_SUITE_REJECTED" ), LNUMVAL( REASON_CIPHER_SUITE_REJECTED ) },
{ LSTRKEY( "BEACON_TIMEOUT" ), LNUMVAL( REASON_BEACON_TIMEOUT ) },
{ LSTRKEY( "NO_AP_FOUND" ), LNUMVAL( REASON_NO_AP_FOUND ) },
{ LSTRKEY( "AUTH_FAIL" ), LNUMVAL( REASON_AUTH_FAIL ) },
{ LSTRKEY( "ASSOC_FAIL" ), LNUMVAL( REASON_ASSOC_FAIL ) },
{ LSTRKEY( "HANDSHAKE_TIMEOUT" ), LNUMVAL( REASON_HANDSHAKE_TIMEOUT ) },
{ LNILKEY, LNILVAL }
};
#endif
const LUA_REG_TYPE wifi_event_monitor_map[] =
{
{ LSTRKEY( "register" ), LFUNCVAL( wifi_event_monitor_register ) },
{ LSTRKEY( "unregister" ), LFUNCVAL( wifi_event_monitor_register ) },
{ LSTRKEY( "STA_CONNECTED" ), LNUMVAL( EVENT_STAMODE_CONNECTED ) },
{ LSTRKEY( "STA_DISCONNECTED" ), LNUMVAL( EVENT_STAMODE_DISCONNECTED ) },
{ LSTRKEY( "STA_AUTHMODE_CHANGE" ), LNUMVAL( EVENT_STAMODE_AUTHMODE_CHANGE ) },
{ LSTRKEY( "STA_GOT_IP" ), LNUMVAL( EVENT_STAMODE_GOT_IP ) },
{ LSTRKEY( "STA_DHCP_TIMEOUT" ), LNUMVAL( EVENT_STAMODE_DHCP_TIMEOUT ) },
{ LSTRKEY( "AP_STACONNECTED" ), LNUMVAL( EVENT_SOFTAPMODE_STACONNECTED ) },
{ LSTRKEY( "AP_STADISCONNECTED" ), LNUMVAL( EVENT_SOFTAPMODE_STADISCONNECTED ) },
{ LSTRKEY( "AP_PROBEREQRECVED" ), LNUMVAL( EVENT_SOFTAPMODE_PROBEREQRECVED ) },
{ LSTRKEY( "EVENT_MAX" ), LNUMVAL( EVENT_MAX ) },
#ifdef WIFI_EVENT_MONITOR_DISCONNECT_REASON_LIST_ENABLE
{ LSTRKEY( "reason" ), LROVAL( wifi_event_monitor_reason_map ) },
#endif
{ LNILKEY, LNILVAL }
};
void wifi_eventmon_init()
{
wifi_event_monitor_task_id = task_get_id(wifi_event_monitor_process_event_queue);//get task id from task interface
wifi_set_event_handler_cb(wifi_event_monitor_handle_event_cb);
return;
}
#endif
#endif
......@@ -43,7 +43,7 @@ static void ws2801_strip(uint8_t const * data, uint16_t len) {
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, ws2801_bit_data);
}
static void enable_pin_mux(pin) {
static void enable_pin_mux(int pin) {
// The API only supports setting PERIPHS_IO_MUX on GPIO 0, 2, 4, 5
switch (pin) {
case 0:
......
#include "module.h"
#include "lauxlib.h"
#include "lmem.h"
#include "platform.h"
#include "c_stdlib.h"
#include "c_string.h"
#include "user_interface.h"
#include "driver/uart.h"
static inline uint32_t _getCycleCount(void) {
uint32_t cycles;
__asm__ __volatile__("rsr %0,ccount":"=a" (cycles));
return cycles;
#define CANARY_VALUE 0x32383132
typedef struct {
int canary;
int size;
uint8_t colorsPerLed;
uint8_t values[0];
} ws2812_buffer;
// Init UART1 to be able to stream WS2812 data
// We use GPIO2 as output pin
static void ws2812_init() {
// Configure UART1
// Set baudrate of UART1 to 3200000
WRITE_PERI_REG(UART_CLKDIV(1), UART_CLK_FREQ / 3200000);
// Set UART Configuration No parity / 6 DataBits / 1 StopBits / Invert TX
WRITE_PERI_REG(UART_CONF0(1), UART_TXD_INV | (1 << UART_STOP_BIT_NUM_S) | (1 << UART_BIT_NUM_S));
// Pull GPIO2 down
platform_gpio_mode(4, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT);
platform_gpio_write(4, 0);
// Waits 10us to simulate a reset
os_delay_us(10);
// Redirect UART1 to GPIO2
// Disable GPIO2
GPIO_REG_WRITE(GPIO_ENABLE_W1TC_ADDRESS, BIT2);
// Enable Function 2 for GPIO2 (U1TXD)
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK);
}
// This algorithm reads the cpu clock cycles to calculate the correct
// pulse widths. It works in both 80 and 160 MHz mode.
// The values for t0h, t1h, ttot have been tweaked and it doesn't get faster than this.
// The datasheet is confusing and one might think that a shorter pulse time can be achieved.
// The period has to be at least 1.25us, even if the datasheet says:
// T0H: 0.35 (+- 0.15) + T0L: 0.8 (+- 0.15), which is 0.85<->1.45 us.
// T1H: 0.70 (+- 0.15) + T1L: 0.6 (+- 0.15), which is 1.00<->1.60 us.
// Anything lower than 1.25us will glitch in the long run.
static void ICACHE_RAM_ATTR ws2812_write(uint8_t pin, uint8_t *pixels, uint32_t length) {
uint8_t *p, *end, pixel, mask;
uint32_t t, t0h, t1h, ttot, c, start_time, pin_mask;
pin_mask = 1 << pin;
p = pixels;
end = p + length;
pixel = *p++;
mask = 0x80;
start_time = 0;
t0h = (1000 * system_get_cpu_freq()) / 3022; // 0.35us (spec=0.35 +- 0.15)
t1h = (1000 * system_get_cpu_freq()) / 1477; // 0.70us (spec=0.70 +- 0.15)
ttot = (1000 * system_get_cpu_freq()) / 800; // 1.25us (MUST be >= 1.25)
while (true) {
if (pixel & mask) {
t = t1h;
} else {
t = t0h;
}
while (((c = _getCycleCount()) - start_time) < ttot); // Wait for the previous bit to finish
GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pin_mask); // Set pin high
start_time = c; // Save the start time
while (((c = _getCycleCount()) - start_time) < t); // Wait for high time to finish
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pin_mask); // Set pin low
if (!(mask >>= 1)) { // Next bit/byte
if (p >= end) {
break;
}
pixel= *p++;
mask = 0x80;
// Stream data using UART1 routed to GPIO2
// ws2812.init() should be called first
//
// NODE_DEBUG should not be activated because it also uses UART1
static void ICACHE_RAM_ATTR ws2812_write(uint8_t *pixels, uint32_t length) {
// Data are sent LSB first, with a start bit at 0, an end bit at 1 and all inverted
// 0b00110111 => 110111 => [0]111011[1] => 10001000 => 00
// 0b00000111 => 000111 => [0]111000[1] => 10001110 => 01
// 0b00110100 => 110100 => [0]001011[1] => 11101000 => 10
// 0b00000100 => 000100 => [0]001000[1] => 11101110 => 11
// Array declared as static const to avoid runtime generation
// But declared in ".data" section to avoid read penalty from FLASH
static const __attribute__((section(".data._uartData"))) uint8_t _uartData[4] = { 0b00110111, 0b00000111, 0b00110100, 0b00000100 };
uint8_t *end = pixels + length;
do {
uint8_t value = *pixels++;
// Wait enough space in the FIFO buffer
// (Less than 124 bytes in the buffer)
while (((READ_PERI_REG(UART_STATUS(1)) >> UART_TXFIFO_CNT_S) & UART_TXFIFO_CNT) > 124);
// Fill the buffer
WRITE_PERI_REG(UART_FIFO(1), _uartData[(value >> 6) & 3]);
WRITE_PERI_REG(UART_FIFO(1), _uartData[(value >> 4) & 3]);
WRITE_PERI_REG(UART_FIFO(1), _uartData[(value >> 2) & 3]);
WRITE_PERI_REG(UART_FIFO(1), _uartData[(value >> 0) & 3]);
} while(pixels < end);
}
// Lua: ws2812.write("string")
// Byte triples in the string are interpreted as G R B values.
//
// ws2812.init() should be called first
//
// ws2812.write(string.char(0, 255, 0)) sets the first LED red.
// ws2812.write(string.char(0, 0, 255):rep(10)) sets ten LEDs blue.
// ws2812.write(string.char(255, 0, 0, 255, 255, 255)) first LED green, second LED white.
static int ws2812_writegrb(lua_State* L) {
size_t length;
const char *values = luaL_checklstring(L, 1, &length);
// Send the buffer
ws2812_write((uint8_t*) values, length);
return 0;
}
// Handle a buffer where we can store led values
static int ws2812_new_buffer(lua_State *L) {
const int leds = luaL_checkint(L, 1);
const int colorsPerLed = luaL_checkint(L, 2);
luaL_argcheck(L, leds > 0, 1, "should be a positive integer");
luaL_argcheck(L, colorsPerLed > 0, 2, "should be a positive integer");
// Allocate memory
size_t size = sizeof(ws2812_buffer) + colorsPerLed*leds*sizeof(uint8_t);
ws2812_buffer * buffer = (ws2812_buffer*)lua_newuserdata(L, size);
// Associate its metatable
luaL_getmetatable(L, "ws2812.buffer");
lua_setmetatable(L, -2);
// Save led strip size
buffer->size = leds;
buffer->colorsPerLed = colorsPerLed;
// Store canary for future type checks
buffer->canary = CANARY_VALUE;
return 1;
}
static int ws2812_buffer_fill(lua_State* L) {
ws2812_buffer * buffer = (ws2812_buffer*)lua_touserdata(L, 1);
luaL_argcheck(L, buffer && buffer->canary == CANARY_VALUE, 1, "ws2812.buffer expected");
// Grab colors
int i, j;
int * colors = luaM_malloc(L, buffer->colorsPerLed * sizeof(int));
for (i = 0; i < buffer->colorsPerLed; i++)
{
colors[i] = luaL_checkinteger(L, 2+i);
}
// Fill buffer
uint8_t * p = &buffer->values[0];
for(i = 0; i < buffer->size; i++)
{
for (j = 0; j < buffer->colorsPerLed; j++)
{
*p++ = colors[j];
}
}
// Free memory
luaM_free(L, colors);
return 0;
}
// Lua: ws2812.writergb(pin, "string")
// Byte triples in the string are interpreted as R G B values and sent to the hardware as G R B.
// WARNING: this function scrambles the input buffer :
// a = string.char(255,0,128)
// ws212.writergb(3,a)
// =a.byte()
// (0,255,128)
// ws2812.writergb(4, string.char(255, 0, 0)) uses GPIO2 and sets the first LED red.
// ws2812.writergb(3, string.char(0, 0, 255):rep(10)) uses GPIO0 and sets ten LEDs blue.
// ws2812.writergb(4, string.char(0, 255, 0, 255, 255, 255)) first LED green, second LED white.
static int ICACHE_FLASH_ATTR ws2812_writergb(lua_State* L)
{
const uint8_t pin = luaL_checkinteger(L, 1);
size_t length;
const char *rgb = luaL_checklstring(L, 2, &length);
// dont modify lua-internal lstring - make a copy instead
char *buffer = (char *)c_malloc(length);
c_memcpy(buffer, rgb, length);
// Ignore incomplete Byte triples at the end of buffer:
length -= length % 3;
// Rearrange R G B values to G R B order needed by WS2812 LEDs:
size_t i;
for (i = 0; i < length; i += 3) {
const char r = buffer[i];
const char g = buffer[i + 1];
buffer[i] = g;
buffer[i + 1] = r;
static int ws2812_buffer_fade(lua_State* L) {
ws2812_buffer * buffer = (ws2812_buffer*)lua_touserdata(L, 1);
const int fade = luaL_checkinteger(L, 2);
luaL_argcheck(L, buffer && buffer->canary == CANARY_VALUE, 1, "ws2812.buffer expected");
luaL_argcheck(L, fade > 0, 2, "fade value should be a strict positive number");
uint8_t * p = &buffer->values[0];
int i;
for(i = 0; i < buffer->size * buffer->colorsPerLed; i++)
{
*p++ /= fade;
}
// Initialize the output pin and wait a bit
platform_gpio_mode(pin, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT);
platform_gpio_write(pin, 0);
return 0;
}
// Send the buffer
ets_intr_lock();
ws2812_write(pin_num[pin], (uint8_t*) buffer, length);
ets_intr_unlock();
static int ws2812_buffer_get(lua_State* L) {
ws2812_buffer * buffer = (ws2812_buffer*)lua_touserdata(L, 1);
const int led = luaL_checkinteger(L, 2) - 1;
c_free(buffer);
luaL_argcheck(L, buffer && buffer->canary == CANARY_VALUE, 1, "ws2812.buffer expected");
luaL_argcheck(L, led >= 0 && led < buffer->size, 2, "index out of range");
int i;
for (i = 0; i < buffer->colorsPerLed; i++)
{
lua_pushnumber(L, buffer->values[buffer->colorsPerLed*led+i]);
}
return buffer->colorsPerLed;
}
static int ws2812_buffer_set(lua_State* L) {
ws2812_buffer * buffer = (ws2812_buffer*)lua_touserdata(L, 1);
const int led = luaL_checkinteger(L, 2) - 1;
luaL_argcheck(L, buffer && buffer->canary == CANARY_VALUE, 1, "ws2812.buffer expected");
luaL_argcheck(L, led >= 0 && led < buffer->size, 2, "index out of range");
int type = lua_type(L, 3);
if(type == LUA_TTABLE)
{
int i;
for (i = 0; i < buffer->colorsPerLed; i++)
{
// Get value and push it on stack
lua_rawgeti(L, 3, i+1);
// Convert it as int and store them in buffer
buffer->values[buffer->colorsPerLed*led+i] = lua_tonumber(L, -1);
}
// Clean up the stack
lua_pop(L, buffer->colorsPerLed);
}
else if(type == LUA_TSTRING)
{
size_t len;
const char * buf = lua_tolstring(L, 3, &len);
// Overflow check
if( buffer->colorsPerLed*led + len > buffer->colorsPerLed*buffer->size )
{
return luaL_error(L, "string size will exceed strip length");
}
c_memcpy(&buffer->values[buffer->colorsPerLed*led], buf, len);
}
else
{
int i;
for (i = 0; i < buffer->colorsPerLed; i++)
{
buffer->values[buffer->colorsPerLed*led+i] = luaL_checkinteger(L, 3+i);
}
}
return 0;
}
// Lua: ws2812.write(pin, "string")
// Byte triples in the string are interpreted as G R B values.
// This function does not corrupt your buffer.
//
// ws2812.write(4, string.char(0, 255, 0)) uses GPIO2 and sets the first LED red.
// ws2812.write(3, string.char(0, 0, 255):rep(10)) uses GPIO0 and sets ten LEDs blue.
// ws2812.write(4, string.char(255, 0, 0, 255, 255, 255)) first LED green, second LED white.
static int ICACHE_FLASH_ATTR ws2812_writegrb(lua_State* L) {
const uint8_t pin = luaL_checkinteger(L, 1);
size_t length;
const char *buffer = luaL_checklstring(L, 2, &length);
static int ws2812_buffer_size(lua_State* L) {
ws2812_buffer * buffer = (ws2812_buffer*)lua_touserdata(L, 1);
// Initialize the output pin
platform_gpio_mode(pin, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT);
platform_gpio_write(pin, 0);
luaL_argcheck(L, buffer && buffer->canary == CANARY_VALUE, 1, "ws2812.buffer expected");
lua_pushnumber(L, buffer->size);
return 1;
}
static int ws2812_buffer_write(lua_State* L) {
ws2812_buffer * buffer = (ws2812_buffer*)lua_touserdata(L, 1);
luaL_argcheck(L, buffer && buffer->canary == CANARY_VALUE, 1, "ws2812.buffer expected");
// Send the buffer
ets_intr_lock();
ws2812_write(pin_num[pin], (uint8_t*) buffer, length);
ets_intr_unlock();
ws2812_write(buffer->values, buffer->colorsPerLed*buffer->size);
return 0;
}
static const LUA_REG_TYPE ws2812_buffer_map[] =
{
{ LSTRKEY( "fade" ), LFUNCVAL( ws2812_buffer_fade )},
{ LSTRKEY( "fill" ), LFUNCVAL( ws2812_buffer_fill )},
{ LSTRKEY( "get" ), LFUNCVAL( ws2812_buffer_get )},
{ LSTRKEY( "set" ), LFUNCVAL( ws2812_buffer_set )},
{ LSTRKEY( "size" ), LFUNCVAL( ws2812_buffer_size )},
{ LSTRKEY( "write" ), LFUNCVAL( ws2812_buffer_write )},
{ LSTRKEY( "__index" ), LROVAL ( ws2812_buffer_map )},
{ LNILKEY, LNILVAL}
};
static const LUA_REG_TYPE ws2812_map[] =
{
{ LSTRKEY( "writergb" ), LFUNCVAL( ws2812_writergb )},
{ LSTRKEY( "write" ), LFUNCVAL( ws2812_writegrb )},
{ LSTRKEY( "newBuffer" ), LFUNCVAL( ws2812_new_buffer )},
{ LSTRKEY( "init" ), LFUNCVAL( ws2812_init )},
{ LNILKEY, LNILVAL}
};
int luaopen_ws2812(lua_State *L) {
// TODO: Make sure that the GPIO system is initialized
luaL_rometatable(L, "ws2812.buffer", (void *)ws2812_buffer_map); // create metatable for ws2812.buffer
return 0;
}
......
......@@ -15,6 +15,8 @@ ifndef PDIR
GEN_LIBS = mqtt.a
endif
STD_CFLAGS=-std=gnu11 -Wimplicit
#############################################################
# Configuration i.e. compile options etc.
# Target specific stuff (defines etc.) goes in here!
......
......@@ -402,14 +402,19 @@ mqtt_message_t* mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message
return fini_message(connection, MQTT_MSG_TYPE_PUBCOMP, 0, 0, 0);
}
mqtt_message_t* mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id)
mqtt_message_t* mqtt_msg_subscribe_init(mqtt_connection_t* connection, uint16_t *message_id)
{
init_message(connection);
if(topic == NULL || topic[0] == '\0')
if((*message_id = append_message_id(connection, 0)) == 0)
return fail_message(connection);
if((*message_id = append_message_id(connection, 0)) == 0)
return &connection->message;
}
mqtt_message_t* mqtt_msg_subscribe_topic(mqtt_connection_t* connection, const char* topic, int qos)
{
if(topic == NULL || topic[0] == '\0')
return fail_message(connection);
if(append_string(connection, topic, c_strlen(topic)) < 0)
......@@ -419,23 +424,63 @@ mqtt_message_t* mqtt_msg_subscribe(mqtt_connection_t* connection, const char* to
return fail_message(connection);
connection->buffer[connection->message.length++] = qos;
return &connection->message;
}
mqtt_message_t* mqtt_msg_subscribe_fini(mqtt_connection_t* connection)
{
return fini_message(connection, MQTT_MSG_TYPE_SUBSCRIBE, 0, 1, 0);
}
mqtt_message_t* mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id)
mqtt_message_t* mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id)
{
init_message(connection);
mqtt_message_t* result;
result = mqtt_msg_subscribe_init(connection, message_id);
if (result->length != 0) {
result = mqtt_msg_subscribe_topic(connection, topic, qos);
}
if (result->length != 0) {
result = mqtt_msg_subscribe_fini(connection);
}
if(topic == NULL || topic[0] == '\0')
return fail_message(connection);
return result;
}
if((*message_id = append_message_id(connection, 0)) == 0)
mqtt_message_t* mqtt_msg_unsubscribe_init(mqtt_connection_t* connection, uint16_t *message_id)
{
return mqtt_msg_subscribe_init(connection, message_id);
}
mqtt_message_t* mqtt_msg_unsubscribe_topic(mqtt_connection_t* connection, const char* topic)
{
if(topic == NULL || topic[0] == '\0')
return fail_message(connection);
if(append_string(connection, topic, c_strlen(topic)) < 0)
return fail_message(connection);
return fini_message(connection, MQTT_MSG_TYPE_SUBSCRIBE, 0, 1, 0);
return &connection->message;
}
mqtt_message_t* mqtt_msg_unsubscribe_fini(mqtt_connection_t* connection)
{
return fini_message(connection, MQTT_MSG_TYPE_UNSUBSCRIBE, 0, 1, 0);
}
mqtt_message_t* mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id)
{
mqtt_message_t* result;
result = mqtt_msg_unsubscribe_init(connection, message_id);
if (result->length != 0) {
result = mqtt_msg_unsubscribe_topic(connection, topic);
}
if (result->length != 0) {
result = mqtt_msg_unsubscribe_fini(connection);
}
return result;
}
mqtt_message_t* mqtt_msg_pingreq(mqtt_connection_t* connection)
......
......@@ -65,6 +65,21 @@ enum mqtt_message_type
MQTT_MSG_TYPE_DISCONNECT = 14
};
enum mqtt_connack_return_code
{
MQTT_CONN_FAIL_SERVER_NOT_FOUND = -5,
MQTT_CONN_FAIL_NOT_A_CONNACK_MSG = -4,
MQTT_CONN_FAIL_DNS = -3,
MQTT_CONN_FAIL_TIMEOUT_RECEIVING = -2,
MQTT_CONN_FAIL_TIMEOUT_SENDING = -1,
MQTT_CONNACK_ACCEPTED = 0,
MQTT_CONNACK_REFUSED_PROTOCOL_VER = 1,
MQTT_CONNACK_REFUSED_ID_REJECTED = 2,
MQTT_CONNACK_REFUSED_SERVER_UNAVAILABLE = 3,
MQTT_CONNACK_REFUSED_BAD_USER_OR_PASS = 4,
MQTT_CONNACK_REFUSED_NOT_AUTHORIZED = 5
};
typedef struct mqtt_message
{
uint8_t* data;
......@@ -101,6 +116,7 @@ static inline int mqtt_get_type(uint8_t* buffer) { return (buffer[0] & 0xf0) >>
static inline int mqtt_get_dup(uint8_t* buffer) { return (buffer[0] & 0x08) >> 3; }
static inline int mqtt_get_qos(uint8_t* buffer) { return (buffer[0] & 0x06) >> 1; }
static inline int mqtt_get_retain(uint8_t* buffer) { return (buffer[0] & 0x01); }
static inline int mqtt_get_connect_ret_code(uint8_t* buffer) { return (buffer[3]); }
void mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length);
int mqtt_get_total_length(uint8_t* buffer, uint16_t length);
......@@ -120,6 +136,14 @@ mqtt_message_t* mqtt_msg_pingreq(mqtt_connection_t* connection);
mqtt_message_t* mqtt_msg_pingresp(mqtt_connection_t* connection);
mqtt_message_t* mqtt_msg_disconnect(mqtt_connection_t* connection);
mqtt_message_t* mqtt_msg_subscribe_init(mqtt_connection_t* connection, uint16_t* message_id);
mqtt_message_t* mqtt_msg_subscribe_topic(mqtt_connection_t* connection, const char* topic, int qos);
mqtt_message_t* mqtt_msg_subscribe_fini(mqtt_connection_t* connection);
mqtt_message_t* mqtt_msg_unsubscribe_init(mqtt_connection_t* connection, uint16_t* message_id);
mqtt_message_t* mqtt_msg_unsubscribe_topic(mqtt_connection_t* connection, const char* topic);
mqtt_message_t* mqtt_msg_unsubscribe_fini(mqtt_connection_t* connection);
#ifdef __cplusplus
}
......
......@@ -12,7 +12,7 @@
# a generated lib/image xxx.a ()
#
ifndef PDIR
GEN_LIBS = wofs.a
GEN_LIBS = libnodemcu_net.a
endif
#############################################################
......@@ -39,6 +39,6 @@ endif
INCLUDES := $(INCLUDES) -I $(PDIR)include
INCLUDES += -I ./
INCLUDES += -I ../libc
INCLUDES += -I ../platform
PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile
/**
* lwip MDNS resolver file.
*
* Created on: Jul 29, 2010
* Author: Daniel Toma
*
* ported from uIP resolv.c Copyright (c) 2002-2003, Adam Dunkels.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* This file implements a MDNS host name and PUCK service registration.
*-----------------------------------------------------------------------------
* Includes
*----------------------------------------------------------------------------*/
#include "lwip/opt.h"
#if LWIP_MDNS /* don't build if not configured for use in lwipopts.h */
#include "lwip/mdns.h"
#include "lwip/udp.h"
#include "lwip/mem.h"
#include "lwip/igmp.h"
#include "osapi.h"
#include "os_type.h"
#include "user_interface.h"
#include "c_string.h"
#include "nodemcu_mdns.h"
#if 0
#define MDNS_DBG(...) os_printf(...)
#else
#define MDNS_DBG(...) do {} while (0)
#endif
#define min(a,b) ((a) < (b) ? (a) : (b))
#define MDNS_NAME_LENGTH 68 //68
#define DNS_RRTYPE_NSEC 47
static const char* service_name_with_suffix = NULL;
#define DNS_SD_SERVICE "_services._dns-sd._udp.local"
#define PUCK_SERVICE_LENGTH 30
#define PUCK_DATASHEET_SIZE 96
#ifdef MEMLEAK_DEBUG
static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;
#endif
/** DNS server IP address */
#ifndef DNS_MULTICAST_ADDRESS
#define DNS_MULTICAST_ADDRESS ipaddr_addr("224.0.0.251") /* resolver1.opendns.com */
#endif
/** DNS server IP address */
#ifndef MDNS_LOCAL
#define MDNS_LOCAL "local" /* resolver1.opendns.com */
#endif
/** DNS server port address */
#ifndef DNS_MDNS_PORT
#define DNS_MDNS_PORT 5353
#endif
/** DNS maximum number of retries when asking for a name, before "timeout". */
#ifndef DNS_MAX_RETRIES
#define DNS_MAX_RETRIES 4
#endif
/** DNS resource record max. TTL (one week as default) */
#ifndef DNS_MAX_TTL
#define DNS_MAX_TTL 604800
#endif
/* DNS protocol flags */
#define DNS_FLAG1_RESPONSE 0x84
#define DNS_FLAG1_OPCODE_STATUS 0x10
#define DNS_FLAG1_OPCODE_INVERSE 0x08
#define DNS_FLAG1_OPCODE_STANDARD 0x00
#define DNS_FLAG1_AUTHORATIVE 0x04
#define DNS_FLAG1_TRUNC 0x02
#define DNS_FLAG1_RD 0x01
#define DNS_FLAG2_RA 0x80
#define DNS_FLAG2_ERR_MASK 0x0f
#define DNS_FLAG2_ERR_NONE 0x00
#define DNS_FLAG2_ERR_NAME 0x03
/* DNS protocol states */
#define DNS_STATE_UNUSED 0
#define DNS_STATE_NEW 1
#define DNS_STATE_ASKING 2
#define DNS_STATE_DONE 3
/* MDNS registration type */
#define MDNS_HOSTNAME_REG 0
#define MDNS_SERVICE_REG 1
/* MDNS registration type */
#define MDNS_REG_ANSWER 1
#define MDNS_SD_ANSWER 2
#define MDNS_SERVICE_REG_ANSWER 3
/* MDNS registration time */
#define MDNS_HOST_TIME 120
#define MDNS_SERVICE_TIME 3600
/** MDNS name length with "." at the beginning and end of name*/
#ifndef MDNS_LENGTH_ADD
#define MDNS_LENGTH_ADD 2
#endif
#ifdef MDNS_MAX_NAME_LENGTH
#undef MDNS_MAX_NAME_LENGTH
#endif
#define MDNS_MAX_NAME_LENGTH (256)
PACK_STRUCT_BEGIN
/** DNS message header */
struct mdns_hdr {
PACK_STRUCT_FIELD(u16_t id);
PACK_STRUCT_FIELD(u8_t flags1);
PACK_STRUCT_FIELD(u8_t flags2);
PACK_STRUCT_FIELD(u16_t numquestions);
PACK_STRUCT_FIELD(u16_t numanswers);
PACK_STRUCT_FIELD(u16_t numauthrr);
PACK_STRUCT_FIELD(u16_t numextrarr);
}PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#define SIZEOF_DNS_HDR 12
PACK_STRUCT_BEGIN
/** MDNS query message structure */
struct mdns_query {
/* MDNS query record starts with either a domain name or a pointer
to a name already present somewhere in the packet. */PACK_STRUCT_FIELD(u16_t type);
PACK_STRUCT_FIELD(u16_t class);
}PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#define SIZEOF_DNS_QUERY 4
PACK_STRUCT_BEGIN
/** MDNS answer message structure */
struct mdns_answer {
/* MDNS answer record starts with either a domain name or a pointer
to a name already present somewhere in the packet. */PACK_STRUCT_FIELD(u16_t type);
PACK_STRUCT_FIELD(u16_t class);
PACK_STRUCT_FIELD(u32_t ttl);
PACK_STRUCT_FIELD(u16_t len);
}PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#define SIZEOF_DNS_ANSWER 10
PACK_STRUCT_BEGIN
/** MDNS answer message structure */
struct mdns_a_rr {
PACK_STRUCT_FIELD(u32_t src);
}PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#define SIZEOF_MDNS_A_RR 4
PACK_STRUCT_BEGIN
/** MDNS service registration message structure */
struct mdns_service {
PACK_STRUCT_FIELD(u16_t prior);
PACK_STRUCT_FIELD(u16_t weight);
PACK_STRUCT_FIELD(u16_t port);
}PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#define SIZEOF_MDNS_SERVICE 6
static os_timer_t mdns_timer;
/* forward declarations */
static void mdns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p,
struct ip_addr *addr, u16_t port);
/*-----------------------------------------------------------------------------
* Globales
*----------------------------------------------------------------------------*/
/* MDNS variables */
//static char puck_datasheet[PUCK_DATASHEET_SIZE];
static struct udp_pcb *mdns_pcb = NULL;
static struct nodemcu_mdns_info * ms_info = NULL;
static struct ip_addr multicast_addr;
static uint8 register_flag = 0;
static uint8 mdns_flag = 0;
static u8_t *mdns_payload;
/**
* Compare the "dotted" name "query" with the encoded name "response"
* to make sure an answer from the DNS server matches the current mdns_table
* entry (otherwise, answers might arrive late for hostname not on the list
* any more).
*
* @param query hostname (not encoded) from the mdns_table
* @param response encoded hostname in the DNS response
* @return 0: names equal; 1: names differ
*/
static u8_t ICACHE_FLASH_ATTR
mdns_compare_name(unsigned char *query, unsigned char *response, unsigned char *pktbase) {
unsigned char n;
do {
n = *response++;
/** @see RFC 1035 - 4.1.4. Message compression */
if ((n & 0xc0) == 0xc0) {
n = ((n << 8) + *response) & 0x3fff;
if (n < response - pktbase) {
response = pktbase + n;
} else {
return 1;
}
} else {
/* Not compressed name */
while (n > 0) {
char q = *query;
if (q >= 'A' && q <= 'Z') {
q = q + 'a' - 'A';
}
char r = *response;
if (r >= 'A' && r <= 'Z') {
r = r + 'a' - 'A';
}
if (q != r) {
return 1;
}
++response;
++query;
--n;
};
++query;
}
} while (*response != 0);
return 0;
}
static int
mdns_namelen(u8_t *p, unsigned int maxlen) {
u8_t *orig = p;
while (*p && *p <= 63) {
if (p - orig > maxlen) {
return -1;
}
p += *p + 1;
}
if (*p >= 0xc0) {
p += 2; // advance over the two byte pointer
} else {
p++; // advance over the final 0
}
if (p - orig > maxlen) {
return -1;
}
return p - orig;
}
/* Copy an unencoded name into an encoded name */
static unsigned char *copy_and_encode_name(unsigned char *ptr, const char *name) {
while (*name) {
const char *p = name;
while (*p != '.' && *p) {
p++;
}
*ptr++ = p - name;
memcpy(ptr, name, p - name);
ptr += p - name;
if (!*p) {
break;
}
name = p + 1;
}
*ptr++ = 0;
return ptr;
}
static err_t send_packet(struct pbuf *p, struct ip_addr *dst_addr, u16_t dst_port, u8_t *addr_ptr) {
err_t err;
/* send dns packet */
struct netif *sta_netif = (struct netif *)eagle_lwip_getif(0x00);
struct netif *ap_netif = (struct netif *)eagle_lwip_getif(0x01);
if (addr_ptr) {
if (wifi_get_opmode() == 0x02) {
if (!ap_netif) {
return;
}
memcpy(addr_ptr, &ap_netif->ip_addr, sizeof(ap_netif->ip_addr));
} else {
if (!sta_netif) {
return;
}
memcpy(addr_ptr, &sta_netif->ip_addr, sizeof(sta_netif->ip_addr));
}
}
if (dst_addr) {
err = udp_sendto(mdns_pcb, p, dst_addr, dst_port);
} else {
err = udp_sendto(mdns_pcb, p, &multicast_addr, DNS_MDNS_PORT);
if(wifi_get_opmode() == 0x03 && wifi_get_broadcast_if() == 0x03 &&\
sta_netif != NULL && ap_netif != NULL) {
if(netif_is_up(sta_netif) && netif_is_up(ap_netif)) {
netif_set_default(sta_netif);
if (addr_ptr) {
memcpy(addr_ptr, &ap_netif->ip_addr, sizeof(ap_netif->ip_addr));
}
err = udp_sendto(mdns_pcb, p, &multicast_addr, DNS_MDNS_PORT);
netif_set_default(ap_netif);
}
}
}
/* free pbuf */
pbuf_free(p);
return err;
}
/**
* Send a mDNS packet for the service type
*
* @param id transaction ID in the DNS query packet
* @return ERR_OK if packet is sent; an err_t indicating the problem otherwise
*/
static err_t ICACHE_FLASH_ATTR
mdns_send_service_type(u16_t id, struct ip_addr *dst_addr, u16_t dst_port) {
err_t err;
struct mdns_hdr *hdr;
struct mdns_answer ans;
struct mdns_a_rr a_rr;
struct mdns_service serv;
struct pbuf *p ,*p_sta;
char *query, *nptr;
const char *pHostname;
struct netif * sta_netif = NULL;
struct netif * ap_netif = NULL;
int max_ttl = dst_addr ? 10 : 7200;
char tmpBuf[PUCK_DATASHEET_SIZE + PUCK_SERVICE_LENGTH];
u8_t n;
u16_t length = 0;
/* if here, we have either a new query or a retry on a previous query to process */
p = pbuf_alloc(PBUF_TRANSPORT,
SIZEOF_DNS_HDR + MDNS_MAX_NAME_LENGTH * 2 + SIZEOF_DNS_QUERY, PBUF_RAM);
if (p != NULL) {
LWIP_ASSERT("pbuf must be in one piece", p->next == NULL);
/* fill dns header */
hdr = (struct mdns_hdr*) p->payload;
os_memset(hdr, 0, SIZEOF_DNS_HDR);
hdr->id = htons(id);
hdr->flags1 = DNS_FLAG1_RESPONSE;
pHostname = DNS_SD_SERVICE;
hdr->numanswers = htons(1);
query = (char*) hdr + SIZEOF_DNS_HDR;
--pHostname;
/* convert hostname into suitable query format. */
do {
++pHostname;
nptr = query;
++query;
for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {
*query = *pHostname;
++query;
++n;
}
*nptr = n;
} while (*pHostname != 0);
*query++ = '\0';
/* fill dns query */
ans.type = htons(DNS_RRTYPE_PTR);
ans.class = htons(DNS_RRCLASS_IN);
ans.ttl = htonl(min(max_ttl, 3600));
ans.len = htons(os_strlen(service_name_with_suffix) + 1 +1 );
length = 0;
MEMCPY( query, &ans, SIZEOF_DNS_ANSWER);
/* resize the query */
query = query + SIZEOF_DNS_ANSWER;
pHostname = service_name_with_suffix;
--pHostname;
/* convert hostname into suitable query format. */
do {
++pHostname;
nptr = query;
++query;
for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {
*query = *pHostname;
++query;
++n;
}
*nptr = n;
} while (*pHostname != 0);
*query++ = '\0';
/* resize pbuf to the exact dns query */
pbuf_realloc(p, (query + length) - ((char*) (p->payload)));
err = send_packet(p, dst_addr, dst_port, 0);
} else {
err = ERR_MEM;
}
return err;
}
/**
* Send a mDNS service answer packet.
*
* @param name service name to query
* @param id transaction ID in the DNS query packet
* @return ERR_OK if packet is sent; an err_t indicating the problem otherwise
*/
static err_t ICACHE_FLASH_ATTR
mdns_send_service(struct nodemcu_mdns_info *info, u16_t id, struct ip_addr *dst_addr, u16_t dst_port) {
err_t err;
struct mdns_hdr *hdr;
struct mdns_answer ans;
struct mdns_service serv;
struct mdns_a_rr a_rr;
struct pbuf *p ,*p_sta;
char *query, *nptr;
char *query_end;
const char *pHostname;
const char *name = info->host_name;
int max_ttl = dst_addr ? 10 : 7200;
u8_t n;
u8_t i = 0;
u16_t length = 0;
u8_t addr1 = 12, addr2 = 12;
struct netif * sta_netif = NULL;
struct netif * ap_netif = NULL;
char tmpBuf[PUCK_DATASHEET_SIZE + PUCK_SERVICE_LENGTH];
u16_t dns_class = dst_addr ? DNS_RRCLASS_IN : DNS_RRCLASS_FLUSH_IN;
/* if here, we have either a new query or a retry on a previous query to process */
p = pbuf_alloc(PBUF_TRANSPORT,
SIZEOF_DNS_HDR + MDNS_MAX_NAME_LENGTH * 2 + SIZEOF_DNS_QUERY, PBUF_RAM);
if (p != NULL) {
LWIP_ASSERT("pbuf must be in one piece", p->next == NULL);
/* fill dns header */
hdr = (struct mdns_hdr*) p->payload;
os_memset(hdr, 0, SIZEOF_DNS_HDR);
hdr->id = htons(id);
hdr->flags1 = DNS_FLAG1_RESPONSE;
hdr->numanswers = htons(4);
hdr->numextrarr = htons(1);
query = (char*) hdr + SIZEOF_DNS_HDR;
query_end = (char *) p->payload + p->tot_len;
c_strlcpy(tmpBuf, service_name_with_suffix, sizeof(tmpBuf));
pHostname = tmpBuf;
--pHostname;
/* convert hostname into suitable query format. */
do {
++pHostname;
nptr = query;
++query;
++addr1;
++addr2;
for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {
*query = *pHostname;
++query;
++addr1;
++addr2;
++n;
}
*nptr = n;
} while (*pHostname != 0);
*query++ = '\0';
length = sizeof(MDNS_LOCAL);
addr1 -= length;
length = os_strlen(service_name_with_suffix) + 1;
addr2 -= length;
ans.type = htons(DNS_RRTYPE_PTR);
ans.class = htons(DNS_RRCLASS_IN);
ans.ttl = htonl(min(max_ttl, 300));
length = os_strlen(ms_info->host_desc) + MDNS_LENGTH_ADD + 1;
ans.len = htons(length);
length = 0;
MEMCPY( query, &ans, SIZEOF_DNS_ANSWER);
/* resize the query */
query = query + SIZEOF_DNS_ANSWER;
int name_offset = query - (const char *) hdr;
pHostname = ms_info->host_desc;
--pHostname;
/* convert hostname into suitable query format. */
do {
++pHostname;
nptr = query;
++query;
for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {
*query = *pHostname;
++query;
++n;
}
*nptr = n;
} while (*pHostname != 0);
*query++ = DNS_OFFSET_FLAG;
*query++ = DNS_DEFAULT_OFFSET;
*query++ = 0xc0 + (name_offset >> 8);
*query++ = name_offset & 0xff;
/* fill the answer */
ans.type = htons(DNS_RRTYPE_TXT);
ans.class = htons(dns_class);
ans.ttl = htonl(min(max_ttl, 300));
// length = os_strlen(TXT_DATA) + MDNS_LENGTH_ADD + 1;
const char *attributes[12];
int attr_count = 0;
for(i = 0; i < 10 && (info->txt_data[i] != NULL); i++) {
length += os_strlen(info->txt_data[i]);
length++;
attributes[attr_count++] = info->txt_data[i];
}
//MDNS_DBG("Found %d user attributes\n", i);
static const char *defaults[] = { "platform=nodemcu", NULL };
for(i = 0; defaults[i] != NULL; i++) {
// See if this is a duplicate
int j;
int len = strchr(defaults[i], '=') + 1 - defaults[i];
for (j = 0; j < attr_count; j++) {
if (strncmp(attributes[j], defaults[i], len) == 0) {
break;
}
}
if (j == attr_count) {
length += os_strlen(defaults[i]);
length++;
attributes[attr_count++] = defaults[i];
}
}
//MDNS_DBG("Found %d total attributes\n", attr_count);
ans.len = htons(length);
MEMCPY( query, &ans, SIZEOF_DNS_ANSWER);
query = query + SIZEOF_DNS_ANSWER;
// Check enough space in the packet
const char *end_of_packet = query + length + 2 + SIZEOF_DNS_ANSWER + SIZEOF_MDNS_SERVICE +
os_strlen(ms_info->host_name) + 7 + 1 + 2 + SIZEOF_DNS_ANSWER + SIZEOF_MDNS_A_RR +
2 + SIZEOF_DNS_ANSWER + 5;
if (query_end <= end_of_packet) {
MDNS_DBG("Too much data to send\n");
pbuf_free(p);
return ERR_MEM;
}
//MDNS_DBG("Query=%x, query_end=%x, end_ofpacket=%x, length=%x\n", query, query_end, end_of_packet, length);
i = 0;
while(attributes[i] != NULL && i < attr_count) {
pHostname = attributes[i];
--pHostname;
/* convert hostname into suitable query format. */
do {
++pHostname;
nptr = query;
++query;
for (n = 0; *pHostname != 0; ++pHostname) {
*query = *pHostname;
++query;
++n;
}
*nptr = n;
} while (*pHostname != 0);
i++;
}
// *query++ = '\0';
// Increment by length
*query++ = 0xc0 + (name_offset >> 8);
*query++ = name_offset & 0xff;
// Increment by 2
ans.type = htons(DNS_RRTYPE_SRV);
ans.class = htons(dns_class);
ans.ttl = htonl(min(max_ttl, 300));
c_strlcpy(tmpBuf,ms_info->host_name, sizeof(tmpBuf));
c_strlcat(tmpBuf, ".", sizeof(tmpBuf));
c_strlcat(tmpBuf, MDNS_LOCAL, sizeof(tmpBuf));
length = os_strlen(tmpBuf) + MDNS_LENGTH_ADD;
ans.len = htons(SIZEOF_MDNS_SERVICE + length);
length = 0;
MEMCPY( query, &ans, SIZEOF_DNS_ANSWER);
/* resize the query */
query = query + SIZEOF_DNS_ANSWER;
serv.prior = htons(0);
serv.weight = htons(0);
serv.port = htons(ms_info->service_port);
MEMCPY( query, &serv, SIZEOF_MDNS_SERVICE);
/* resize the query */
query = query + SIZEOF_MDNS_SERVICE;
int hostname_offset = query - (const char *) hdr;
pHostname = tmpBuf;
--pHostname;
do {
++pHostname;
nptr = query;
++query;
for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {
*query = *pHostname;
++query;
++n;
}
*nptr = n;
} while (*pHostname != 0);
*query++ = '\0';
// increment by strlen(service_name) + 1 + 7 + sizeof_dns_answer + sizeof_mdns_service
*query++ = 0xc0 + (hostname_offset >> 8);
*query++ = hostname_offset & 0xff;
ans.type = htons(DNS_RRTYPE_A);
ans.class = htons(dns_class);
ans.ttl = htonl(min(max_ttl, 300));
ans.len = htons(DNS_IP_ADDR_LEN);
MEMCPY( query, &ans, SIZEOF_DNS_ANSWER);
/* resize the query */
query = query + SIZEOF_DNS_ANSWER;
// increment by strlen(service_name) + 1 + 7 + sizeof_dns_answer
/* fill the payload of the mDNS message */
/* set the local IP address */
a_rr.src = 0;
MEMCPY( query, &a_rr, SIZEOF_MDNS_A_RR);
u8_t *addr_ptr = query + ((char *) &a_rr.src - (char *) &a_rr);
/* resize the query */
query = query + SIZEOF_MDNS_A_RR;
// Append the NSEC record that says we only have an A record
*query++ = 0xc0 + (hostname_offset >> 8);
*query++ = hostname_offset & 0xff;
ans.type = htons(DNS_RRTYPE_NSEC);
ans.class = htons(dns_class);
ans.ttl = htonl(min(max_ttl, 300));
ans.len = htons(5);
MEMCPY( query, &ans, SIZEOF_DNS_ANSWER);
query = query + SIZEOF_DNS_ANSWER;
*query++ = 0xc0 + (hostname_offset >> 8);
*query++ = hostname_offset & 0xff;
*query++ = 0;
*query++ = 1;
*query++ = 0x40;
//MDNS_DBG("Final ptr=%x\n", query);
// increment by sizeof_mdns_a_rr
/* set the name of the authority field.
* The same name as the Query using the offset address*/
/* resize pbuf to the exact dns query */
pbuf_realloc(p, (query) - ((char*) (p->payload)));
err = send_packet(p, dst_addr, dst_port, addr_ptr);
if (!dst_addr) {
// this is being sent multicast...
// so reset the timer
os_timer_disarm(&mdns_timer);
os_timer_arm(&mdns_timer, 1000 * 280, 1);
}
} else {
MDNS_DBG("ERR_MEM \n");
err = ERR_MEM;
}
return err;
}
static char *append_nsec_record(char *query, u32_t actual_rr, int max_ttl) {
struct mdns_answer ans;
ans.type = htons(DNS_RRTYPE_NSEC);
ans.class = htons(DNS_RRCLASS_IN);
ans.ttl = htonl(min(max_ttl, 300));
ans.len = htons(9);
MEMCPY( query, &ans, SIZEOF_DNS_ANSWER);
char *rr_len = query + ((char *) &ans.len - (char *) &ans) + 1;
query = query + SIZEOF_DNS_ANSWER;
*query++ = 0xc0;
*query++ = sizeof(struct mdns_hdr);
*query++ = 0;
char *bm_len = query;
*query++ = 5;
char *abase = query;
*query++ = 0;
*query++ = 0;
*query++ = 0;
*query++ = 0;
*query++ = 0;
while (actual_rr > 0) {
int v = actual_rr & 255;
if (v < 5 * 8) {
abase[v >> 3] |= 0x80 >> (v & 7);
actual_rr = actual_rr >> 8;
}
}
while (query[-1] == 0) {
query--;
(*bm_len)--;
(*rr_len)--;
}
return query;
}
/**
* This sends an empty response -- this is used when we doin't have an RR to send
* but the name exists
*/
static void
mdns_send_no_rr(struct mdns_hdr *req, const char *name, u32_t actual_rr, struct ip_addr *dst_addr, u16_t dst_port) {
int max_ttl = dst_addr ? 10 : 7200;
struct pbuf *p;
p = pbuf_alloc(PBUF_TRANSPORT,
SIZEOF_DNS_HDR + MDNS_MAX_NAME_LENGTH * 2 + SIZEOF_DNS_QUERY, PBUF_RAM);
if (p != NULL) {
LWIP_ASSERT("pbuf must be in one piece", p->next == NULL);
/* fill dns header */
struct mdns_hdr *hdr = (struct mdns_hdr*) p->payload;
os_memset(hdr, 0, SIZEOF_DNS_HDR);
hdr->id = req->id;
hdr->flags1 = DNS_FLAG1_RESPONSE;
hdr->numextrarr = htons(1);
char *query = (char*) hdr + SIZEOF_DNS_HDR;
char *query_end = (char *) p->payload + p->tot_len;
// Now copy over the dns name
int len = strlen(name);
if (query_end - query >= len + SIZEOF_DNS_QUERY + 15) {
query = copy_and_encode_name((char *) (hdr + 1), name);
query = append_nsec_record(query, actual_rr, max_ttl);
// Set the length code correctly
pbuf_realloc(p, query - ((char*) (p->payload)));
send_packet(p, dst_addr, dst_port, NULL);
}
}
}
/**
* This sends a single A record and the NSEC record as additional
*/
static void
mdns_send_a_rr(struct mdns_hdr *req, const char *name, struct ip_addr *dst_addr, u16_t dst_port) {
int max_ttl = dst_addr ? 10 : 7200;
struct pbuf *p;
p = pbuf_alloc(PBUF_TRANSPORT,
SIZEOF_DNS_HDR + MDNS_MAX_NAME_LENGTH * 2 + SIZEOF_DNS_QUERY, PBUF_RAM);
if (p != NULL) {
LWIP_ASSERT("pbuf must be in one piece", p->next == NULL);
/* fill dns header */
struct mdns_hdr *hdr = (struct mdns_hdr*) p->payload;
os_memset(hdr, 0, SIZEOF_DNS_HDR);
hdr->id = req->id;
hdr->flags1 = DNS_FLAG1_RESPONSE;
hdr->numanswers = htons(1);
hdr->numextrarr = htons(1);
char *query = (char*) hdr + SIZEOF_DNS_HDR;
char *query_end = (char *) p->payload + p->tot_len;
// Now copy over the dns name
int len = strlen(name) + 1;
if (query_end - query >= len + SIZEOF_DNS_QUERY + 4 + 2 + 4 + 15) {
query = copy_and_encode_name((char *) (hdr + 1), name);
struct mdns_answer ans;
ans.type = htons(DNS_RRTYPE_A);
ans.class = htons(DNS_RRCLASS_IN);
ans.ttl = htonl(min(max_ttl, 300));
ans.len = htons(4);
MEMCPY( query, &ans, SIZEOF_DNS_ANSWER);
query = query + SIZEOF_DNS_ANSWER;
char *addr_ptr = query;
query += 4;
// Now add the NSEC record
*query++ = 0xc0;
*query++ = sizeof(*hdr);
query = append_nsec_record(query, DNS_RRTYPE_A, max_ttl);
// Set the length code correctly
pbuf_realloc(p, query - ((char*) (p->payload)));
send_packet(p, dst_addr, dst_port, addr_ptr);
}
}
}
/**
* Receive input function for DNS response packets arriving for the dns UDP pcb.
*
* @params see udp.h
*/
static void ICACHE_FLASH_ATTR
mdns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr,
u16_t port) {
u16_t i;
struct mdns_hdr *hdr;
u8_t nquestions;
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(pcb);
struct nodemcu_mdns_info *info = (struct nodemcu_mdns_info *)arg;
/* is the dns message too big ? */
if (p->tot_len > DNS_MSG_SIZE) {
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too big\n"));
/* free pbuf and return */
goto memerr1;
}
/* is the dns message big enough ? */
if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + SIZEOF_DNS_ANSWER)) {
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n"));
/* free pbuf and return */
goto memerr1;
}
/* copy dns payload inside static buffer for processing */
if (pbuf_copy_partial(p, mdns_payload, p->tot_len, 0) == p->tot_len) {
/* The ID in the DNS header should be our entry into the name table. */
hdr = (struct mdns_hdr*) mdns_payload;
i = htons(hdr->id);
nquestions = htons(hdr->numquestions);
//nanswers = htons(hdr->numanswers);
/* if we have a question send an answer if necessary */
u8_t qno;
u8_t *qptr = (u8_t *) (hdr + 1);
u8_t *qend = mdns_payload + p->tot_len;
for (qno = 0; qno < nquestions && qptr < qend; qno++) {
char tmpBuf[PUCK_DATASHEET_SIZE + PUCK_SERVICE_LENGTH];
struct mdns_query qry;
int namelen = mdns_namelen(qptr, qend - qptr);
memcpy(&qry, namelen + qptr, sizeof(qry));
u16_t qry_type = ntohs(qry.type);
if (port == 5353 && (ntohs(qry.class) & 0x8000) == 0) {
addr = NULL;
}
u32_t actual_rr = 0;
const char *no_rr_name = NULL;
/* MDNS_DS_DOES_NAME_CHECK */
/* Check if the name in the "question" part match with the name of the MDNS DS service. */
if (mdns_compare_name((unsigned char *) DNS_SD_SERVICE,
(unsigned char *) qptr, (unsigned char *) hdr) == 0) {
if (qry_type == DNS_RRTYPE_PTR || qry_type == DNS_RRTYPE_ANY) {
mdns_send_service_type(i, addr, port);
} else {
no_rr_name = DNS_SD_SERVICE;
actual_rr = DNS_RRTYPE_PTR;
}
} else if (mdns_compare_name((unsigned char *) service_name_with_suffix,
(unsigned char *) qptr, (unsigned char *) hdr) == 0) {
if (qry_type == DNS_RRTYPE_PTR || qry_type == DNS_RRTYPE_ANY) {
mdns_send_service(info, i, addr, port);
} else {
no_rr_name = service_name_with_suffix;
actual_rr = DNS_RRTYPE_PTR;
}
} else {
c_strlcpy(tmpBuf,ms_info->host_name, sizeof(tmpBuf));
c_strlcat(tmpBuf, ".", sizeof(tmpBuf));
c_strlcat(tmpBuf, MDNS_LOCAL, sizeof(tmpBuf));
no_rr_name = tmpBuf;
if (mdns_compare_name((unsigned char *) tmpBuf,
(unsigned char *) qptr, (unsigned char *) hdr) == 0) {
if (qry_type == DNS_RRTYPE_A || qry_type == DNS_RRTYPE_ANY) {
mdns_send_a_rr(hdr, tmpBuf, addr, port);
} else {
actual_rr = DNS_RRTYPE_A;
}
} else {
c_strlcpy(tmpBuf,ms_info->host_desc, sizeof(tmpBuf));
c_strlcat(tmpBuf, ".", sizeof(tmpBuf));
c_strlcat(tmpBuf, service_name_with_suffix, sizeof(tmpBuf));
if (mdns_compare_name((unsigned char *) tmpBuf,
(unsigned char *) qptr, (unsigned char *) hdr) == 0) {
if (qry_type == DNS_RRTYPE_TXT || qry_type == DNS_RRTYPE_SRV || qry_type == DNS_RRTYPE_ANY) {
mdns_send_service(info, i, addr, port);
} else {
actual_rr = (DNS_RRTYPE_TXT << 8) + DNS_RRTYPE_SRV;
}
}
}
}
if (actual_rr) {
mdns_send_no_rr(hdr, no_rr_name, actual_rr, addr, port);
}
qptr += namelen + sizeof(qry); // Now points to next question
}
}
memerr1:
/* free pbuf */
pbuf_free(p);
return;
}
static void
mdns_free_info(struct nodemcu_mdns_info *info) {
os_free((void *) info);
}
/**
* close the UDP pcb .
*/
void ICACHE_FLASH_ATTR
nodemcu_mdns_close(void)
{
os_timer_disarm(&mdns_timer);
if (mdns_pcb != NULL) {
udp_remove(mdns_pcb);
}
if (mdns_payload) {
os_free(mdns_payload);
}
mdns_payload = NULL;
mdns_pcb = NULL;
mdns_free_info(ms_info);
ms_info = NULL;
}
static void ICACHE_FLASH_ATTR
mdns_set_servicename(const char *name) {
char tmpBuf[128];
os_sprintf(tmpBuf, "_%s._tcp.local", name);
if (service_name_with_suffix) {
os_free(service_name_with_suffix);
}
service_name_with_suffix = c_strdup(tmpBuf);
}
static u8_t reg_counter;
static void
mdns_reg_handler_restart(void) {
reg_counter = 99;
}
static void ICACHE_FLASH_ATTR
mdns_reg(struct nodemcu_mdns_info *info) {
mdns_send_service(info,0,0,0);
if (reg_counter++ > 10) {
mdns_send_service_type(0,0,0);
reg_counter = 0;
}
}
static struct nodemcu_mdns_info *
mdns_dup_info(const struct nodemcu_mdns_info *info) {
struct nodemcu_mdns_info *result;
// calculate length
int len = sizeof(struct nodemcu_mdns_info);
len += c_strlen(info->host_name) + 1;
len += c_strlen(info->host_desc) + 1;
len += c_strlen(info->service_name) + 1;
int i;
for (i = 0; i < sizeof(info->txt_data) / sizeof(info->txt_data[0]) && info->txt_data[i]; i++) {
len += c_strlen(info->txt_data[i]) + 1;
}
#define COPY_OVER(dest, src, p) len = c_strlen(src) + 1; memcpy(p, src, len); dest = p; p += len
result = (struct nodemcu_mdns_info *) os_zalloc(len);
if (result) {
char *p = (char *) (result + 1);
result->service_port = info->service_port;
COPY_OVER(result->host_name, info->host_name, p);
COPY_OVER(result->host_desc, info->host_desc, p);
COPY_OVER(result->service_name, info->service_name, p);
for (i = 0; i < sizeof(info->txt_data) / sizeof(info->txt_data[0]) && info->txt_data[i]; i++) {
COPY_OVER(result->txt_data[i], info->txt_data[i], p);
}
}
#undef COPY_OVER
return result;
}
/**
* Initialize the resolver: set up the UDP pcb and configure the default server
* (NEW IP).
*
* returns TRUE if it worked, FALSE if it failed.
*/
bool ICACHE_FLASH_ATTR
nodemcu_mdns_init(struct nodemcu_mdns_info *info) {
/* initialize default DNS server address */
multicast_addr.addr = DNS_MULTICAST_ADDRESS;
struct ip_info ipconfig;
mdns_free_info(ms_info);
ms_info = mdns_dup_info(info); // Save the passed block. We need all the data forever
if (!ms_info) {
return FALSE;
}
if (mdns_payload) {
os_free(mdns_payload);
}
mdns_payload = (u8_t *) os_malloc(DNS_MSG_SIZE);
if (!mdns_payload) {
MDNS_DBG("Alloc fail\n");
return FALSE;
}
LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n"));
mdns_set_servicename(ms_info->service_name);
// get the host name as instrumentName_serialNumber for MDNS
// set the name of the service, the same as host name
MDNS_DBG("host_name = %s\n", ms_info->host_name);
MDNS_DBG("server_name = %s\n", service_name_with_suffix);
/* initialize mDNS */
mdns_pcb = udp_new();
if (!mdns_pcb) {
return FALSE;
}
/* join to the multicast address 224.0.0.251 */
if(wifi_get_opmode() & 0x01) {
struct netif *sta_netif = (struct netif *)eagle_lwip_getif(0x00);
if (sta_netif && sta_netif->ip_addr.addr && igmp_joingroup(&sta_netif->ip_addr, &multicast_addr) != ERR_OK) {
MDNS_DBG("sta udp_join_multigrup failed!\n");
return FALSE;
};
}
if(wifi_get_opmode() & 0x02) {
struct netif *ap_netif = (struct netif *)eagle_lwip_getif(0x01);
if (ap_netif && ap_netif->ip_addr.addr && igmp_joingroup(&ap_netif->ip_addr, &multicast_addr) != ERR_OK) {
MDNS_DBG("ap udp_join_multigrup failed!\n");
return FALSE;
};
}
register_flag = 1;
/* join to any IP address at the port 5353 */
if (udp_bind(mdns_pcb, IP_ADDR_ANY, DNS_MDNS_PORT) != ERR_OK) {
MDNS_DBG("udp_bind failed!\n");
return FALSE;
};
/*loopback function for the multicast(224.0.0.251) messages received at port 5353*/
udp_recv(mdns_pcb, mdns_recv, ms_info);
mdns_flag = 1;
/*
* Register the name of the instrument
*/
//MDNS_DBG("About to start timer\n");
os_timer_disarm(&mdns_timer);
os_timer_setfn(&mdns_timer, (os_timer_func_t *)mdns_reg,ms_info);
os_timer_arm(&mdns_timer, 1000 * 280, 1);
/* kick off the first one right away */
mdns_reg_handler_restart();
mdns_reg(ms_info);
return TRUE;
}
#endif /* LWIP_MDNS */
......@@ -15,6 +15,8 @@ ifndef PDIR
GEN_LIBS = libplatform.a
endif
STD_CFLAGS=-std=gnu11 -Wimplicit
#############################################################
# Configuration i.e. compile options etc.
# Target specific stuff (defines etc.) goes in here!
......@@ -38,7 +40,6 @@ endif
INCLUDES := $(INCLUDES) -I $(PDIR)include
INCLUDES += -I ./
INCLUDES += -I ../wofs
INCLUDES += -I ../spiffs
INCLUDES += -I ../libc
INCLUDES += -I ../lua
......
......@@ -10,89 +10,13 @@ void cmn_platform_init(void)
}
// ****************************************************************************
// GPIO functions
int platform_gpio_exists( unsigned pin )
{
return pin < NUM_GPIO;
}
// ****************************************************************************
// CAN functions
int platform_can_exists( unsigned id )
{
return id < NUM_CAN;
}
// ****************************************************************************
// SPI functions
int platform_spi_exists( unsigned id )
{
return id < NUM_SPI;
}
// ****************************************************************************
// PWM functions
int platform_pwm_exists( unsigned id )
{
return ((id < NUM_PWM) && (id > 0));
}
// ****************************************************************************
// ADC functions
int platform_adc_exists( unsigned id )
{
return id < NUM_ADC;
}
// ****************************************************************************
// UART functions
int platform_uart_exists( unsigned id )
{
return id < NUM_UART;
}
// ****************************************************************************
// OneWire functions
int platform_ow_exists( unsigned id )
{
return ((id < NUM_OW) && (id > 0));
}
// ****************************************************************************
// Timer functions
int platform_tmr_exists( unsigned id )
{
return id < NUM_TMR;
}
// ****************************************************************************
// I2C support
int platform_i2c_exists( unsigned id )
{
#ifndef NUM_I2C
return 0;
#else
return id < NUM_I2C;
#endif
}
// ****************************************************************************
// Internal flash support functions
// This symbol must be exported by the linker command file and must reflect the
// TOTAL size of flash used by the eLua image (not only the code and constants,
// but also .data and whatever else ends up in the eLua image). FS will start
// at the next usable (aligned to a flash sector boundary) address after
// at the next usable (aligned to a flash sector boundary) address after
// flash_used_size.
// extern char flash_used_size[];
......@@ -151,12 +75,12 @@ uint32_t platform_flash_get_first_free_block_address( uint32_t *psect )
if(_flash_used_end>0){ // find the used sector
sect = flashh_find_sector( platform_flash_mapped2phys ( (uint32_t)_flash_used_end - 1), NULL, &end );
if( psect )
*psect = sect + 1;
*psect = sect + 1;
return end + 1;
}else{
sect = flashh_find_sector( 0, &start, NULL ); // find the first free sector
if( psect )
*psect = sect;
*psect = sect;
return start;
}
}
......@@ -231,7 +155,7 @@ uint32_t platform_flash_read( void *to, uint32_t fromaddr, uint32_t size )
platform_s_flash_read( tmpdata, temp, blksize );
for( i = rest; size && ( i < blksize ); i ++, size --, pto ++ )
*pto = tmpdata[ i ];
if( size == 0 )
return ssize;
fromaddr = temp + blksize;
......
......@@ -41,12 +41,6 @@
#define SYS_PARAM_SEC_NUM 4
#define SYS_PARAM_SEC_START (FLASH_SEC_NUM - SYS_PARAM_SEC_NUM)
// #define WOFS_SEC_START 0x80
// #define WOFS_SEC_START 0x60
// #define WOFS_SEC_END (SYS_PARAM_SEC_START)
// #define WOFS_SEC_NUM (WOFS_SEC_END - WOFS_SEC_START)
// #define WOFS_SEC_NUM 0xc
#define INTERNAL_FLASH_SECTOR_SIZE SPI_FLASH_SEC_SIZE
// #define INTERNAL_FLASH_SECTOR_ARRAY { 0x4000, 0x4000, 0x4000, 0x4000, 0x10000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000 }
#define INTERNAL_FLASH_WRITE_UNIT_SIZE 4
......
......@@ -8,28 +8,6 @@
#include "spi_flash.h"
#include "c_stdio.h"
#if defined(ESP_INIT_DATA_ENABLE_READVDD33)
# define INIT_107 0xff
#elif defined(ESP_INIT_DATA_ENABLE_READADC)
# define INIT_107 0x00
#elif defined(ESP_INIT_DATA_FIXED_VDD33_VALUE)
# define INIT_107 ESP_INIT_DATA_FIXED_VDD33_VALUE
#else
# define INIT_107 0xff
#endif
static const uint8_t flash_init_data[128] =
{
0x05, 0x00, 0x04, 0x02, 0x05, 0x05, 0x05, 0x02, 0x05, 0x00, 0x04, 0x05, 0x05, 0x04, 0x05, 0x05,
0x04, 0xFE, 0xFD, 0xFF, 0xF0, 0xF0, 0xF0, 0xE0, 0xE0, 0xE0, 0xE1, 0x0A, 0xFF, 0xFF, 0xF8, 0x00,
0xF8, 0xF8, 0x52, 0x4E, 0x4A, 0x44, 0x40, 0x38, 0x00, 0x00, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xE1, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x93, 0x43, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, INIT_107, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
uint32_t flash_detect_size_byte(void)
{
#define FLASH_BUFFER_SIZE_DETECT 32
......@@ -132,13 +110,13 @@ uint32_t flash_rom_get_size_byte(void)
// 32Mbit, 4MByte
flash_size = 4 * 1024 * 1024;
break;
case SIZE_64MBIT:
// 64Mbit, 8MByte
flash_size = 8 * 1024 * 1024;
case SIZE_16MBIT_8M_8M:
// 16Mbit, 2MByte
flash_size = 2 * 1024 * 1024;
break;
case SIZE_128MBIT:
// 128Mbit, 16MByte
flash_size = 16 * 1024 * 1024;
case SIZE_32MBIT_8M_8M:
// 32Mbit, 4MByte
flash_size = 4 * 1024 * 1024;
break;
default:
// Unknown flash size, fall back mode.
......@@ -206,16 +184,18 @@ bool flash_rom_set_size_byte(uint32_t size)
flash_size = SIZE_32MBIT;
flash_rom_set_size_type(flash_size);
break;
/*
case 8 * 1024 * 1024:
// 64Mbit, 8MByte
flash_size = SIZE_64MBIT;
flash_size = SIZE_16MBIT_8M_8M;
flash_rom_set_size_type(flash_size);
break;
case 16 * 1024 * 1024:
// 128Mbit, 16MByte
flash_size = SIZE_128MBIT;
flash_size = SIZE_32MBIT_8M_8M;
flash_rom_set_size_type(flash_size);
break;
*/
default:
// Unknown flash size.
result = false;
......@@ -321,66 +301,6 @@ bool flash_rom_set_speed(uint32_t speed)
return true;
}
bool flash_init_data_default(void)
{
/* Can't copy directly from flash (which is where the default data lives)
* due to it being unmapped during the write, so bounce via ram buffer. */
uint8_t init_data[128];
os_memcpy (init_data, flash_init_data, 128);
// FLASH SEC - 4
// Dangerous, here are dinosaur infested!!!!!
// Reboot required!!!
// It will init system data to default!
bool result = false;
#if defined(FLASH_SAFE_API)
if (SPI_FLASH_RESULT_OK == flash_safe_erase_sector((flash_safe_get_sec_num() - 4)))
{
if (SPI_FLASH_RESULT_OK == flash_safe_write((flash_safe_get_sec_num() - 4) * SPI_FLASH_SEC_SIZE, (uint32 *)init_data, 128))
{
result = true;
}
}
#else
if (SPI_FLASH_RESULT_OK == spi_flash_erase_sector((flash_rom_get_sec_num() - 4)))
{
if (SPI_FLASH_RESULT_OK == spi_flash_write((flash_rom_get_sec_num() - 4) * SPI_FLASH_SEC_SIZE, (uint32 *)init_data, 128))
{
result = true;
}
}
#endif // defined(FLASH_SAFE_API)
return result;
}
bool flash_init_data_blank(void)
{
// FLASH SEC - 2
// Dangerous, here are dinosaur infested!!!!!
// Reboot required!!!
// It will init system config to blank!
bool result = false;
#if defined(FLASH_SAFE_API)
if ((SPI_FLASH_RESULT_OK == flash_safe_erase_sector((flash_safe_get_sec_num() - 2))) &&
(SPI_FLASH_RESULT_OK == flash_safe_erase_sector((flash_safe_get_sec_num() - 1))))
#else
if ((SPI_FLASH_RESULT_OK == spi_flash_erase_sector((flash_rom_get_sec_num() - 2))) &&
(SPI_FLASH_RESULT_OK == spi_flash_erase_sector((flash_rom_get_sec_num() - 1))))
#endif // defined(FLASH_SAFE_API)
{
result = true;
}
return result ;
}
bool flash_self_destruct(void)
{
// Dangerous, Erase your flash. Good bye!
SPIEraseChip();
return true;
}
uint8_t byte_of_aligned_array(const uint8_t *aligned_array, uint32_t index)
{
if ( (((uint32_t)aligned_array) % 4) != 0 )
......
......@@ -78,12 +78,12 @@ typedef struct
SIZE_8MBIT = 2,
SIZE_16MBIT = 3,
SIZE_32MBIT = 4,
SIZE_64MBIT = 5,
SIZE_128MBIT = 6,
SIZE_16MBIT_8M_8M = 5,
SIZE_32MBIT_8M_8M = 6,
} size : 4;
uint32_t entry_point;
uint32_t memory_offset;
uint32_t segment_size;
uint32_t segment_size;
} ICACHE_STORE_TYPEDEF_ATTR SPIFlashInfo;
uint32_t flash_detect_size_byte(void);
......@@ -100,10 +100,6 @@ bool flash_rom_set_size_byte(uint32_t);
uint16_t flash_rom_get_sec_num(void);
uint8_t flash_rom_get_mode(void);
uint32_t flash_rom_get_speed(void);
bool flash_init_data_written(void);
bool flash_init_data_default(void);
bool flash_init_data_blank(void);
bool flash_self_destruct(void);
uint8_t byte_of_aligned_array(const uint8_t* aligned_array, uint32_t index);
uint16_t word_of_aligned_array(const uint16_t *aligned_array, uint32_t index);
// uint8_t flash_rom_get_checksum(void);
......
#include "flash_fs.h"
#include "c_string.h"
#if defined( BUILD_WOFS )
#include "romfs.h"
#elif defined( BUILD_SPIFFS )
#include "spiffs.h"
#endif
int fs_mode2flag(const char *mode){
if(c_strlen(mode)==1){
......
......@@ -4,38 +4,7 @@
#include "user_config.h"
#if defined( BUILD_WOFS )
#include "romfs.h"
#define FS_OPEN_OK 0
#define FS_RDONLY O_RDONLY
#define FS_WRONLY O_WRONLY
#define FS_RDWR O_RDWR
#define FS_APPEND O_APPEND
#define FS_TRUNC O_TRUNC
#define FS_CREAT O_CREAT
#define FS_EXCL O_EXCL
#define FS_SEEK_SET SEEK_SET
#define FS_SEEK_CUR SEEK_CUR
#define FS_SEEK_END SEEK_END
#define fs_open wofs_open
#define fs_close wofs_close
#define fs_write wofs_write
#define fs_read wofs_read
#define fs_seek wofs_lseek
#define fs_eof wofs_eof
#define fs_getc wofs_getc
#define fs_ungetc wofs_ungetc
#define fs_format wofs_format
#define fs_next wofs_next
#define FS_NAME_MAX_LENGTH MAX_FNAME_LENGTH
#elif defined( BUILD_SPIFFS )
#if defined( BUILD_SPIFFS )
#include "spiffs.h"
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment