2015-09-19 21:06:56 +02:00
/*
* Copyright 2015 Robert Foss . All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
*
* - Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* - 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 .
* - Neither the name of the copyright holders nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* " 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 COPYRIGHT HOLDER OR CONTRIBUTORS 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 .
*
* @ author Robert Foss < dev @ robertfoss . se >
2016-01-28 06:52:09 +01:00
*
* Additions & fixes : Johny Mattsson < jmattsson @ dius . com . au >
2015-09-19 21:06:56 +02:00
*/
2015-12-16 06:04:58 +01:00
# include "module.h"
2015-09-02 14:41:27 +02:00
# include "lauxlib.h"
# include "platform.h"
# include "c_stdlib.h"
2016-01-28 06:52:09 +01:00
# include "c_stdio.h"
2015-09-02 14:41:27 +02:00
# include "c_string.h"
2016-01-20 09:37:03 +01:00
# include "ctype.h"
2015-09-02 14:41:27 +02:00
# include "user_interface.h"
# include "espconn.h"
# include "flash_fs.h"
2016-03-01 07:54:10 +01:00
# include "task/task.h"
2015-09-02 14:41:27 +02:00
# define MIN(x, y) (((x) < (y)) ? (x) : (y))
2016-01-28 06:52:09 +01:00
# define LITLEN(strliteral) (sizeof (strliteral) -1)
2015-09-02 14:41:27 +02:00
2015-09-19 21:06:56 +02:00
# define ENDUSER_SETUP_ERR_FATAL (1 << 0)
# define ENDUSER_SETUP_ERR_NONFATAL (1 << 1)
# define ENDUSER_SETUP_ERR_NO_RETURN (1 << 2)
# define ENDUSER_SETUP_ERR_OUT_OF_MEMORY 1
# define ENDUSER_SETUP_ERR_CONNECTION_NOT_FOUND 2
# define ENDUSER_SETUP_ERR_UNKOWN_ERROR 3
# define ENDUSER_SETUP_ERR_SOCKET_ALREADY_OPEN 4
2015-09-02 14:41:27 +02:00
/**
* DNS Response Packet :
*
* | DNS ID - 16 bits |
* | dns_header |
* | QNAME |
* | dns_body |
* | ip - 32 bits |
*
2015-09-16 14:56:44 +02:00
* DNS Header Part | FLAGS | | Q COUNT | | A CNT | | AUTH CNT | | ADD CNT | */
static const char dns_header [ ] = { 0x80 , 0x00 , 0x00 , 0x01 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 } ;
/* DNS Query Part | Q TYPE | | Q CLASS| */
static const char dns_body [ ] = { 0x00 , 0x01 , 0x00 , 0x01 ,
/* DNS Answer Part |LBL OFFS| | TYPE | | CLASS | | TTL | | RD LEN | */
0xC0 , 0x0C , 0x00 , 0x01 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x78 , 0x00 , 0x04 } ;
static const char http_html_filename [ ] = " index.html " ;
2016-01-28 06:52:09 +01:00
static const char http_header_200 [ ] = " HTTP/1.1 200 OK \r \n Cache-control:no-cache \r \n Content-Type: text/html \r \n " ; /* Note single \r\n here! */
static const char http_header_302 [ ] = " HTTP/1.1 302 Moved \r \n Location: / \r \n \r \n " ;
static const char http_header_401 [ ] = " HTTP/1.1 401 Bad request \r \n \r \n " ;
static const char http_header_404 [ ] = " HTTP/1.1 404 Not found \r \n \r \n " ;
static const char http_header_500 [ ] = " HTTP/1.1 500 Internal Error \r \n \r \n " ;
/* The below is the un-minified version of the http_html_backup[] string.
* Minified using https : //kangax.github.io/html-minifier/
* Note : using method = " get " due to iOS not always sending body in same
* packet as the HTTP header , and us thus missing it in that case
*/
#if 0
< ! DOCTYPE html >
< html >
< head >
< meta http - equiv = " content-type " content = " text/html; charset=UTF-8 " >
< meta charset = " utf-8 " >
< meta name = " viewport " content = " width=380 " >
< title > WiFi Login < / title >
< style media = " screen " type = " text/css " >
* { margin : 0 ; padding : 0 }
html { height : 100 % ; background : linear - gradient ( rgba ( 196 , 102 , 0 , .2 ) , rgba ( 155 , 89 , 182 , .2 ) ) , url ( data : image / png ; base64 , iVBORw0KGgoAAAANSUhEUgAAAEYAAAA8AgMAAACm + SSwAAAADFBMVEVBR1FFS1VHTlg8Q0zU / YXIAAADVElEQVQ4yy1TTYvTUBQ9GTKiYNoodsCF4MK6U4TZChOhiguFWHyBFzqlLl4hoeNvEBeCrlrhBVKq1EUKLTP + hvi1GyguXqBdiZCBzGqg20K8L3hDQnK55 + OeJNguHx6UujYl3dL5ALn4JOIUluAqeAWciyGaSdvngOWzNT + G0UyGUOxVOAdqkjXDCbBiUyjZ5QzYEbGadYAi6kHxth + kthXNVNCDofwhGv1D4QGGiM9iAjbCHgr2iUUpDJbs + VPQ4xAr2fX7KXbkOJMdok965Ksb + 6l rjdkem8AshIuHm9Nyu19uTunYlOXDTQqi8VgeH0kBXH2xq / ouiMZPzuMukymutrBmulUTovC6HqNFW2ZOiqlpSXZOTvSUeUPxChjxol8BLbRy4gJuhV7OR4LRVBs3WQ9VVAU7SXgK2HeUrOj7bC8YsUgr3lEV / TXB7hK90EBnxaeg1Ov15bY80M736ekCGesGAaGvG0Ct4WRkVQVHIgIM9xJgvSFfPay8Q6GNv7VpR7xUnkvhnMQCJDYkYOtNLihV70tCU1Sk + BQrpoP + HLHUrJkuta40C6LP5GvBv + Hqo10ATxxFrTPvNdPr7XwgQud6RvQN / sXjBGzqbU27wcj9cgsyvSTrpyXV8gKpXeNJU3aFl7MOdldzV4 + HfO19jBa5f2IjWwx1OLHIvFHkqbBj20ro1g7nDfY1DpScvDRUNARgjMMVO0zoMjKxJ6uWCPP + YRAWbGoaN8kXYHmLjB9FXLGOazfFVCvOgqzfnicNPrHtPKlex2ye824gMza0cTZ2sS2Xm7Qst / UfFw8O6vVtmUKxZy9xFgzMys5cJ5fxZw4y37Ufk1Dsfb8MqOjYxE3ZMWxiDcO0PYUaD2ys + 8 OW1pbB7 / e3sfZeGVCL0Q2aMjjPdm2sxADuejZxHJAd8dO9DSUdA0V8 / NggRRanDkBrANn8yHlEQOn / MmwoQfQF7xgmKDnv520bS / pgylP67vf3y2V5sCwfoCEMkZClgOfJAFX9eXefR2RpnmRs4CDVPceaRfoFzCkJVJX27vWZnoqyvmtXU3 + dW1EIXIu8Qg5Qta4Zlv7drUCoWe8 / 8 MXzaEwux7ESE9h6qnHj3mIO0 / D9RvzfxPmjWiQ1vbeSk4rrHwhAre35EEVaAAAAAElFTkSuQmCC ) }
body { font - family : arial , verdana }
div { position : absolute ; margin : auto ; top : 0 ; right : 0 ; bottom : 0 ; left : 0 ; width : 320 px ; height : 304 px }
form { width : 320 px ; text - align : center ; position : relative }
form fieldset { background : # fff ; border : 0 none ; border - radius : 5 px ; box - shadow : 0 0 15 px 1 px rgba ( 0 , 0 , 0 , .4 ) ; padding : 20 px 30 px ; box - sizing : border - box }
form input { padding : 15 px ; border : 1 px solid # ccc ; border - radius : 3 px ; margin - bottom : 10 px ; width : 100 % ; box - sizing : border - box ; font - family : montserrat ; color : # 2 C3E50 ; font - size : 13 px }
form . action - button { border : 0 none ; border - radius : 3 px ; cursor : pointer ; }
# msform .submit:focus,form .action-button:hover{box-shadow:0 0 0 2px #fff,0 0 0 3px #27AE60;}
# msform .wifitoggle:focus,form .wifitoggle:hover{box-shadow:0 0 0 2px #fff,0 0 0 3px #ccc;}
select { width : 100 % ; margin - bottom : 20 px ; padding : 10 px 5 px ; border : 1 px solid # ccc ; display : none ; }
. fs - title { font - size : 15 px ; text - transform : uppercase ; color : # 2 C3E50 ; margin - bottom : 10 px }
. fs - subtitle { font - weight : 400 ; font - size : 13 px ; color : # 666 ; margin - bottom : 20 px }
. fs - status { font - weight : 400 ; font - size : 13 px ; color : # 666 ; margin - bottom : 10 px ; padding - top : 20 px ; border - top : 1 px solid # ccc }
. submit { width : 100 px ; background : # 27 AE60 ; color : # fff ; font - weight : 700 ; margin : 10 px 5 px ; padding : 10 px 5 px ; }
. wifitoggle { float : right ; clear : both ; max - width : 75 % ; font - size : 11 px ; background : # ccc ; color : # 000 ; margin : 0 0 10 px ; 0 ; padding : 5 px 10 px ; }
< / style >
< / head >
< body >
< div >
< form method = " get " action = " /update " >
< fieldset >
< h2 class = " fs-title " > WiFi Login < / h2 >
< h3 class = " fs-subtitle " > Connect gadget to your WiFi network < / h3 >
< input autocorrect = " off " autocapitalize = " none " name = " wifi_ssid " id = " ssid " placeholder = " WiFi Name " >
< button type = ' button ' class = " action-button wifitoggle " id = " apbutton " disabled > Searching for networks . . . < / button >
< select name = " aplist " id = " aplist " size = " 2 " >
< / select >
< input name = " wifi_password " placeholder = " Password " type = " password " >
< input type = submit name = save class = ' action - button submit ' value = ' Save ' >
< h3 class = " fs-status " > Status : < span id = " status " > Updating . . . < / span > < / h3 >
< / fieldset >
< / form >
< / div >
< script >
function aplist ( ) { return document . getElementById ( " aplist " ) ; }
function fetch ( url , method , callback )
{
var xhr = new XMLHttpRequest ( ) ;
xhr . onreadystatechange = check_ready ;
function check_ready ( )
{
if ( xhr . readyState = = = 4 )
callback ( xhr . status = = = 200 ? xhr . responseText : null ) ;
}
xhr . open ( method , url , true ) ;
xhr . send ( ) ;
}
function new_status ( stat )
{
if ( stat )
{
var e = document . getElementById ( " status " ) ;
e . innerHTML = stat ;
}
setTimeout ( refresh_status , 3000 ) ;
}
2015-09-02 14:41:27 +02:00
2016-01-28 06:52:09 +01:00
function refresh_status ( )
{
fetch ( ' / status ' , ' GET ' , new_status ) ;
}
function refresh_ap_list ( )
{
var sel = aplist ( ) ;
sel . innerHTML = ' < option value = " " disabled > Scanning . . . < / option > ' ;
fetch ( ' / aplist ' , ' GET ' , got_ap_list ) ;
}
function toggle_aplist ( ev , force )
{
var sel = aplist ( ) ;
var btn = document . getElementById ( " apbutton " ) ;
if ( force | | sel . style . display = = ' block ' )
{
sel . style . display = ' none ' ;
btn . innerHTML = ' Show networks ' ;
}
else
{
sel . style . display = ' block ' ;
btn . innerHTML = ' Hide networks ' ;
}
}
function got_ap_list ( json )
{
var btn = document . getElementById ( " apbutton " ) ;
if ( json )
{
var list = JSON . parse ( json ) ;
list . sort ( function ( a , b ) { return b . rssi - a . rssi ; } ) ;
var ssids = list . map ( function ( a ) { return a . ssid ; } ) . filter ( function ( item , pos , self ) { return self . indexOf ( item ) = = pos ; } ) ;
var sel = aplist ( ) ;
sel . innerHTML = " " ;
sel . setAttribute ( " size " , Math . max ( Math . min ( 5 , list . length ) , 2 ) ) ;
for ( var i = 0 ; i < ssids . length ; + + i )
{
var o = document . createElement ( " option " ) ;
sel . options . add ( o ) ;
o . innerHTML = ssids [ i ] ;
}
btn . disabled = false ;
toggle_aplist ( null , true ) ;
btn . onclick = toggle_aplist ;
}
else
{
btn . innerHTML = " No networks found " ;
}
}
window . onload = function ( )
{
refresh_status ( ) ;
refresh_ap_list ( ) ;
aplist ( ) . onchange = function ( ) { document . getElementById ( " ssid " ) . value = aplist ( ) . value ; }
}
< / script >
< / body >
< / html >
# endif
static const char http_html_backup [ ] =
" <!DOCTYPE html><html><head><meta http-equiv=content-type content= \" text/html; charset=UTF-8 \" ><meta charset=utf-8><meta name=viewport content= \" width=380 \" ><title>WiFi Login</title><style media=screen type=text/css>*{margin:0;padding:0}html{height:100%;background:linear-gradient(rgba(196,102,0,.2),rgba(155,89,182,.2)),url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEYAAAA8AgMAAACm+SSwAAAADFBMVEVBR1FFS1VHTlg8Q0zU/YXIAAADVElEQVQ4yy1TTYvTUBQ9GTKiYNoodsCF4MK6U4TZChOhiguFWHyBFzqlLl4hoeNvEBeCrlrhBVKq1EUKLTP+hvi1GyguXqBdiZCBzGqg20K8L3hDQnK55+OeJNguHx6UujYl3dL5ALn4JOIUluAqeAWciyGaSdvngOWzNT+G0UyGUOxVOAdqkjXDCbBiUyjZ5QzYEbGadYAi6kHxth+kthXNVNCDofwhGv1D4QGGiM9iAjbCHgr2iUUpDJbs+VPQ4xAr2fX7KXbkOJMdok965Ksb+6lrjdkem8AshIuHm9Nyu19uTunYlOXDTQqi8VgeH0kBXH2xq/ouiMZPzuMukymutrBmulUTovC6HqNFW2ZOiqlpSXZOTvSUeUPxChjxol8BLbRy4gJuhV7OR4LRVBs3WQ9VVAU7SXgK2HeUrOj7bC8YsUgr3lEV/TXB7hK90EBnxaeg1Ov15bY80M736ekCGesGAaGvG0Ct4WRkVQVHIgIM9xJgvSFfPay8Q6GNv7VpR7xUnkvhnMQCJDYkYOtNLihV70tCU1Sk+BQrpoP+HLHUrJkuta40C6LP5GvBv+Hqo10ATxxFrTPvNdPr7XwgQud6RvQN/sXjBGzqbU27wcj9cgsyvSTrpyXV8gKpXeNJU3aFl7MOdldzV4+HfO19jBa5f2IjWwx1OLHIvFHkqbBj20ro1g7nDfY1DpScvDRUNARgjMMVO0zoMjKxJ6uWCPP+YRAWbGoaN8kXYHmLjB9FXLGOazfFVCvOgqzfnicNPrHtPKlex2ye824gMza0cTZ2sS2Xm7Qst/UfFw8O6vVtmUKxZy9xFgzMys5cJ5fxZw4y37Ufk1Dsfb8MqOjYxE3ZMWxiDcO0PYUaD2ys+8OW1pbB7/e3sfZeGVCL0Q2aMjjPdm2sxADuejZxHJAd8dO9DSUdA0V8/NggRRanDkBrANn8yHlEQOn/MmwoQfQF7xgmKDnv520bS/pgylP67vf3y2V5sCwfoCEMkZClgOfJAFX9eXefR2RpnmRs4CDVPceaRfoFzCkJVJX27vWZnoqyvmtXU3+dW1EIXIu8Qg5Qta4Zlv7drUCoWe8/8MXzaEwux7ESE9h6qnHj3mIO0/D9RvzfxPmjWiQ1vbeSk4rrHwhAre35EEVaAAAAAElFTkSuQmCC)}body{font-family:arial,verdana}div{position:absolute;margin:auto;top:0;right:0;bottom:0;left:0;width:320px;height:304px}form{width:320px;text-align:center;position:relative}form fieldset{background:#fff;border:0 none;border-radius:5px;box-shadow:0 0 15px 1px rgba(0,0,0,.4);padding:20px 30px;box-sizing:border-box}form input{padding:15px;border:1px solid #ccc;border-radius:3px;margin-bottom:10px;width:100%;box-sizing:border-box;font-family:montserrat;color:#2C3E50;font-size:13px}form .action-button{border:0 none;border-radius:3px;cursor:pointer}#msform .submit:focus,form .action-button:hover{box-shadow:0 0 0 2px #fff,0 0 0 3px #27AE60}#msform .wifitoggle:focus,form .wifitoggle:hover{box-shadow:0 0 0 2px #fff,0 0 0 3px #ccc}select{width:100%;margin-bottom:20px;padding:10px 5px;border:1px solid #ccc;display:none}.fs-title{font-size:15px;text-transform:uppercase;color:#2C3E50;margin-bottom:10px}.fs-subtitle{font-weight:400;font-size:13px;color:#666;margin-bottom:20px}.fs-status{font-weight:400;font-size:13px;color:#666;margin-bottom:10px;padding-top:20px;border-top:1px solid #ccc}.submit{width:100px;background:#27AE60;color:#fff;font-weight:700;margin:10px 5px;padding:10px 5px}.wifitoggle{float:right;clear:both;max-width:75%;font-size:11px;background:#ccc;color:#000;margin:0 0 10px;padding:5px 10px}</style><body><div><form action=/update><fieldset><h2 class=fs-title>WiFi Login</h2><h3 class=fs-subtitle>Connect gadget to your WiFi network</h3><input autocorrect=off autocapitalize=none name=wifi_ssid id=ssid placeholder= \" WiFi Name \" > <button type=button class= \" action-button wifitoggle \" id=apbutton disabled>Searching for networks...</button><select name=aplist id=aplist size=2></select><input name=wifi_password placeholder=Password type=password> <input type=submit name=save class= \" action-button submit \" value=Save><h3 class=fs-status>Status: <span id=status>Updating...</span></h3></fieldset></form></div><script>function aplist(){return document.getElementById( \" aplist \" )}function fetch(t,e,n){function s(){4===i.readyState&&n(200===i.status?i.responseText:null)}var i=new XMLHttpRequest;i.onreadystatechange=s,i.open(e,t,!0),i.send()}function new_status(t){if(t){var e=document.getElementById( \" status \" );e.innerHTML=t}setTimeout(refresh_status,3e3)}function refresh_status(){fetch( \" /status \" , \" GET \" ,new_status)}function refresh_ap_list(){var t=aplist();t.innerHTML='<option value= \" \" disabled>Scanning...</option>',fetch( \" /aplist \" , \" GET \" ,got_ap_list)}function tog
typedef struct scan_listener
{
struct scan_listener * next ;
int remote_port ;
uint8 remote_ip [ 4 ] ;
} scan_listener_t ;
2015-09-19 21:06:56 +02:00
typedef struct
{
struct espconn * espconn_dns_udp ;
struct espconn * espconn_http_tcp ;
char * http_payload_data ;
uint32_t http_payload_len ;
os_timer_t check_station_timer ;
int lua_connected_cb_ref ;
int lua_err_cb_ref ;
int lua_dbg_cb_ref ;
2016-01-28 06:52:09 +01:00
scan_listener_t * scan_listeners ;
2015-09-19 21:06:56 +02:00
} enduser_setup_state_t ;
static enduser_setup_state_t * state ;
2016-01-28 06:52:09 +01:00
static bool manual = false ;
2016-03-01 07:54:10 +01:00
static task_handle_t do_station_cfg_handle ;
2015-09-02 14:41:27 +02:00
2015-09-12 18:07:53 +02:00
static int enduser_setup_start ( lua_State * L ) ;
static int enduser_setup_stop ( lua_State * L ) ;
static void enduser_setup_station_start ( void ) ;
2015-09-19 21:06:56 +02:00
static void enduser_setup_station_start ( void ) ;
2015-09-12 18:07:53 +02:00
static void enduser_setup_ap_start ( void ) ;
static void enduser_setup_ap_stop ( void ) ;
2016-01-20 09:37:03 +01:00
static void enduser_setup_check_station ( void * p ) ;
2015-09-19 21:06:56 +02:00
static void enduser_setup_debug ( lua_State * L , const char * str ) ;
# define ENDUSER_SETUP_DEBUG_ENABLE 0
# if ENDUSER_SETUP_DEBUG_ENABLE
# define ENDUSER_SETUP_DEBUG(l, str) enduser_setup_debug(l, str)
# else
2016-01-28 06:52:09 +01:00
# define ENDUSER_SETUP_DEBUG(l, str) do {} while(0)
2015-09-19 21:06:56 +02:00
# endif
static void enduser_setup_debug ( lua_State * L , const char * str )
{
if ( state ! = NULL & & L ! = NULL & & state - > lua_dbg_cb_ref ! = LUA_NOREF )
{
lua_rawgeti ( L , LUA_REGISTRYINDEX , state - > lua_dbg_cb_ref ) ;
lua_pushstring ( L , str ) ;
lua_call ( L , 1 , 0 ) ;
}
}
2016-01-28 06:52:09 +01:00
# define ENDUSER_SETUP_ERROR(str, err, err_severity) \
do { \
if ( err_severity & ENDUSER_SETUP_ERR_FATAL ) enduser_setup_stop ( lua_getstate ( ) ) ; \
enduser_setup_error ( lua_getstate ( ) , str , err ) ; \
if ( ! ( err_severity & ENDUSER_SETUP_ERR_NO_RETURN ) ) \
return err ; \
} while ( 0 )
2015-09-19 21:06:56 +02:00
2016-01-28 06:52:09 +01:00
# define ENDUSER_SETUP_ERROR_VOID(str, err, err_severity) \
do { \
if ( err_severity & ENDUSER_SETUP_ERR_FATAL ) enduser_setup_stop ( lua_getstate ( ) ) ; \
enduser_setup_error ( lua_getstate ( ) , str , err ) ; \
if ( ! ( err_severity & ENDUSER_SETUP_ERR_NO_RETURN ) ) \
return ; \
} while ( 0 )
2015-09-19 21:06:56 +02:00
static void enduser_setup_error ( lua_State * L , const char * str , int err )
{
ENDUSER_SETUP_DEBUG ( L , " enduser_setup_error " ) ;
if ( state ! = NULL & & L ! = NULL & & state - > lua_err_cb_ref ! = LUA_NOREF )
{
lua_rawgeti ( L , LUA_REGISTRYINDEX , state - > lua_err_cb_ref ) ;
lua_pushnumber ( L , err ) ;
2016-01-28 06:52:09 +01:00
lua_pushfstring ( L , " enduser_setup: %s " , str ) ;
2015-09-19 21:06:56 +02:00
lua_call ( L , 2 , 0 ) ;
}
}
static void enduser_setup_connected_callback ( lua_State * L )
{
ENDUSER_SETUP_DEBUG ( L , " enduser_setup_connected_callback " ) ;
if ( state ! = NULL & & L ! = NULL & & state - > lua_connected_cb_ref ! = LUA_NOREF )
{
lua_rawgeti ( L , LUA_REGISTRYINDEX , state - > lua_connected_cb_ref ) ;
lua_call ( L , 0 , 0 ) ;
}
}
2015-09-02 14:41:27 +02:00
2015-09-12 18:07:53 +02:00
static void enduser_setup_check_station_start ( void )
2015-09-02 14:41:27 +02:00
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , " enduser_setup_check_station_start " ) ;
2015-09-19 21:06:56 +02:00
os_timer_setfn ( & ( state - > check_station_timer ) , enduser_setup_check_station , NULL ) ;
os_timer_arm ( & ( state - > check_station_timer ) , 1 * 1000 , TRUE ) ;
2015-09-02 14:41:27 +02:00
}
2015-09-12 18:07:53 +02:00
static void enduser_setup_check_station_stop ( void )
2015-09-02 14:41:27 +02:00
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , " enduser_setup_check_station_stop " ) ;
2015-09-02 14:41:27 +02:00
2016-03-01 08:33:11 +01:00
if ( state ! = NULL )
os_timer_disarm ( & ( state - > check_station_timer ) ) ;
2015-09-02 14:41:27 +02:00
}
/**
* Check Station
*
* Check that we ' ve successfully entered station mode .
*/
2016-01-20 09:37:03 +01:00
static void enduser_setup_check_station ( void * p )
2015-09-02 14:41:27 +02:00
{
2016-01-20 09:37:03 +01:00
( void ) p ;
2015-09-02 14:41:27 +02:00
struct ip_info ip ;
c_memset ( & ip , 0 , sizeof ( struct ip_info ) ) ;
wifi_get_ip_info ( STATION_IF , & ip ) ;
int i ;
char has_ip = 0 ;
for ( i = 0 ; i < sizeof ( struct ip_info ) ; + + i )
{
has_ip | = ( ( char * ) & ip ) [ i ] ;
}
2015-09-16 14:56:44 +02:00
2015-09-02 14:41:27 +02:00
if ( has_ip = = 0 )
{
return ;
}
2015-09-16 14:56:44 +02:00
2016-01-28 06:52:09 +01:00
enduser_setup_connected_callback ( lua_getstate ( ) ) ;
2015-09-02 14:41:27 +02:00
enduser_setup_stop ( NULL ) ;
}
/**
* Search String
*
* Search string for first occurance of any char in srch_str .
*
* @ return - 1 iff no occurance of char was found .
*/
2015-09-12 18:07:53 +02:00
static int enduser_setup_srch_str ( const char * str , const char * srch_str )
2015-09-02 14:41:27 +02:00
{
2016-01-28 06:52:09 +01:00
char * found = strpbrk ( str , srch_str ) ;
if ( ! found )
2015-09-02 14:41:27 +02:00
return - 1 ;
2016-01-28 06:52:09 +01:00
else
return found - str ;
2015-09-02 14:41:27 +02:00
}
/**
* Load HTTP Payload
*
* @ return - 0 iff payload loaded successfully
* 1 iff backup html was loaded
* 2 iff out of memory
*/
2015-09-12 18:07:53 +02:00
static int enduser_setup_http_load_payload ( void )
2015-09-02 14:41:27 +02:00
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , " enduser_setup_http_load_payload " ) ;
2015-09-02 14:41:27 +02:00
int f = fs_open ( http_html_filename , fs_mode2flag ( " r " ) ) ;
int err = fs_seek ( f , 0 , FS_SEEK_END ) ;
int file_len = ( int ) fs_tell ( f ) ;
int err2 = fs_seek ( f , 0 , FS_SEEK_SET ) ;
2015-09-19 21:06:56 +02:00
2016-01-28 06:52:09 +01:00
const char cl_hdr [ ] = " Content-length:%5d \r \n \r \n " ;
const size_t cl_len = LITLEN ( cl_hdr ) + 3 ; /* room to expand %4d */
2015-09-02 14:41:27 +02:00
if ( f = = 0 | | err = = - 1 | | err2 = = - 1 )
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , " enduser_setup_http_load_payload unable to load file index.html, loading backup HTML. " ) ;
2015-09-02 14:41:27 +02:00
2016-01-28 06:52:09 +01:00
int payload_len = LITLEN ( http_header_200 ) + cl_len + LITLEN ( http_html_backup ) ;
2015-09-19 21:06:56 +02:00
state - > http_payload_len = payload_len ;
state - > http_payload_data = ( char * ) c_malloc ( payload_len ) ;
if ( state - > http_payload_data = = NULL )
2015-09-02 14:41:27 +02:00
{
return 2 ;
}
2015-09-19 21:06:56 +02:00
2015-09-02 14:41:27 +02:00
int offset = 0 ;
2016-01-28 06:52:09 +01:00
c_memcpy ( & ( state - > http_payload_data [ offset ] ) , & ( http_header_200 ) , LITLEN ( http_header_200 ) ) ;
offset + = LITLEN ( http_header_200 ) ;
offset + = c_sprintf ( state - > http_payload_data + offset , cl_hdr , LITLEN ( http_html_backup ) ) ;
c_memcpy ( & ( state - > http_payload_data [ offset ] ) , & ( http_html_backup ) , LITLEN ( http_html_backup ) ) ;
2015-09-02 14:41:27 +02:00
return 1 ;
}
2015-09-19 21:06:56 +02:00
2016-01-28 06:52:09 +01:00
int payload_len = LITLEN ( http_header_200 ) + cl_len + file_len ;
2015-09-19 21:06:56 +02:00
state - > http_payload_len = payload_len ;
state - > http_payload_data = ( char * ) c_malloc ( payload_len ) ;
if ( state - > http_payload_data = = NULL )
2015-09-02 14:41:27 +02:00
{
return 2 ;
}
2015-09-19 21:06:56 +02:00
2015-09-02 14:41:27 +02:00
int offset = 0 ;
2016-01-28 06:52:09 +01:00
c_memcpy ( & ( state - > http_payload_data [ offset ] ) , & ( http_header_200 ) , LITLEN ( http_header_200 ) ) ;
offset + = LITLEN ( http_header_200 ) ;
offset + = c_sprintf ( state - > http_payload_data + offset , cl_hdr , file_len ) ;
2015-09-19 21:06:56 +02:00
fs_read ( f , & ( state - > http_payload_data [ offset ] ) , file_len ) ;
2015-09-02 14:41:27 +02:00
return 0 ;
}
/**
* De - escape URL data
*
* Parse escaped and form encoded data of request .
*/
2015-09-12 18:07:53 +02:00
static void enduser_setup_http_urldecode ( char * dst , const char * src , int src_len )
2015-09-02 14:41:27 +02:00
{
char a , b ;
int i ;
for ( i = 0 ; i < src_len & & * src ; + + i )
{
if ( ( * src = = ' % ' ) & & ( ( a = src [ 1 ] ) & & ( b = src [ 2 ] ) ) & & ( isxdigit ( a ) & & isxdigit ( b ) ) )
{
if ( a > = ' a ' )
{
a - = ' a ' - ' A ' ;
}
if ( a > = ' A ' )
{
a - = ( ' A ' - 10 ) ;
}
else
{
a - = ' 0 ' ;
}
if ( b > = ' a ' )
{
b - = ' a ' - ' A ' ;
}
if ( b > = ' A ' )
{
b - = ( ' A ' - 10 ) ;
}
else
{
b - = ' 0 ' ;
}
* dst + + = 16 * a + b ;
src + = 3 ;
i + = 2 ;
} else {
char c = * src + + ;
if ( c = = ' + ' )
{
c = ' ' ;
}
* dst + + = c ;
}
}
* dst + + = ' \0 ' ;
}
2016-03-01 07:54:10 +01:00
/**
* Task to do the actual station configuration .
* This config * cannot * be done in the network receive callback or serious
* issues like memory corruption occur .
*/
static void do_station_cfg ( task_param_t param , uint8_t prio )
{
struct station_config * cnf = ( struct station_config * ) param ;
( void ) prio ;
/* Best-effort disconnect-reconfig-reconnect. If the device is currently
* connected , the disconnect will work but the connect will report failure
* ( though it will actually start connecting ) . If the devices is not
* connected , the disconnect may fail but the connect will succeed . A
* solid head - in - the - sand approach seems to be the best tradeoff on
* functionality - vs - code - size .
* TODO : maybe use an error callback to at least report if the set config
* call fails .
*/
wifi_station_disconnect ( ) ;
wifi_station_set_config ( cnf ) ;
wifi_station_connect ( ) ;
os_free ( cnf ) ;
}
2015-09-02 14:41:27 +02:00
/**
* Handle HTTP Credentials
*
* @ return - return 0 iff credentials are found and handled successfully
* return 1 iff credentials aren ' t found
* return 2 iff an error occured
*/
2015-09-12 18:07:53 +02:00
static int enduser_setup_http_handle_credentials ( char * data , unsigned short data_len )
2015-09-02 14:41:27 +02:00
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , " enduser_setup_http_handle_credentials " ) ;
2015-09-02 14:41:27 +02:00
2015-10-01 20:22:45 +02:00
char * name_str = ( char * ) ( ( uint32_t ) strstr ( & ( data [ 6 ] ) , " wifi_ssid= " ) ) ;
char * pwd_str = ( char * ) ( ( uint32_t ) strstr ( & ( data [ 6 ] ) , " wifi_password= " ) ) ;
2015-09-02 14:41:27 +02:00
if ( name_str = = NULL | | pwd_str = = NULL )
{
return 1 ;
}
2016-01-28 06:52:09 +01:00
int name_field_len = LITLEN ( " wifi_ssid= " ) ;
int pwd_field_len = LITLEN ( " wifi_password= " ) ;
2015-09-02 14:41:27 +02:00
char * name_str_start = name_str + name_field_len ;
char * pwd_str_start = pwd_str + pwd_field_len ;
int name_str_len = enduser_setup_srch_str ( name_str_start , " & " ) ;
int pwd_str_len = enduser_setup_srch_str ( pwd_str_start , " & " ) ;
if ( name_str_len = = - 1 | | pwd_str_len = = - 1 | | name_str_len > 31 | | pwd_str_len > 63 )
{
return 1 ;
}
2015-09-19 21:06:56 +02:00
2016-03-01 07:54:10 +01:00
struct station_config * cnf = os_zalloc ( sizeof ( struct station_config ) ) ;
enduser_setup_http_urldecode ( cnf - > ssid , name_str_start , name_str_len ) ;
enduser_setup_http_urldecode ( cnf - > password , pwd_str_start , pwd_str_len ) ;
2015-09-02 14:41:27 +02:00
2016-03-01 07:54:10 +01:00
task_post_medium ( do_station_cfg_handle , ( task_param_t ) cnf ) ;
2015-09-02 14:41:27 +02:00
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , " WiFi Credentials Stored " ) ;
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , " ----------------------- " ) ;
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , " name: " ) ;
2016-03-01 07:54:10 +01:00
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , cnf - > ssid ) ;
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , " pass: " ) ;
2016-03-01 07:54:10 +01:00
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , cnf - > password ) ;
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , " ----------------------- " ) ;
2015-09-02 14:41:27 +02:00
return 0 ;
}
/**
* Serve HTML
2015-09-19 21:06:56 +02:00
*
2015-09-02 14:41:27 +02:00
* @ return - return 0 iff html was served successfully
*/
2016-01-28 06:52:09 +01:00
static int enduser_setup_http_serve_header ( struct espconn * http_client , const char * header , uint32_t header_len )
2015-09-02 14:41:27 +02:00
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , " enduser_setup_http_serve_header " ) ;
2015-09-19 21:06:56 +02:00
2016-01-28 06:52:09 +01:00
int8_t err = espconn_send ( http_client , ( char * ) header , header_len ) ;
2015-09-02 14:41:27 +02:00
if ( err = = ESPCONN_MEM )
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR ( " http_serve_header failed. espconn_send out of memory " , ENDUSER_SETUP_ERR_OUT_OF_MEMORY , ENDUSER_SETUP_ERR_NONFATAL ) ;
2015-09-02 14:41:27 +02:00
}
else if ( err = = ESPCONN_ARG )
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR ( " http_serve_header failed. espconn_send can't find network transmission " , ENDUSER_SETUP_ERR_CONNECTION_NOT_FOUND , ENDUSER_SETUP_ERR_NONFATAL ) ;
2015-09-02 14:41:27 +02:00
}
else if ( err ! = 0 )
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR ( " http_serve_header failed. espconn_send failed " , ENDUSER_SETUP_ERR_UNKOWN_ERROR , ENDUSER_SETUP_ERR_NONFATAL ) ;
2015-09-02 14:41:27 +02:00
}
2015-09-19 21:06:56 +02:00
2015-09-02 14:41:27 +02:00
return 0 ;
}
/**
* Serve HTML
2015-09-16 14:56:44 +02:00
*
2015-09-02 14:41:27 +02:00
* @ return - return 0 iff html was served successfully
*/
2015-09-12 18:07:53 +02:00
static int enduser_setup_http_serve_html ( struct espconn * http_client )
2015-09-02 14:41:27 +02:00
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , " enduser_setup_http_serve_html " ) ;
2015-09-16 14:56:44 +02:00
2015-09-19 21:06:56 +02:00
if ( state - > http_payload_data = = NULL )
2015-09-02 14:41:27 +02:00
{
enduser_setup_http_load_payload ( ) ;
}
2015-09-16 14:56:44 +02:00
2016-01-28 06:52:09 +01:00
int8_t err = espconn_send ( http_client , state - > http_payload_data , state - > http_payload_len ) ;
2015-09-02 14:41:27 +02:00
if ( err = = ESPCONN_MEM )
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR ( " http_serve_html failed. espconn_send out of memory " , ENDUSER_SETUP_ERR_OUT_OF_MEMORY , ENDUSER_SETUP_ERR_NONFATAL ) ;
2015-09-02 14:41:27 +02:00
}
else if ( err = = ESPCONN_ARG )
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR ( " http_serve_html failed. espconn_send can't find network transmission " , ENDUSER_SETUP_ERR_CONNECTION_NOT_FOUND , ENDUSER_SETUP_ERR_NONFATAL ) ;
2015-09-02 14:41:27 +02:00
}
else if ( err ! = 0 )
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR ( " http_serve_html failed. espconn_send failed " , ENDUSER_SETUP_ERR_UNKOWN_ERROR , ENDUSER_SETUP_ERR_NONFATAL ) ;
2015-09-02 14:41:27 +02:00
}
2015-09-16 14:56:44 +02:00
2015-09-02 14:41:27 +02:00
return 0 ;
}
2016-01-28 06:52:09 +01:00
static void serve_status ( struct espconn * conn )
{
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , " enduser_setup_serve_status " ) ;
const char fmt [ ] =
" HTTP/1.1 200 OK \r \n "
" Cache-control: no-cache \r \n "
" Content-type: text/plain \r \n "
" Content-length: %d \r \n "
" \r \n "
2016-03-01 07:55:45 +01:00
" %s%s " ;
2016-01-28 06:52:09 +01:00
const char * state [ ] =
{
" Idle " ,
" Connecting... " ,
" Failed to connect - wrong password " ,
" Failed to connect - network not found " ,
2016-03-01 07:55:45 +01:00
" Failed to connect "
2016-01-28 06:52:09 +01:00
} ;
const size_t num_states = sizeof ( state ) / sizeof ( state [ 0 ] ) ;
uint8_t which = wifi_station_get_connect_status ( ) ;
if ( which < num_states )
{
const char * s = state [ which ] ;
int len = c_strlen ( s ) ;
char buf [ sizeof ( fmt ) + 10 + len ] ; /* more than enough for the formatted */
2016-03-01 07:55:45 +01:00
len = c_sprintf ( buf , fmt , len , s , " " ) ;
enduser_setup_http_serve_header ( conn , buf , len ) ;
}
else if ( which = = num_states )
{
struct station_config cnf = { 0 , } ;
wifi_station_get_config ( & cnf ) ;
const char successmsg [ ] = " WiFi successfully connected to " ;
int len = LITLEN ( successmsg ) + c_strlen ( cnf . ssid ) ;
char buf [ sizeof ( fmt ) + sizeof ( successmsg ) + 32 ] ; // max-ssid
len = c_sprintf ( buf , fmt , len , successmsg , cnf . ssid ) ;
2016-01-28 06:52:09 +01:00
enduser_setup_http_serve_header ( conn , buf , len ) ;
}
else
enduser_setup_http_serve_header ( conn , http_header_500 , LITLEN ( http_header_500 ) ) ;
}
2015-09-02 14:41:27 +02:00
/**
* Disconnect HTTP client
*
* End TCP connection and free up resources .
*/
2015-09-12 18:07:53 +02:00
static void enduser_setup_http_disconnect ( struct espconn * espconn )
2015-09-02 14:41:27 +02:00
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , " enduser_setup_http_disconnect " ) ;
2015-09-02 14:41:27 +02:00
//TODO: Construct and maintain os task queue(?) to be able to issue system_os_task with espconn_disconnect.
}
2016-01-28 06:52:09 +01:00
/* --- WiFi AP scanning support -------------------------------------------- */
static void free_scan_listeners ( void )
2015-09-02 14:41:27 +02:00
{
2016-01-28 06:52:09 +01:00
if ( ! state | | ! state - > scan_listeners )
return ;
2015-09-02 14:41:27 +02:00
2016-01-28 06:52:09 +01:00
scan_listener_t * l = state - > scan_listeners , * next = 0 ;
while ( l )
2015-09-02 14:41:27 +02:00
{
2016-01-28 06:52:09 +01:00
next = l - > next ;
c_free ( l ) ;
l = next ;
}
state - > scan_listeners = 0 ;
}
static inline bool same_remote ( uint8 addr1 [ 4 ] , int port1 , uint8 addr2 [ 4 ] , int port2 )
{
return ( port1 = = port2 ) & & ( c_memcmp ( addr1 , addr2 , 4 ) = = 0 ) ;
}
static void on_disconnect ( void * arg )
{
struct espconn * conn = arg ;
if ( conn - > type = = ESPCONN_TCP & & state & & state - > scan_listeners )
{
scan_listener_t * * sl = & state - > scan_listeners ;
while ( * sl )
2015-10-01 20:22:45 +02:00
{
2016-01-28 06:52:09 +01:00
/* Remove any and all references to the closed conn from the scan list */
scan_listener_t * l = * sl ;
if ( same_remote (
l - > remote_ip , l - > remote_port ,
conn - > proto . tcp - > remote_ip , conn - > proto . tcp - > remote_port ) )
{
* sl = l - > next ;
c_free ( l ) ;
/* No early exit to guard against multi-entry on list */
}
else
sl = & ( * sl ) - > next ;
2015-10-01 20:22:45 +02:00
}
2016-01-28 06:52:09 +01:00
}
}
static char * escape_ssid ( char * dst , const char * src )
{
for ( int i = 0 ; i < 32 & & src [ i ] ; + + i )
{
if ( src [ i ] = = ' \\ ' | | src [ i ] = = ' " ' )
* dst + + = ' \\ ' ;
* dst + + = src [ i ] ;
}
return dst ;
}
static void notify_scan_listeners ( const char * payload , size_t sz )
{
if ( ! state )
return ;
if ( ! state - > espconn_http_tcp )
goto cleanup ;
struct espconn * conn = state - > espconn_http_tcp ;
for ( scan_listener_t * l = state - > scan_listeners ; l ; l = l - > next )
{
c_memcpy ( conn - > proto . tcp - > remote_ip , l - > remote_ip , 4 ) ;
conn - > proto . tcp - > remote_port = l - > remote_port ;
if ( espconn_send ( conn , ( char * ) payload , sz ) ! = ESPCONN_OK )
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , " failed to send wifi list " ) ;
enduser_setup_http_disconnect ( conn ) ;
}
cleanup :
free_scan_listeners ( ) ;
}
2015-09-16 14:56:44 +02:00
2016-01-28 06:52:09 +01:00
static void on_scan_done ( void * arg , STATUS status )
{
if ( ! state | | ! state - > scan_listeners )
return ;
if ( status = = OK )
{
unsigned num_nets = 0 ;
for ( struct bss_info * wn = arg ; wn ; wn = wn - > next . stqe_next )
+ + num_nets ;
const char header_fmt [ ] =
" HTTP/1.1 200 OK \r \n "
" Connection:close \r \n "
" Cache-control: no-cache \r \n "
" Content-type:application/json \r \n "
" Content-length:%4d \r \n "
" \r \n " ;
const size_t hdr_sz = sizeof ( header_fmt ) + 1 - 1 ; /* +expand %4d, -\0 */
/* To be able to safely escape a pathological SSID, we need 2*32 bytes */
const size_t max_entry_sz = sizeof ( " { \" ssid \" : \" \" , \" rssi \" :}, " ) + 2 * 32 + 6 ;
const size_t alloc_sz = hdr_sz + num_nets * max_entry_sz + 3 ;
char * http = os_zalloc ( alloc_sz ) ;
if ( ! http )
goto serve_500 ;
char * p = http + hdr_sz ; /* start body where we know it will be */
/* p[0] will be clobbered when we print the header, so fill it in last */
+ + p ;
for ( struct bss_info * wn = arg ; wn ; wn = wn - > next . stqe_next )
2015-10-01 20:22:45 +02:00
{
2016-01-28 06:52:09 +01:00
if ( wn ! = arg )
* p + + = ' , ' ;
const char entry_start [ ] = " { \" ssid \" : \" " ;
strcpy ( p , entry_start ) ;
p + = sizeof ( entry_start ) - 1 ;
p = escape_ssid ( p , wn - > ssid ) ;
const char entry_mid [ ] = " \" , \" rssi \" : " ;
strcpy ( p , entry_mid ) ;
p + = sizeof ( entry_mid ) - 1 ;
p + = c_sprintf ( p , " %d " , wn - > rssi ) ;
* p + + = ' } ' ;
2015-10-01 20:22:45 +02:00
}
2016-01-28 06:52:09 +01:00
* p + + = ' ] ' ;
size_t body_sz = ( p - http ) - hdr_sz ;
c_sprintf ( http , header_fmt , body_sz ) ;
http [ hdr_sz ] = ' [ ' ; /* Rewrite the \0 with the correct start of body */
notify_scan_listeners ( http , hdr_sz + body_sz ) ;
c_free ( http ) ;
return ;
}
serve_500 :
notify_scan_listeners ( http_header_500 , LITLEN ( http_header_500 ) ) ;
}
/* ---- end WiFi AP scan support ------------------------------------------- */
static void enduser_setup_http_recvcb ( void * arg , char * data , unsigned short data_len )
{
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , " enduser_setup_http_recvcb " ) ;
if ( ! state )
{
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , " ignoring received data while stopped " ) ;
return ;
2015-09-02 14:41:27 +02:00
}
2016-01-28 06:52:09 +01:00
struct espconn * http_client = ( struct espconn * ) arg ;
if ( c_strncmp ( data , " GET " , 4 ) = = 0 )
2015-09-02 14:41:27 +02:00
{
2016-01-28 06:52:09 +01:00
if ( c_strncmp ( data + 4 , " / " , 2 ) = = 0 )
2015-10-01 20:22:45 +02:00
{
2016-01-28 06:52:09 +01:00
if ( enduser_setup_http_serve_html ( http_client ) ! = 0 )
ENDUSER_SETUP_ERROR_VOID ( " http_recvcb failed. Unable to send HTML. " , ENDUSER_SETUP_ERR_UNKOWN_ERROR , ENDUSER_SETUP_ERR_NONFATAL ) ;
2015-10-01 20:22:45 +02:00
}
2016-01-28 06:52:09 +01:00
else if ( c_strncmp ( data + 4 , " /aplist " , 8 ) = = 0 )
{
scan_listener_t * l = os_malloc ( sizeof ( scan_listener_t ) ) ;
if ( ! l )
ENDUSER_SETUP_ERROR_VOID ( " out of memory " , ENDUSER_SETUP_ERR_OUT_OF_MEMORY , ENDUSER_SETUP_ERR_NONFATAL ) ;
c_memcpy ( l - > remote_ip , http_client - > proto . tcp - > remote_ip , 4 ) ;
l - > remote_port = http_client - > proto . tcp - > remote_port ;
bool already = ( state - > scan_listeners ! = NULL ) ;
l - > next = state - > scan_listeners ;
state - > scan_listeners = l ;
2015-09-16 14:56:44 +02:00
2016-01-28 06:52:09 +01:00
if ( ! already )
{
if ( ! wifi_station_scan ( NULL , on_scan_done ) )
{
enduser_setup_http_serve_header ( http_client , http_header_500 , LITLEN ( http_header_500 ) ) ;
free_scan_listeners ( ) ;
}
}
return ;
}
else if ( c_strncmp ( data + 4 , " /status " , 8 ) = = 0 )
{
serve_status ( http_client ) ;
}
else if ( c_strncmp ( data + 4 , " /update? " , 8 ) = = 0 )
{
switch ( enduser_setup_http_handle_credentials ( data , data_len ) )
{
case 0 :
enduser_setup_http_serve_header ( http_client , http_header_302 , LITLEN ( http_header_302 ) ) ;
break ;
case 1 :
enduser_setup_http_serve_header ( http_client , http_header_401 , LITLEN ( http_header_401 ) ) ;
break ;
default :
ENDUSER_SETUP_ERROR_VOID ( " http_recvcb failed. Failed to handle wifi credentials. " , ENDUSER_SETUP_ERR_UNKOWN_ERROR , ENDUSER_SETUP_ERR_NONFATAL ) ;
break ;
}
}
else
2015-10-01 20:22:45 +02:00
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , " serving 404 " ) ;
enduser_setup_http_serve_header ( http_client , http_header_404 , LITLEN ( http_header_404 ) ) ;
2015-10-01 20:22:45 +02:00
}
2015-09-02 14:41:27 +02:00
}
2016-01-28 06:52:09 +01:00
else /* not GET */
2015-09-02 14:41:27 +02:00
{
2016-01-28 06:52:09 +01:00
enduser_setup_http_serve_header ( http_client , http_header_401 , LITLEN ( http_header_401 ) ) ;
2015-09-02 14:41:27 +02:00
}
2016-01-28 06:52:09 +01:00
enduser_setup_http_disconnect ( http_client ) ;
2015-09-02 14:41:27 +02:00
}
2015-09-12 18:07:53 +02:00
static void enduser_setup_http_connectcb ( void * arg )
2015-09-02 14:41:27 +02:00
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , " enduser_setup_http_connectcb " ) ;
2015-09-02 14:41:27 +02:00
struct espconn * callback_espconn = ( struct espconn * ) arg ;
int8_t err = 0 ;
err | = espconn_regist_recvcb ( callback_espconn , enduser_setup_http_recvcb ) ;
2016-01-28 06:52:09 +01:00
err | = espconn_regist_disconcb ( callback_espconn , on_disconnect ) ;
2015-09-16 14:56:44 +02:00
2015-09-02 14:41:27 +02:00
if ( err ! = 0 )
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR_VOID ( " http_connectcb failed. Callback registration failed. " , ENDUSER_SETUP_ERR_UNKOWN_ERROR , ENDUSER_SETUP_ERR_NONFATAL ) ;
2015-09-02 14:41:27 +02:00
}
}
2015-09-19 21:06:56 +02:00
static int enduser_setup_http_start ( void )
2015-09-02 14:41:27 +02:00
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , " enduser_setup_http_start " ) ;
2015-09-19 21:06:56 +02:00
state - > espconn_http_tcp = ( struct espconn * ) c_malloc ( sizeof ( struct espconn ) ) ;
if ( state - > espconn_http_tcp = = NULL )
2015-09-02 14:41:27 +02:00
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR ( " http_start failed. Memory allocation failed (espconn_http_tcp == NULL). " , ENDUSER_SETUP_ERR_OUT_OF_MEMORY , ENDUSER_SETUP_ERR_FATAL ) ;
2015-09-02 14:41:27 +02:00
}
esp_tcp * esp_tcp_data = ( esp_tcp * ) c_malloc ( sizeof ( esp_tcp ) ) ;
if ( esp_tcp_data = = NULL )
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR ( " http_start failed. Memory allocation failed (esp_udp == NULL). " , ENDUSER_SETUP_ERR_OUT_OF_MEMORY , ENDUSER_SETUP_ERR_FATAL ) ;
2015-09-02 14:41:27 +02:00
}
2015-09-19 21:06:56 +02:00
c_memset ( state - > espconn_http_tcp , 0 , sizeof ( struct espconn ) ) ;
2015-09-02 14:41:27 +02:00
c_memset ( esp_tcp_data , 0 , sizeof ( esp_tcp ) ) ;
2015-09-19 21:06:56 +02:00
state - > espconn_http_tcp - > proto . tcp = esp_tcp_data ;
state - > espconn_http_tcp - > type = ESPCONN_TCP ;
state - > espconn_http_tcp - > state = ESPCONN_NONE ;
2015-09-02 14:41:27 +02:00
esp_tcp_data - > local_port = 80 ;
int8_t err ;
2015-09-19 21:06:56 +02:00
err = espconn_regist_connectcb ( state - > espconn_http_tcp , enduser_setup_http_connectcb ) ;
2015-09-02 14:41:27 +02:00
if ( err ! = 0 )
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR ( " http_start failed. Couldn't add receive callback. " , ENDUSER_SETUP_ERR_UNKOWN_ERROR , ENDUSER_SETUP_ERR_FATAL ) ;
2015-09-02 14:41:27 +02:00
}
2015-09-19 21:06:56 +02:00
err = espconn_accept ( state - > espconn_http_tcp ) ;
2015-09-02 14:41:27 +02:00
if ( err = = ESPCONN_ISCONN )
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR ( " http_start failed. Couldn't create connection, already listening for that connection. " , ENDUSER_SETUP_ERR_SOCKET_ALREADY_OPEN , ENDUSER_SETUP_ERR_FATAL ) ;
2015-09-02 14:41:27 +02:00
}
else if ( err = = ESPCONN_MEM )
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR ( " http_start failed. Couldn't create connection, out of memory. " , ENDUSER_SETUP_ERR_OUT_OF_MEMORY , ENDUSER_SETUP_ERR_FATAL ) ;
2015-09-02 14:41:27 +02:00
}
else if ( err = = ESPCONN_ARG )
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR ( " http_start failed. Can't find connection from espconn argument " , ENDUSER_SETUP_ERR_CONNECTION_NOT_FOUND , ENDUSER_SETUP_ERR_FATAL ) ;
2015-09-02 14:41:27 +02:00
}
else if ( err ! = 0 )
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR ( " http_start failed. Unknown error " , ENDUSER_SETUP_ERR_UNKOWN_ERROR , ENDUSER_SETUP_ERR_FATAL ) ;
2015-09-02 14:41:27 +02:00
}
2015-09-16 14:56:44 +02:00
2015-09-19 21:06:56 +02:00
err = espconn_regist_time ( state - > espconn_http_tcp , 2 , 0 ) ;
2015-09-02 14:41:27 +02:00
if ( err = = ESPCONN_ARG )
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR ( " http_start failed. Unable to set TCP timeout. " , ENDUSER_SETUP_ERR_CONNECTION_NOT_FOUND , ENDUSER_SETUP_ERR_NONFATAL | ENDUSER_SETUP_ERR_NO_RETURN ) ;
2015-09-02 14:41:27 +02:00
}
err = enduser_setup_http_load_payload ( ) ;
if ( err = = 1 )
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , " enduser_setup_http_start info. Loaded backup HTML. " ) ;
2015-09-02 14:41:27 +02:00
}
else if ( err = = 2 )
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR ( " http_start failed. Unable to allocate memory for HTTP payload. " , ENDUSER_SETUP_ERR_OUT_OF_MEMORY , ENDUSER_SETUP_ERR_FATAL ) ;
2015-09-02 14:41:27 +02:00
}
2015-09-19 21:06:56 +02:00
return 0 ;
2015-09-02 14:41:27 +02:00
}
2015-09-12 18:07:53 +02:00
static void enduser_setup_http_stop ( void )
2015-09-02 14:41:27 +02:00
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , " enduser_setup_http_stop " ) ;
2015-09-02 14:41:27 +02:00
2015-09-19 21:06:56 +02:00
if ( state ! = NULL & & state - > espconn_http_tcp ! = NULL )
2015-09-02 14:41:27 +02:00
{
2015-09-19 21:06:56 +02:00
espconn_delete ( state - > espconn_http_tcp ) ;
2015-09-02 14:41:27 +02:00
}
}
2015-09-12 18:07:53 +02:00
static void enduser_setup_ap_stop ( void )
2015-09-02 14:41:27 +02:00
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , " enduser_setup_station_stop " ) ;
2015-09-02 14:41:27 +02:00
wifi_set_opmode ( ~ SOFTAP_MODE & wifi_get_opmode ( ) ) ;
}
2015-09-12 18:07:53 +02:00
static void enduser_setup_ap_start ( void )
2015-09-02 14:41:27 +02:00
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , " enduser_setup_ap_start " ) ;
2015-09-02 14:41:27 +02:00
struct softap_config cnf ;
2015-09-27 20:02:25 +02:00
c_memset ( & ( cnf ) , 0 , sizeof ( struct softap_config ) ) ;
2015-12-21 04:50:36 +01:00
# ifndef ENDUSER_SETUP_AP_SSID
# define ENDUSER_SETUP_AP_SSID "SetupGadget"
# endif
2015-09-27 20:02:25 +02:00
char ssid [ ] = ENDUSER_SETUP_AP_SSID ;
2016-01-28 06:52:09 +01:00
int ssid_name_len = c_strlen ( ssid ) ;
2015-09-27 20:02:25 +02:00
c_memcpy ( & ( cnf . ssid ) , ssid , ssid_name_len ) ;
uint8_t mac [ 6 ] ;
wifi_get_macaddr ( SOFTAP_IF , mac ) ;
cnf . ssid [ ssid_name_len ] = ' _ ' ;
2016-01-28 06:52:09 +01:00
c_sprintf ( cnf . ssid + ssid_name_len + 1 , " %02X%02X%02X " , mac [ 3 ] , mac [ 4 ] , mac [ 5 ] ) ;
cnf . ssid_len = ssid_name_len + 7 ;
2015-09-02 14:41:27 +02:00
cnf . channel = 1 ;
cnf . authmode = AUTH_OPEN ;
cnf . ssid_hidden = 0 ;
cnf . max_connection = 5 ;
cnf . beacon_interval = 100 ;
2016-01-28 06:52:09 +01:00
wifi_set_opmode ( STATIONAP_MODE ) ;
2015-09-02 14:41:27 +02:00
wifi_softap_set_config ( & cnf ) ;
}
2015-09-12 18:07:53 +02:00
static void enduser_setup_dns_recv_callback ( void * arg , char * recv_data , unsigned short recv_len )
2015-09-02 14:41:27 +02:00
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , " enduser_setup_dns_recv_callback. " ) ;
2015-09-02 14:41:27 +02:00
struct espconn * callback_espconn = arg ;
struct ip_info ip_info ;
2015-09-19 21:06:56 +02:00
uint32_t qname_len = c_strlen ( & ( recv_data [ 12 ] ) ) + 1 ; // \0=1byte
uint32_t dns_reply_static_len = ( uint32_t ) sizeof ( dns_header ) + ( uint32_t ) sizeof ( dns_body ) + 2 + 4 ; // dns_id=2bytes, ip=4bytes
uint32_t dns_reply_len = dns_reply_static_len + qname_len ;
2015-09-02 14:41:27 +02:00
uint8_t if_mode = wifi_get_opmode ( ) ;
if ( ( if_mode & SOFTAP_MODE ) = = 0 )
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR_VOID ( " dns_recv_callback failed. Interface mode not supported. " , ENDUSER_SETUP_ERR_UNKOWN_ERROR , ENDUSER_SETUP_ERR_FATAL ) ;
2015-09-02 14:41:27 +02:00
}
2015-09-19 21:06:56 +02:00
2015-09-02 14:41:27 +02:00
uint8_t if_index = ( if_mode = = STATION_MODE ? STATION_IF : SOFTAP_IF ) ;
if ( wifi_get_ip_info ( if_index , & ip_info ) = = false )
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR_VOID ( " dns_recv_callback failed. Unable to get interface IP. " , ENDUSER_SETUP_ERR_UNKOWN_ERROR , ENDUSER_SETUP_ERR_FATAL ) ;
2015-09-02 14:41:27 +02:00
}
2015-09-19 21:06:56 +02:00
2015-09-02 14:41:27 +02:00
char * dns_reply = ( char * ) c_malloc ( dns_reply_len ) ;
if ( dns_reply = = NULL )
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR_VOID ( " dns_recv_callback failed. Failed to allocate memory. " , ENDUSER_SETUP_ERR_OUT_OF_MEMORY , ENDUSER_SETUP_ERR_NONFATAL ) ;
2015-09-02 14:41:27 +02:00
}
uint32_t insert_byte = 0 ;
c_memcpy ( & ( dns_reply [ insert_byte ] ) , recv_data , 2 ) ;
insert_byte + = 2 ;
c_memcpy ( & ( dns_reply [ insert_byte ] ) , dns_header , sizeof ( dns_header ) ) ;
insert_byte + = ( uint32_t ) sizeof ( dns_header ) ;
c_memcpy ( & ( dns_reply [ insert_byte ] ) , & ( recv_data [ 12 ] ) , qname_len ) ;
insert_byte + = qname_len ;
c_memcpy ( & ( dns_reply [ insert_byte ] ) , dns_body , sizeof ( dns_body ) ) ;
insert_byte + = ( uint32_t ) sizeof ( dns_body ) ;
c_memcpy ( & ( dns_reply [ insert_byte ] ) , & ( ip_info . ip ) , 4 ) ;
2015-09-19 21:06:56 +02:00
2015-11-12 05:46:26 +01:00
// SDK 1.4.0 changed behaviour, for UDP server need to look up remote ip/port
remot_info * pr = 0 ;
if ( espconn_get_connection_info ( callback_espconn , & pr , 0 ) ! = ESPCONN_OK )
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR_VOID ( " dns_recv_callback failed. Unable to get IP of UDP sender. " , ENDUSER_SETUP_ERR_CONNECTION_NOT_FOUND , ENDUSER_SETUP_ERR_FATAL ) ;
2015-11-12 05:46:26 +01:00
}
callback_espconn - > proto . udp - > remote_port = pr - > remote_port ;
os_memmove ( callback_espconn - > proto . udp - > remote_ip , pr - > remote_ip , 4 ) ;
2015-09-02 14:41:27 +02:00
int8_t err ;
2016-01-28 06:52:09 +01:00
err = espconn_send ( callback_espconn , dns_reply , dns_reply_len ) ;
2015-09-02 14:41:27 +02:00
c_free ( dns_reply ) ;
if ( err = = ESPCONN_MEM )
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR_VOID ( " dns_recv_callback failed. Failed to allocate memory for send. " , ENDUSER_SETUP_ERR_OUT_OF_MEMORY , ENDUSER_SETUP_ERR_FATAL ) ;
2015-09-02 14:41:27 +02:00
}
else if ( err = = ESPCONN_ARG )
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR_VOID ( " dns_recv_callback failed. Can't execute transmission. " , ENDUSER_SETUP_ERR_CONNECTION_NOT_FOUND , ENDUSER_SETUP_ERR_FATAL ) ;
2015-09-02 14:41:27 +02:00
}
else if ( err ! = 0 )
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR_VOID ( " dns_recv_callback failed. espconn_send failed " , ENDUSER_SETUP_ERR_UNKOWN_ERROR , ENDUSER_SETUP_ERR_FATAL ) ;
2015-09-02 14:41:27 +02:00
}
}
2015-09-19 21:06:56 +02:00
static void enduser_setup_free ( void )
2015-09-02 14:41:27 +02:00
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , " enduser_setup_free " ) ;
2015-09-19 21:06:56 +02:00
if ( state = = NULL )
{
return ;
}
if ( state - > espconn_dns_udp ! = NULL )
{
if ( state - > espconn_dns_udp - > proto . udp ! = NULL )
{
c_free ( state - > espconn_dns_udp - > proto . udp ) ;
}
c_free ( state - > espconn_dns_udp ) ;
}
2015-09-02 14:41:27 +02:00
2015-09-19 21:06:56 +02:00
if ( state - > espconn_http_tcp ! = NULL )
2015-09-02 14:41:27 +02:00
{
2015-09-19 21:06:56 +02:00
if ( state - > espconn_http_tcp - > proto . tcp ! = NULL )
2015-09-02 14:41:27 +02:00
{
2015-09-19 21:06:56 +02:00
c_free ( state - > espconn_http_tcp - > proto . tcp ) ;
2015-09-02 14:41:27 +02:00
}
2015-09-19 21:06:56 +02:00
c_free ( state - > espconn_http_tcp ) ;
2015-09-02 14:41:27 +02:00
}
2015-09-19 21:06:56 +02:00
c_free ( state - > http_payload_data ) ;
2016-01-28 06:52:09 +01:00
free_scan_listeners ( ) ;
2015-09-19 21:06:56 +02:00
c_free ( state ) ;
state = NULL ;
2015-09-02 14:41:27 +02:00
}
2015-09-19 21:06:56 +02:00
static int enduser_setup_dns_start ( void )
2015-09-02 14:41:27 +02:00
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , " enduser_setup_dns_start " ) ;
2015-09-02 14:41:27 +02:00
2015-09-19 21:06:56 +02:00
if ( state - > espconn_dns_udp ! = NULL )
2015-09-02 14:41:27 +02:00
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR ( " dns_start failed. Appears to already be started (espconn_dns_udp != NULL). " , ENDUSER_SETUP_ERR_UNKOWN_ERROR , ENDUSER_SETUP_ERR_FATAL ) ;
2015-09-02 14:41:27 +02:00
}
2015-09-19 21:06:56 +02:00
state - > espconn_dns_udp = ( struct espconn * ) c_malloc ( sizeof ( struct espconn ) ) ;
if ( state - > espconn_dns_udp = = NULL )
2015-09-02 14:41:27 +02:00
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR ( " dns_start failed. Memory allocation failed (espconn_dns_udp == NULL). " , ENDUSER_SETUP_ERR_OUT_OF_MEMORY , ENDUSER_SETUP_ERR_FATAL ) ;
2015-09-02 14:41:27 +02:00
}
esp_udp * esp_udp_data = ( esp_udp * ) c_malloc ( sizeof ( esp_udp ) ) ;
if ( esp_udp_data = = NULL )
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR ( " dns_start failed. Memory allocation failed (esp_udp == NULL). " , ENDUSER_SETUP_ERR_OUT_OF_MEMORY , ENDUSER_SETUP_ERR_FATAL ) ;
2015-09-02 14:41:27 +02:00
}
2015-09-19 21:06:56 +02:00
c_memset ( state - > espconn_dns_udp , 0 , sizeof ( struct espconn ) ) ;
2015-09-02 14:41:27 +02:00
c_memset ( esp_udp_data , 0 , sizeof ( esp_udp ) ) ;
2015-09-19 21:06:56 +02:00
state - > espconn_dns_udp - > proto . udp = esp_udp_data ;
state - > espconn_dns_udp - > type = ESPCONN_UDP ;
state - > espconn_dns_udp - > state = ESPCONN_NONE ;
2015-09-02 14:41:27 +02:00
esp_udp_data - > local_port = 53 ;
int8_t err ;
2015-09-19 21:06:56 +02:00
err = espconn_regist_recvcb ( state - > espconn_dns_udp , enduser_setup_dns_recv_callback ) ;
2015-09-02 14:41:27 +02:00
if ( err ! = 0 )
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR ( " dns_start failed. Couldn't add receive callback, unknown error. " , ENDUSER_SETUP_ERR_UNKOWN_ERROR , ENDUSER_SETUP_ERR_FATAL ) ;
2015-09-02 14:41:27 +02:00
}
2015-09-19 21:06:56 +02:00
err = espconn_create ( state - > espconn_dns_udp ) ;
2015-09-02 14:41:27 +02:00
if ( err = = ESPCONN_ISCONN )
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR ( " dns_start failed. Couldn't create connection, already listening for that connection. " , ENDUSER_SETUP_ERR_SOCKET_ALREADY_OPEN , ENDUSER_SETUP_ERR_FATAL ) ;
2015-09-02 14:41:27 +02:00
}
else if ( err = = ESPCONN_MEM )
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR ( " dns_start failed. Couldn't create connection, out of memory. " , ENDUSER_SETUP_ERR_OUT_OF_MEMORY , ENDUSER_SETUP_ERR_FATAL ) ;
2015-09-02 14:41:27 +02:00
}
else if ( err ! = 0 )
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_ERROR ( " dns_start failed. Couldn't create connection, unknown error. " , ENDUSER_SETUP_ERR_UNKOWN_ERROR , ENDUSER_SETUP_ERR_FATAL ) ;
2015-09-02 14:41:27 +02:00
}
2015-09-19 21:06:56 +02:00
return 0 ;
2015-09-02 14:41:27 +02:00
}
2015-09-12 18:07:53 +02:00
static void enduser_setup_dns_stop ( void )
2015-09-02 14:41:27 +02:00
{
2016-01-28 06:52:09 +01:00
ENDUSER_SETUP_DEBUG ( lua_getstate ( ) , " enduser_setup_dns_stop " ) ;
2015-09-02 14:41:27 +02:00
2016-03-01 08:33:11 +01:00
if ( state ! = NULL & & state - > espconn_dns_udp ! = NULL )
2015-09-02 14:41:27 +02:00
{
2015-09-19 21:06:56 +02:00
espconn_delete ( state - > espconn_dns_udp ) ;
2015-09-02 14:41:27 +02:00
}
2015-09-19 21:06:56 +02:00
}
2015-09-02 14:41:27 +02:00
2015-09-19 21:06:56 +02:00
static int enduser_setup_init ( lua_State * L )
{
ENDUSER_SETUP_DEBUG ( L , " enduser_setup_init " ) ;
if ( state ! = NULL )
2015-09-02 14:41:27 +02:00
{
2016-01-28 06:52:09 +01:00
enduser_setup_error ( L , " init failed. Appears to already be started. " , ENDUSER_SETUP_ERR_UNKOWN_ERROR ) ;
2015-09-19 21:06:56 +02:00
return ENDUSER_SETUP_ERR_UNKOWN_ERROR ;
2015-09-02 14:41:27 +02:00
}
2015-09-19 21:06:56 +02:00
2016-01-28 06:52:09 +01:00
state = ( enduser_setup_state_t * ) os_zalloc ( sizeof ( enduser_setup_state_t ) ) ;
2015-09-19 21:06:56 +02:00
if ( state = = NULL )
{
2016-01-28 06:52:09 +01:00
enduser_setup_error ( L , " init failed. Unable to allocate memory. " , ENDUSER_SETUP_ERR_OUT_OF_MEMORY ) ;
2015-09-19 21:06:56 +02:00
return ENDUSER_SETUP_ERR_OUT_OF_MEMORY ;
}
c_memset ( state , 0 , sizeof ( enduser_setup_state_t ) ) ;
state - > lua_connected_cb_ref = LUA_NOREF ;
state - > lua_err_cb_ref = LUA_NOREF ;
state - > lua_dbg_cb_ref = LUA_NOREF ;
if ( ! lua_isnoneornil ( L , 1 ) )
{
lua_pushvalue ( L , 1 ) ;
state - > lua_connected_cb_ref = luaL_ref ( L , LUA_REGISTRYINDEX ) ;
}
else
{
state - > lua_connected_cb_ref = LUA_NOREF ;
}
if ( ! lua_isnoneornil ( L , 2 ) )
{
lua_pushvalue ( L , 2 ) ;
state - > lua_err_cb_ref = luaL_ref ( L , LUA_REGISTRYINDEX ) ;
}
else
{
state - > lua_err_cb_ref = LUA_NOREF ;
}
if ( ! lua_isnoneornil ( L , 3 ) )
2015-09-02 14:41:27 +02:00
{
2015-09-19 21:06:56 +02:00
lua_pushvalue ( L , 3 ) ;
state - > lua_dbg_cb_ref = luaL_ref ( L , LUA_REGISTRYINDEX ) ;
}
else
{
state - > lua_dbg_cb_ref = LUA_NOREF ;
2015-09-02 14:41:27 +02:00
}
2015-09-19 21:06:56 +02:00
return 0 ;
2015-09-02 14:41:27 +02:00
}
2016-01-28 06:52:09 +01:00
static int enduser_setup_manual ( lua_State * L )
{
if ( ! lua_isnoneornil ( L , 1 ) )
manual = lua_toboolean ( L , 1 ) ;
lua_pushboolean ( L , manual ) ;
return 1 ;
}
2015-09-19 21:06:56 +02:00
static int enduser_setup_start ( lua_State * L )
2015-09-02 14:41:27 +02:00
{
2015-09-19 21:06:56 +02:00
ENDUSER_SETUP_DEBUG ( L , " enduser_setup_start " ) ;
2016-03-01 07:54:10 +01:00
if ( ! do_station_cfg_handle )
do_station_cfg_handle = task_get_id ( do_station_cfg ) ;
2015-09-19 21:06:56 +02:00
if ( enduser_setup_init ( L ) )
2016-01-28 06:52:09 +01:00
goto failed ;
if ( ! manual )
2015-09-19 21:06:56 +02:00
{
2016-01-28 06:52:09 +01:00
enduser_setup_check_station_start ( ) ;
enduser_setup_ap_start ( ) ;
2015-09-19 21:06:56 +02:00
}
if ( enduser_setup_dns_start ( ) )
2016-01-28 06:52:09 +01:00
goto failed ;
2015-09-19 21:06:56 +02:00
if ( enduser_setup_http_start ( ) )
2016-01-28 06:52:09 +01:00
goto failed ;
goto out ;
2015-09-16 14:56:44 +02:00
2016-01-28 06:52:09 +01:00
failed :
enduser_setup_stop ( L ) ;
out :
2015-09-02 14:41:27 +02:00
return 0 ;
}
2015-09-12 18:07:53 +02:00
static int enduser_setup_stop ( lua_State * L )
2015-09-02 14:41:27 +02:00
{
2016-01-28 06:52:09 +01:00
if ( ! manual )
{
enduser_setup_check_station_stop ( ) ;
enduser_setup_ap_stop ( ) ;
}
2015-09-02 14:41:27 +02:00
enduser_setup_dns_stop ( ) ;
enduser_setup_http_stop ( ) ;
2015-09-19 21:06:56 +02:00
enduser_setup_free ( ) ;
2015-09-02 14:41:27 +02:00
return 0 ;
}
2015-12-16 06:04:58 +01:00
static const LUA_REG_TYPE enduser_setup_map [ ] = {
2016-01-28 06:52:09 +01:00
{ LSTRKEY ( " manual " ) , LFUNCVAL ( enduser_setup_manual ) } ,
2015-09-02 14:41:27 +02:00
{ LSTRKEY ( " start " ) , LFUNCVAL ( enduser_setup_start ) } ,
{ LSTRKEY ( " stop " ) , LFUNCVAL ( enduser_setup_stop ) } ,
{ LNILKEY , LNILVAL }
} ;
2015-12-16 06:04:58 +01:00
NODEMCU_MODULE ( ENDUSER_SETUP , " enduser_setup " , enduser_setup_map , NULL ) ;