Commit 04ce0adf authored by Marcel Stör's avatar Marcel Stör Committed by GitHub
Browse files

Next 1.5.4.1 master drop (#1627)

* add u8g.fb_rle display

* move comm drivers to u8g_glue.c

* disable fb_rle per default

* implement file.size for spiffs (#1516)

Another bug squashed!

* Fix start-up race between UART & start_lua. (#1522)

Input during startup (especially while doing initial filesystem format)
ran the risk of filling up the task queue, preventing the start_lua task
from being queued, and hence NodeMCU would not start up that time.

* Reimplemented esp_init_data_default.

To work around the pesky "rf_cal[0] !=0x05" hang when booting on a chip
which doesn't have esp_init_data written to it.

It is no longer possible to do the writing of the esp_init_data_default
from within nodemcu_init(), as the SDK now hangs long before it gets
there.  As such, I've had to reimplement this in our user_start_trampoline
and get it all done before the SDK has a chance to look for the init data.
It's unfortunate that we have to spend IRAM on this, but I see no better
alternative at this point.

* Replace hardcoded init data with generated data from SDK

The esp_init_data_default.bin is now extracted from the SDK (and its
patch file, if present), and the contents are automatically embedded
into user_main.o.

* Rework flashing instructions

Clarifies issues around SDK init data and hopefully clears up some
confusion, when paired with the esp_init_data_default changes in
NodeMCU.

* Fix typo

* Fixes the gpio.serout problem from #1534 (#1535)

* Fix some issues in gpio.serout
* Minor cleanup

* fix dereferencing NULL pointer in vfs_errno() (#1539)

* add map ids for flash sizes 32m-c2, 64m, 128m in user_rf_cal_sector_set() (#1529)

* Somfy/TELIS driver (#1521)

* Reduced LUAL_BUFFERSIZE to 256. Should free up some stack (#1530)

* avoid task queue overrun for serial input (#1540)

Thank you.

* Increase irom0_0_seg size for PR build

* Improve reliability of FS detection. (#1528)

* Version to make filesystem detection more reliable
* Improve bad fs detection

* Version of printf that doesn't suffer from buffer overflows (#1564)

* Small improvement to http client (#1558)

* Remove luaL_buffer from file_g_read() (#1541)

* remove luaL_buffer from file_g_read()
- avoid memory leak when function gets terminated by lua_error
- skip scanning for end_char when reading until EOF
* attempt to free memory in any case

* Change HTTP failures from debug to error messages (#1568)

* Change HTTP failures from debug to error messages

* Add tag to HTTP error messages

* Create macro for error msg and improve dbg msg

* Add ssd1306_128x32 for U8G (#1571)

* Update CONTRIBUTING.md

* Add support to mix ws2812.buffer objects.  (#1575)

* Add load/dump/mix/power operations on the buffer object
* Calculate the pixel value in mix and then clip to the range.
* Fixed the two wrong userdata types
* Added a couple more useful methods
* Add support for shifting a piece of the buffer.
* Fix a minor bug with offset shifts

* Update to the wifi module (#1497)

* Removed inline documentation for several functions and update comments
Since documentation is now part of the repository, the inline
documentation just adds to the already huge wifi.c

* Wifi module: add new functionality, update documentation

Functions Added:
wifi.getdefaultmode(): returns default wifi opmode
wifi.sta.apchange(): select alternate cached AP
wifi.sta.apinfo(): get cached AP list 
wifi.sta.aplimit(): set cached AP limit
wifi.sta.getapindex(): get index of currently configured AP
wifi.sta.getdefaultconfig(): get default station configuration
wifi.ap.getdefaultconfig(): get default AP configuration

functions modified:
wifi.setmode: saving mode to flash is now optional
wifi.sta.config: now accepts table as an argument and save config to
flash is now optional
wifi.sta.getconfig: added option to return table
wifi.ap.config: save config to flash is now optional
wifi.ap.getconfig: added option to return table

Documentation changes:
- Modified documentation to reflect above changes
- Removed unnecessary inline documentation from `wifi.c` 
- Updated documentation for `wifi.sta.disconnect`to address issue #1480 
- Fixed inaccurate documentation for function `wifi.sleeptype`
- Added more details to `wifi.nullmodesleep()`

* Move function `wifi.sleeptype()` to `wifi.sta.sleeptype()`

* Fixed problem where wifi.x.getconfig() returned invalid strings when
ssid or password were set to maximum length.

* fix error in documentation for `wifi.sta.getapindex`

* Renamed some wifi functions
wifi.sta.apinfo -> getapinfo
wifi.sta.aplimit -> setaplimit 
wifi.sta.apchange -> changeap

also organized the wifi_station_map array

* Make the MQTT PING functionality work better. (#1557)

Deal with flow control stopped case

* Implement object model for files (#1532)

* Eus channelfix (#1583)

Squashed commits included:

Bug fixes and final implementation
- Added Content-Length: 0 to all headers
- Endpoint name checks not using trailing space so cache-busting techniques can be used (i.e., append a nonce to the URL)
- Track when connecting so APList scan doesn't take place during (which changes the channel)
- More debugging output added to assist in tracking down some issues

Added /status.json endpoint for phone apps/XHR to get JSON response

Station Status caching for wifi channel workaround + AJAX/CORS
- During checkstation poll, cache the last station status
- Shut down the station if status = 2,3,4 and channel is different than SoftAP
- Add Access-Control-Allow-Origin: * to endpoint responses used by a service
- Add a /setwifi GET endpoint for phone apps/XHR to use (same parameters as /update endpoint). Returns a JSON response containing chip id and status code.
- Add handler for OPTIONS verb (needed for CORS support)

Wi-Fi Channel Issue Workaround
- Do a site survey upon startup, set SoftAP channel to the strongest rssi's channel
- Compare successful station connect channel to SoftAP's. If different, then defer the Lua success callback to the end. Shut down Station and start the SoftAP back up with original channel.
- After the 10 second shutdown timer fires, check to see if success callback was already called. If not, then call it while starting the Station back up.

HTTP Response and DNS enhancements
- If DNS's UDP buffer fills up, keep going as non-fatal. It's UDP and not guaranteed anyways. I've seen this occur when connecting a PC to the SoftAP and every open program tries to phone home at the same time, overwhelming the EUS DNS server.
- Support for detecting/handling pre-gzipped `enduser_setup.html` (and `http_html_backup`) payload. Nice for keeping the size of the `state->http_payload_data` as small as possible (also makes minimization not as critical)
- Corrected misuse of HTTP 401 response status (changed one occurrence to 400/Bad Request, and changed another to 405/Method Not Allowed)

* Normalized formatting (tabs-to-spaces)
* Added documentation
* Corrected misuse of strlen for binary (gzip) data.
* Added NULL check after malloc

* fix vfs_lseek() result checking in enduser_setup and clarify SPIFFS_lseek() return value (#1570)

* Fix link

* Overhaul flashing docs once again (#1587)

* Add chapter about determine flash size plus small fixes
* Rewrite esptool.py chapter, move flash size chapter to end

* i2c - allow slave stretching SCL (just loop and check) (#1589)

* Add note on dev board usage of SPI bus 0 (#1591)

* Turn SPI busses note to admonition note

* support for custom websocket headers (#1573)

Looks good to me. Thank you.

Also:
 - allow for '\0's in received messages

* add client:config for setting websocket headers

Also:
 - headers are case-insensitive now

* fix docs

* fix typo

* remove unnecessary luaL_argcheck calls

* replace os_sprintf with simple string copy

* Handle error condition in file.read() (#1599)

* handle error condition in file.read()

* simplify loop initialization

* Fix macro as suggested in #1548

* Extract and hoist net receive callbacks

This is done to avoid the accidental upval binding

* Fix typo at rtctime.md

rtctime.dsleep -> rtctime.dsleep_aligned
parent 7b83bbb2
...@@ -4,16 +4,22 @@ ...@@ -4,16 +4,22 @@
The following is a set of guidelines for contributing to NodeMCU on GitHub. These are just guidelines, not rules, use your best judgment and feel free to propose changes to this document in a pull request. The following is a set of guidelines for contributing to NodeMCU on GitHub. These are just guidelines, not rules, use your best judgment and feel free to propose changes to this document in a pull request.
It is appreciated but optional if you raise an issue _before_ you start changing NodeMCU, discussing the proposed change; emphasing that the you are proposing to develop the patch yourself, and outlining the strategy for implementation. This type of discussion is what we should be doing on the issues list and it is better to do this before or in parallel to developing the patch rather than having "you should have done it this way" type of feedback on the PR itself. It is appreciated if you raise an issue _before_ you start changing NodeMCU, discussing the proposed change; emphasing that the you are proposing to develop the patch yourself, and outlining the strategy for implementation. This type of discussion is what we should be doing on the issues list and it is better to do this before or in parallel to developing the patch rather than having "you should have done it this way" type of feedback on the PR itself.
### Table Of Contents ### Table Of Contents
* [General remarks](#general-remarks)
* [Development environment setup](#development-environment-setup) * [Development environment setup](#development-environment-setup)
* [Writing Documentation](#writing-documentation) * [Writing Documentation](#writing-documentation)
* [Working with Git and GitHub](#working-with-git-and-github) * [Working with Git and GitHub](#working-with-git-and-github)
* [General flow](#general-flow) * [General flow](#general-flow)
* [Keeping your fork in sync](#keeping-your-fork-in-sync) * [Keeping your fork in sync](#keeping-your-fork-in-sync)
* [Commit messages](#commit-messages) * [Commit messages](#commit-messages)
* [For collaborators](#for-collaborators)
* [Handling releases](#handling-release)
## General remarks
We are a friendly and welcoming community and look forward to your contributions. Once your contribution is integrated into this repository we feel responsible for it. Therefore, be prepared for constructive feedback. Before we merge anything we need to ensure that it fits in and is consistent with the rest of NodeMCU.
If you made something really cool but won't spend time to integrate it into this upstream project please still share it in your fork on GitHub. If you mention it in an issues we'll take a look at it anyway.
## Development environment setup ## Development environment setup
Use the platform and tools you feel most comfortable with. There are no constraints imposed by this project. You have (at least) two options to set up the toolchain to build the NodeMCU firmware: Use the platform and tools you feel most comfortable with. There are no constraints imposed by this project. You have (at least) two options to set up the toolchain to build the NodeMCU firmware:
...@@ -52,7 +58,7 @@ Avoid intermediate merge commits. [Rebase](https://www.atlassian.com/git/tutoria ...@@ -52,7 +58,7 @@ Avoid intermediate merge commits. [Rebase](https://www.atlassian.com/git/tutoria
1. `git checkout <branch-name>` 1. `git checkout <branch-name>`
1. Make changes to the code base and commit them using e.g. `git commit -a -m 'Look ma, I did it'` 1. Make changes to the code base and commit them using e.g. `git commit -a -m 'Look ma, I did it'`
1. When you're done: 1. When you're done:
1. [Squash your commits](http://www.andrewconnell.com/blog/squash-multiple-git-commits-into-one). There are [several ways](http://stackoverflow.com/a/5201642/131929) of doing this. 1. Think about [squashing (some of) your commits](http://www.andrewconnell.com/blog/squash-multiple-git-commits-into-one). There are [several ways](http://stackoverflow.com/a/5201642/131929) to do this. There's no need to squash everything into a single commit as GitHub offers to do this when we merge your changes. However, you might want to trim your commit history to relevant chunks.
1. Bring your fork up-to-date with the NodeMCU upstream repo ([see below](#keeping-your-fork-in-sync)). Then rebase your branch on `dev` running `git rebase dev`. 1. Bring your fork up-to-date with the NodeMCU upstream repo ([see below](#keeping-your-fork-in-sync)). Then rebase your branch on `dev` running `git rebase dev`.
1. `git push` 1. `git push`
1. [Create a pull request](https://help.github.com/articles/creating-a-pull-request/) (PR) on GitHub. 1. [Create a pull request](https://help.github.com/articles/creating-a-pull-request/) (PR) on GitHub.
...@@ -90,3 +96,15 @@ Further paragraphs come after blank lines. ...@@ -90,3 +96,15 @@ Further paragraphs come after blank lines.
Don't forget to [reference affected issues](https://help.github.com/articles/closing-issues-via-commit-messages/) in the commit message to have them closed automatically on GitHub. Don't forget to [reference affected issues](https://help.github.com/articles/closing-issues-via-commit-messages/) in the commit message to have them closed automatically on GitHub.
[Amend](https://help.github.com/articles/changing-a-commit-message/) your commit messages if necessary to make sure what the world sees on GitHub is as expressive and meaningful as possible. [Amend](https://help.github.com/articles/changing-a-commit-message/) your commit messages if necessary to make sure what the world sees on GitHub is as expressive and meaningful as possible.
## For collaborators
### Handling releases
- Create a [milestone](https://github.com/nodemcu/nodemcu-firmware/milestones) right after you cut a new release. Give it a meaningful name if you already have an idea what the scope of the upcoming release is going to be. Also set the due date to ~2 months in the future.
- Add this milestone to every PR before you merge it. Also add the milestone to PRs you want to see land in this milestone.
- Add notes to the description of the milestone in the course of the ~2 months it lives.
- Be careful and reluctant to merge PRs once we're past the 6-weeks mark of a milestone. Ideally we don't merge anything in the last 2 weeks.
- Cutting a release
- Create an annotated tag like so: `git tag -a <SDK-version>-master_<yyyyMMdd> -m ""`, `git push --tags`
- Create a new [release](https://github.com/nodemcu/nodemcu-firmware/releases) based on the tag you just pushed. The version name is the same as the tag name.
- Write release notes. Mention breaking changes explicitly. Since every PR that went into this release is linked to from the milestone it should be fairly easy to include important changes in the release notes.
...@@ -207,14 +207,14 @@ sdk_patched: sdk_extracted $(TOP_DIR)/sdk/.patched-$(SDK_VER) ...@@ -207,14 +207,14 @@ sdk_patched: sdk_extracted $(TOP_DIR)/sdk/.patched-$(SDK_VER)
$(TOP_DIR)/sdk/.extracted-$(SDK_BASE_VER): $(TOP_DIR)/cache/esp_iot_sdk_v$(SDK_FILE_VER).zip $(TOP_DIR)/sdk/.extracted-$(SDK_BASE_VER): $(TOP_DIR)/cache/esp_iot_sdk_v$(SDK_FILE_VER).zip
mkdir -p "$(dir $@)" mkdir -p "$(dir $@)"
(cd "$(dir $@)" && rm -fr esp_iot_sdk_v$(SDK_VER) ESP8266_NONOS_SDK && unzip $(TOP_DIR)/cache/esp_iot_sdk_v$(SDK_FILE_VER).zip ESP8266_NONOS_SDK/lib/* ESP8266_NONOS_SDK/ld/eagle.rom.addr.v6.ld ESP8266_NONOS_SDK/include/* ) (cd "$(dir $@)" && rm -fr esp_iot_sdk_v$(SDK_VER) ESP8266_NONOS_SDK && unzip $(TOP_DIR)/cache/esp_iot_sdk_v$(SDK_FILE_VER).zip ESP8266_NONOS_SDK/lib/* ESP8266_NONOS_SDK/ld/eagle.rom.addr.v6.ld ESP8266_NONOS_SDK/include/* ESP8266_NONOS_SDK/bin/esp_init_data_default.bin)
mv $(dir $@)/ESP8266_NONOS_SDK $(dir $@)/esp_iot_sdk_v$(SDK_VER) mv $(dir $@)/ESP8266_NONOS_SDK $(dir $@)/esp_iot_sdk_v$(SDK_VER)
rm -f $(SDK_DIR)/lib/liblwip.a rm -f $(SDK_DIR)/lib/liblwip.a
touch $@ touch $@
$(TOP_DIR)/sdk/.patched-$(SDK_VER): $(TOP_DIR)/cache/esp_iot_sdk_v$(SDK_PATCH_VER).zip $(TOP_DIR)/sdk/.patched-$(SDK_VER): $(TOP_DIR)/cache/esp_iot_sdk_v$(SDK_PATCH_VER).zip
mkdir -p "$(dir $@)/patch" mkdir -p "$(dir $@)/patch"
(cd "$(dir $@)/patch" && unzip $(TOP_DIR)/cache/esp_iot_sdk_v$(SDK_PATCH_VER)*.zip *.a && mv *.a $(SDK_DIR)/lib/) (cd "$(dir $@)/patch" && unzip $(TOP_DIR)/cache/esp_iot_sdk_v$(SDK_PATCH_VER)*.zip *.a esp_init_data_default.bin && mv *.a $(SDK_DIR)/lib/ && mv esp_init_data_default.bin $(SDK_DIR)/bin/)
rmdir $(dir $@)/patch rmdir $(dir $@)/patch
rm -f $(SDK_DIR)/lib/liblwip.a rm -f $(SDK_DIR)/lib/liblwip.a
touch $@ touch $@
......
...@@ -33,6 +33,8 @@ LOCAL uint8 pinSCL = 15; ...@@ -33,6 +33,8 @@ LOCAL uint8 pinSCL = 15;
LOCAL void ICACHE_FLASH_ATTR LOCAL void ICACHE_FLASH_ATTR
i2c_master_setDC(uint8 SDA, uint8 SCL) i2c_master_setDC(uint8 SDA, uint8 SCL)
{ {
uint8 sclLevel;
SDA &= 0x01; SDA &= 0x01;
SCL &= 0x01; SCL &= 0x01;
m_nLastSDA = SDA; m_nLastSDA = SDA;
...@@ -47,6 +49,11 @@ i2c_master_setDC(uint8 SDA, uint8 SCL) ...@@ -47,6 +49,11 @@ i2c_master_setDC(uint8 SDA, uint8 SCL)
} else { } else {
I2C_MASTER_SDA_HIGH_SCL_HIGH(); I2C_MASTER_SDA_HIGH_SCL_HIGH();
} }
if(1 == SCL) {
do {
sclLevel = GPIO_INPUT_GET(GPIO_ID_PIN(I2C_MASTER_SCL_GPIO));
} while(sclLevel == 0);
}
} }
/****************************************************************************** /******************************************************************************
......
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
// For event signalling // For event signalling
static task_handle_t sig = 0; static task_handle_t sig = 0;
static uint8 *sig_flag;
static uint8 isr_flag = 0;
// UartDev is defined and initialized in rom code. // UartDev is defined and initialized in rom code.
extern UartDevice UartDev; extern UartDevice UartDev;
...@@ -277,8 +279,12 @@ uart0_rx_intr_handler(void *para) ...@@ -277,8 +279,12 @@ uart0_rx_intr_handler(void *para)
got_input = true; got_input = true;
} }
if (got_input && sig) if (got_input && sig) {
task_post_low (sig, false); if (isr_flag == *sig_flag) {
isr_flag ^= 0x01;
task_post_low (sig, 0x8000 | isr_flag << 14 | false);
}
}
} }
static void static void
...@@ -316,21 +322,21 @@ uart_stop_autobaud() ...@@ -316,21 +322,21 @@ uart_stop_autobaud()
* Description : user interface for init uart * Description : user interface for init uart
* Parameters : UartBautRate uart0_br - uart0 bautrate * Parameters : UartBautRate uart0_br - uart0 bautrate
* UartBautRate uart1_br - uart1 bautrate * UartBautRate uart1_br - uart1 bautrate
* uint8 task_prio - task priority to signal on input
* os_signal_t sig_input - signal to post * os_signal_t sig_input - signal to post
* uint8 *flag_input - flag of consumer task
* Returns : NONE * Returns : NONE
*******************************************************************************/ *******************************************************************************/
void ICACHE_FLASH_ATTR void ICACHE_FLASH_ATTR
uart_init(UartBautRate uart0_br, UartBautRate uart1_br, os_signal_t sig_input) uart_init(UartBautRate uart0_br, UartBautRate uart1_br, os_signal_t sig_input, uint8 *flag_input)
{ {
sig = sig_input; sig = sig_input;
sig_flag = flag_input;
// rom use 74880 baut_rate, here reinitialize // rom use 74880 baut_rate, here reinitialize
UartDev.baut_rate = uart0_br; UartDev.baut_rate = uart0_br;
uart_config(UART0); uart_config(UART0);
UartDev.baut_rate = uart1_br; UartDev.baut_rate = uart1_br;
uart_config(UART1); uart_config(UART1);
ETS_UART_INTR_ENABLE();
#ifdef BIT_RATE_AUTOBAUD #ifdef BIT_RATE_AUTOBAUD
uart_init_autobaud(0); uart_init_autobaud(0);
#endif #endif
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
*/ */
#include "osapi.h" #include "osapi.h"
#include "../libc/c_stdio.h"
#include "user_interface.h" #include "user_interface.h"
#include "espconn.h" #include "espconn.h"
#include "mem.h" #include "mem.h"
...@@ -94,7 +95,7 @@ static int ICACHE_FLASH_ATTR http_chunked_decode( const char * chunked, char * d ...@@ -94,7 +95,7 @@ static int ICACHE_FLASH_ATTR http_chunked_decode( const char * chunked, char * d
char * endstr; char * endstr;
/* [chunk-size] */ /* [chunk-size] */
i = strtoul( str + j, NULL, 16 ); i = strtoul( str + j, NULL, 16 );
HTTPCLIENT_DEBUG( "Chunk Size:%d\r\n", i ); HTTPCLIENT_DEBUG( "Chunk Size:%d", i );
if ( i <= 0 ) if ( i <= 0 )
break; break;
/* [chunk-size-end-ptr] */ /* [chunk-size-end-ptr] */
...@@ -137,7 +138,7 @@ static void ICACHE_FLASH_ATTR http_receive_callback( void * arg, char * buf, uns ...@@ -137,7 +138,7 @@ static void ICACHE_FLASH_ATTR http_receive_callback( void * arg, char * buf, uns
char * new_buffer; char * new_buffer;
if ( new_size > BUFFER_SIZE_MAX || NULL == (new_buffer = (char *) os_malloc( new_size ) ) ) if ( new_size > BUFFER_SIZE_MAX || NULL == (new_buffer = (char *) os_malloc( new_size ) ) )
{ {
HTTPCLIENT_DEBUG( "Response too long (%d)\n", new_size ); HTTPCLIENT_ERR( "Response too long (%d)", new_size );
req->buffer[0] = '\0'; /* Discard the buffer to avoid using an incomplete response. */ req->buffer[0] = '\0'; /* Discard the buffer to avoid using an incomplete response. */
if ( req->secure ) if ( req->secure )
espconn_secure_disconnect( conn ); espconn_secure_disconnect( conn );
...@@ -163,12 +164,12 @@ static void ICACHE_FLASH_ATTR http_send_callback( void * arg ) ...@@ -163,12 +164,12 @@ static void ICACHE_FLASH_ATTR http_send_callback( void * arg )
if ( req->post_data == NULL ) if ( req->post_data == NULL )
{ {
HTTPCLIENT_DEBUG( "All sent\n" ); HTTPCLIENT_DEBUG( "All sent" );
} }
else else
{ {
/* The headers were sent, now send the contents. */ /* The headers were sent, now send the contents. */
HTTPCLIENT_DEBUG( "Sending request body\n" ); HTTPCLIENT_DEBUG( "Sending request body" );
if ( req->secure ) if ( req->secure )
espconn_secure_send( conn, (uint8_t *) req->post_data, strlen( req->post_data ) ); espconn_secure_send( conn, (uint8_t *) req->post_data, strlen( req->post_data ) );
else else
...@@ -181,7 +182,7 @@ static void ICACHE_FLASH_ATTR http_send_callback( void * arg ) ...@@ -181,7 +182,7 @@ static void ICACHE_FLASH_ATTR http_send_callback( void * arg )
static void ICACHE_FLASH_ATTR http_connect_callback( void * arg ) static void ICACHE_FLASH_ATTR http_connect_callback( void * arg )
{ {
HTTPCLIENT_DEBUG( "Connected\n" ); HTTPCLIENT_DEBUG( "Connected" );
struct espconn * conn = (struct espconn *) arg; struct espconn * conn = (struct espconn *) arg;
request_args_t * req = (request_args_t *) conn->reverse; request_args_t * req = (request_args_t *) conn->reverse;
espconn_regist_recvcb( conn, http_receive_callback ); espconn_regist_recvcb( conn, http_receive_callback );
...@@ -250,7 +251,7 @@ static void ICACHE_FLASH_ATTR http_connect_callback( void * arg ) ...@@ -250,7 +251,7 @@ static void ICACHE_FLASH_ATTR http_connect_callback( void * arg )
} }
req->headers = NULL; req->headers = NULL;
HTTPCLIENT_DEBUG( "Sending request header\n" ); HTTPCLIENT_DEBUG( "Sending request header" );
} }
static void http_free_req( request_args_t * req) static void http_free_req( request_args_t * req)
...@@ -272,7 +273,7 @@ static void http_free_req( request_args_t * req) ...@@ -272,7 +273,7 @@ static void http_free_req( request_args_t * req)
static void ICACHE_FLASH_ATTR http_disconnect_callback( void * arg ) static void ICACHE_FLASH_ATTR http_disconnect_callback( void * arg )
{ {
HTTPCLIENT_DEBUG( "Disconnected\n" ); HTTPCLIENT_DEBUG( "Disconnected" );
struct espconn *conn = (struct espconn *) arg; struct espconn *conn = (struct espconn *) arg;
if ( conn == NULL ) if ( conn == NULL )
...@@ -295,7 +296,7 @@ static void ICACHE_FLASH_ATTR http_disconnect_callback( void * arg ) ...@@ -295,7 +296,7 @@ static void ICACHE_FLASH_ATTR http_disconnect_callback( void * arg )
if ( req->buffer == NULL ) if ( req->buffer == NULL )
{ {
HTTPCLIENT_DEBUG( "Buffer probably shouldn't be NULL\n" ); HTTPCLIENT_DEBUG( "Buffer probably shouldn't be NULL" );
} }
else if ( req->buffer[0] != '\0' ) else if ( req->buffer[0] != '\0' )
{ {
...@@ -305,7 +306,7 @@ static void ICACHE_FLASH_ATTR http_disconnect_callback( void * arg ) ...@@ -305,7 +306,7 @@ static void ICACHE_FLASH_ATTR http_disconnect_callback( void * arg )
if (( os_strncmp( req->buffer, version_1_0, strlen( version_1_0 ) ) != 0 ) && if (( os_strncmp( req->buffer, version_1_0, strlen( version_1_0 ) ) != 0 ) &&
( os_strncmp( req->buffer, version_1_1, strlen( version_1_1 ) ) != 0 )) ( os_strncmp( req->buffer, version_1_1, strlen( version_1_1 ) ) != 0 ))
{ {
HTTPCLIENT_DEBUG( "Invalid version in %s\n", req->buffer ); HTTPCLIENT_ERR( "Invalid version in %s", req->buffer );
} }
else else
{ {
...@@ -326,7 +327,7 @@ static void ICACHE_FLASH_ATTR http_disconnect_callback( void * arg ) ...@@ -326,7 +327,7 @@ static void ICACHE_FLASH_ATTR http_disconnect_callback( void * arg )
char *locationOffsetEnd = (char *) os_strstr(locationOffset, "\r\n"); char *locationOffsetEnd = (char *) os_strstr(locationOffset, "\r\n");
if ( locationOffsetEnd == NULL ) { if ( locationOffsetEnd == NULL ) {
HTTPCLIENT_DEBUG( "Found Location header but was incomplete\n" ); HTTPCLIENT_ERR( "Found Location header but was incomplete" );
http_status = -1; http_status = -1;
} else { } else {
*locationOffsetEnd = '\0'; *locationOffsetEnd = '\0';
...@@ -371,7 +372,7 @@ static void ICACHE_FLASH_ATTR http_disconnect_callback( void * arg ) ...@@ -371,7 +372,7 @@ static void ICACHE_FLASH_ATTR http_disconnect_callback( void * arg )
return; return;
} }
} else { } else {
HTTPCLIENT_DEBUG("Too many redirections\n"); HTTPCLIENT_ERR("Too many redirections");
http_status = -1; http_status = -1;
} }
} else { } else {
...@@ -379,7 +380,7 @@ static void ICACHE_FLASH_ATTR http_disconnect_callback( void * arg ) ...@@ -379,7 +380,7 @@ static void ICACHE_FLASH_ATTR http_disconnect_callback( void * arg )
if (NULL == body) { if (NULL == body) {
/* Find missing body */ /* Find missing body */
HTTPCLIENT_DEBUG("Body shouldn't be NULL\n"); HTTPCLIENT_ERR("Body shouldn't be NULL");
/* To avoid NULL body */ /* To avoid NULL body */
body = ""; body = "";
} else { } else {
...@@ -411,16 +412,9 @@ static void ICACHE_FLASH_ATTR http_disconnect_callback( void * arg ) ...@@ -411,16 +412,9 @@ static void ICACHE_FLASH_ATTR http_disconnect_callback( void * arg )
} }
static void ICACHE_FLASH_ATTR http_error_callback( void *arg, sint8 errType )
{
HTTPCLIENT_DEBUG( "Disconnected with error\n" );
http_disconnect_callback( arg );
}
static void ICACHE_FLASH_ATTR http_timeout_callback( void *arg ) static void ICACHE_FLASH_ATTR http_timeout_callback( void *arg )
{ {
HTTPCLIENT_DEBUG( "Connection timeout\n" ); HTTPCLIENT_ERR( "Connection timeout" );
struct espconn * conn = (struct espconn *) arg; struct espconn * conn = (struct espconn *) arg;
if ( conn == NULL ) if ( conn == NULL )
{ {
...@@ -439,13 +433,20 @@ static void ICACHE_FLASH_ATTR http_timeout_callback( void *arg ) ...@@ -439,13 +433,20 @@ static void ICACHE_FLASH_ATTR http_timeout_callback( void *arg )
} }
static void ICACHE_FLASH_ATTR http_error_callback( void *arg, sint8 errType )
{
HTTPCLIENT_ERR( "Disconnected with error: %d", errType );
http_timeout_callback( arg );
}
static void ICACHE_FLASH_ATTR http_dns_callback( const char * hostname, ip_addr_t * addr, void * arg ) static void ICACHE_FLASH_ATTR http_dns_callback( const char * hostname, ip_addr_t * addr, void * arg )
{ {
request_args_t * req = (request_args_t *) arg; request_args_t * req = (request_args_t *) arg;
if ( addr == NULL ) if ( addr == NULL )
{ {
HTTPCLIENT_DEBUG( "DNS failed for %s\n", hostname ); HTTPCLIENT_ERR( "DNS failed for %s", hostname );
if ( req->callback_handle != NULL ) if ( req->callback_handle != NULL )
{ {
req->callback_handle( "", -1, "" ); req->callback_handle( "", -1, "" );
...@@ -454,7 +455,7 @@ static void ICACHE_FLASH_ATTR http_dns_callback( const char * hostname, ip_addr_ ...@@ -454,7 +455,7 @@ static void ICACHE_FLASH_ATTR http_dns_callback( const char * hostname, ip_addr_
} }
else else
{ {
HTTPCLIENT_DEBUG( "DNS found %s " IPSTR "\n", hostname, IP2STR( addr ) ); HTTPCLIENT_DEBUG( "DNS found %s " IPSTR, hostname, IP2STR( addr ) );
struct espconn * conn = (struct espconn *) os_zalloc( sizeof(struct espconn) ); struct espconn * conn = (struct espconn *) os_zalloc( sizeof(struct espconn) );
conn->type = ESPCONN_TCP; conn->type = ESPCONN_TCP;
...@@ -489,7 +490,7 @@ static void ICACHE_FLASH_ATTR http_dns_callback( const char * hostname, ip_addr_ ...@@ -489,7 +490,7 @@ static void ICACHE_FLASH_ATTR http_dns_callback( const char * hostname, ip_addr_
void ICACHE_FLASH_ATTR http_raw_request( const char * hostname, int port, bool secure, const char * method, const char * path, const char * headers, const char * post_data, http_callback_t callback_handle, int redirect_follow_count ) void ICACHE_FLASH_ATTR http_raw_request( const char * hostname, int port, bool secure, const char * method, const char * path, const char * headers, const char * post_data, http_callback_t callback_handle, int redirect_follow_count )
{ {
HTTPCLIENT_DEBUG( "DNS request\n" ); HTTPCLIENT_DEBUG( "DNS request" );
request_args_t * req = (request_args_t *) os_zalloc( sizeof(request_args_t) ); request_args_t * req = (request_args_t *) os_zalloc( sizeof(request_args_t) );
req->hostname = esp_strdup( hostname ); req->hostname = esp_strdup( hostname );
...@@ -512,7 +513,7 @@ void ICACHE_FLASH_ATTR http_raw_request( const char * hostname, int port, bool s ...@@ -512,7 +513,7 @@ void ICACHE_FLASH_ATTR http_raw_request( const char * hostname, int port, bool s
if ( error == ESPCONN_INPROGRESS ) if ( error == ESPCONN_INPROGRESS )
{ {
HTTPCLIENT_DEBUG( "DNS pending\n" ); HTTPCLIENT_DEBUG( "DNS pending" );
} }
else if ( error == ESPCONN_OK ) else if ( error == ESPCONN_OK )
{ {
...@@ -523,9 +524,9 @@ void ICACHE_FLASH_ATTR http_raw_request( const char * hostname, int port, bool s ...@@ -523,9 +524,9 @@ void ICACHE_FLASH_ATTR http_raw_request( const char * hostname, int port, bool s
{ {
if ( error == ESPCONN_ARG ) if ( error == ESPCONN_ARG )
{ {
HTTPCLIENT_DEBUG( "DNS arg error %s\n", hostname ); HTTPCLIENT_ERR( "DNS arg error %s", hostname );
}else { }else {
HTTPCLIENT_DEBUG( "DNS error code %d\n", error ); HTTPCLIENT_ERR( "DNS error code %d", error );
} }
http_dns_callback( hostname, NULL, req ); /* Handle all DNS errors the same way. */ http_dns_callback( hostname, NULL, req ); /* Handle all DNS errors the same way. */
} }
...@@ -561,7 +562,7 @@ void ICACHE_FLASH_ATTR http_request( const char * url, const char * method, cons ...@@ -561,7 +562,7 @@ void ICACHE_FLASH_ATTR http_request( const char * url, const char * method, cons
} }
else else
{ {
HTTPCLIENT_DEBUG( "URL is not HTTP or HTTPS %s\n", url ); HTTPCLIENT_ERR( "URL is not HTTP or HTTPS %s", url );
return; return;
} }
...@@ -578,7 +579,7 @@ void ICACHE_FLASH_ATTR http_request( const char * url, const char * method, cons ...@@ -578,7 +579,7 @@ void ICACHE_FLASH_ATTR http_request( const char * url, const char * method, cons
} }
if (path - url >= sizeof(hostname)) { if (path - url >= sizeof(hostname)) {
HTTPCLIENT_DEBUG( "hostname is too long %s\n", url ); HTTPCLIENT_ERR( "hostname is too long %s", url );
return; return;
} }
...@@ -592,7 +593,7 @@ void ICACHE_FLASH_ATTR http_request( const char * url, const char * method, cons ...@@ -592,7 +593,7 @@ void ICACHE_FLASH_ATTR http_request( const char * url, const char * method, cons
port = atoi( colon + 1 ); port = atoi( colon + 1 );
if ( port == 0 ) if ( port == 0 )
{ {
HTTPCLIENT_DEBUG( "Port error %s\n", url ); HTTPCLIENT_ERR( "Port error %s", url );
return; return;
} }
...@@ -606,10 +607,10 @@ void ICACHE_FLASH_ATTR http_request( const char * url, const char * method, cons ...@@ -606,10 +607,10 @@ void ICACHE_FLASH_ATTR http_request( const char * url, const char * method, cons
path = "/"; path = "/";
} }
HTTPCLIENT_DEBUG( "hostname=%s\n", hostname ); HTTPCLIENT_DEBUG( "hostname=%s", hostname );
HTTPCLIENT_DEBUG( "port=%d\n", port ); HTTPCLIENT_DEBUG( "port=%d", port );
HTTPCLIENT_DEBUG( "method=%s\n", method ); HTTPCLIENT_DEBUG( "method=%s", method );
HTTPCLIENT_DEBUG( "path=%s\n", path ); HTTPCLIENT_DEBUG( "path=%s", path );
http_raw_request( hostname, port, secure, method, path, headers, post_data, callback_handle, redirect_follow_count); http_raw_request( hostname, port, secure, method, path, headers, post_data, callback_handle, redirect_follow_count);
} }
...@@ -645,10 +646,11 @@ void ICACHE_FLASH_ATTR http_put( const char * url, const char * headers, const c ...@@ -645,10 +646,11 @@ void ICACHE_FLASH_ATTR http_put( const char * url, const char * headers, const c
void ICACHE_FLASH_ATTR http_callback_example( char * response, int http_status, char * full_response ) void ICACHE_FLASH_ATTR http_callback_example( char * response, int http_status, char * full_response )
{ {
os_printf( "http_status=%d\n", http_status ); dbg_printf( "http_status=%d\n", http_status );
if ( http_status != HTTP_STATUS_GENERIC_ERROR ) if ( http_status != HTTP_STATUS_GENERIC_ERROR )
{ {
os_printf( "strlen(full_response)=%d\n", strlen( full_response ) ); dbg_printf( "strlen(full_response)=%d\n", strlen( full_response ) );
os_printf( "response=%s<EOF>\n", response ); dbg_printf( "response=%s<EOF>\n", response );
} }
} }
...@@ -10,18 +10,25 @@ ...@@ -10,18 +10,25 @@
#ifndef __HTTPCLIENT_H__ #ifndef __HTTPCLIENT_H__
#define __HTTPCLIENT_H__ #define __HTTPCLIENT_H__
#if defined(GLOBAL_DEBUG_ON) static const char log_prefix[] = "HTTP client: ";
#define HTTPCLIENT_DEBUG_ON
#if defined(DEVELOP_VERSION)
#define HTTPCLIENT_DEBUG_ON
#endif #endif
#if defined(HTTPCLIENT_DEBUG_ON) #if defined(HTTPCLIENT_DEBUG_ON)
#define HTTPCLIENT_DEBUG(format, ...) os_printf(format, ##__VA_ARGS__) #define HTTPCLIENT_DEBUG(format, ...) dbg_printf("%s"format"\n", log_prefix, ##__VA_ARGS__)
#else
#define HTTPCLIENT_DEBUG(...)
#endif
#if defined(NODE_ERROR)
#define HTTPCLIENT_ERR(format, ...) NODE_ERR("%s"format"\n", log_prefix, ##__VA_ARGS__)
#else #else
#define HTTPCLIENT_DEBUG(format, ...) #define HTTPCLIENT_ERR(...)
#endif #endif
#if defined(USES_SDK_BEFORE_V140) #if defined(USES_SDK_BEFORE_V140)
#define espconn_send espconn_sent #define espconn_send espconn_sent
#define espconn_secure_send espconn_secure_sent #define espconn_secure_send espconn_secure_sent
#endif #endif
/* /*
......
...@@ -101,7 +101,7 @@ typedef struct { ...@@ -101,7 +101,7 @@ typedef struct {
int buff_uart_no; //indicate which uart use tx/rx buffer int buff_uart_no; //indicate which uart use tx/rx buffer
} UartDevice; } UartDevice;
void uart_init(UartBautRate uart0_br, UartBautRate uart1_br, os_signal_t sig_input); void uart_init(UartBautRate uart0_br, UartBautRate uart1_br, os_signal_t sig_input, uint8 *flag_input);
void uart0_alt(uint8 on); void uart0_alt(uint8 on);
void uart0_sendStr(const char *str); void uart0_sendStr(const char *str);
void uart0_putc(const char c); void uart0_putc(const char c);
......
...@@ -149,5 +149,7 @@ void uart_div_modify(int no, unsigned int freq); ...@@ -149,5 +149,7 @@ void uart_div_modify(int no, unsigned int freq);
/* Returns 0 on success, 1 on failure */ /* Returns 0 on success, 1 on failure */
uint8_t SPIRead(uint32_t src_addr, uint32_t *des_addr, uint32_t size); uint8_t SPIRead(uint32_t src_addr, uint32_t *des_addr, uint32_t size);
uint8_t SPIWrite(uint32_t dst_addr, const uint32_t *src, uint32_t size);
uint8_t SPIEraseSector(uint32_t sector);
#endif #endif
...@@ -2,5 +2,6 @@ ...@@ -2,5 +2,6 @@
#define _SECTIONS_H_ #define _SECTIONS_H_
#define TEXT_SECTION_ATTR __attribute__((section(".text"))) #define TEXT_SECTION_ATTR __attribute__((section(".text")))
#define RAM_CONST_SECTION_ATTR __attribute((section(".data")))
#endif #endif
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
// //
// I2C based displays go into here: // I2C based displays go into here:
// U8G_DISPLAY_TABLE_ENTRY(sh1106_128x64_i2c) \ // U8G_DISPLAY_TABLE_ENTRY(sh1106_128x64_i2c) \
// U8G_DISPLAY_TABLE_ENTRY(ssd1306_128x32_i2c) \
// U8G_DISPLAY_TABLE_ENTRY(ssd1306_128x64_i2c) \ // U8G_DISPLAY_TABLE_ENTRY(ssd1306_128x64_i2c) \
// U8G_DISPLAY_TABLE_ENTRY(ssd1306_64x48_i2c) \ // U8G_DISPLAY_TABLE_ENTRY(ssd1306_64x48_i2c) \
// U8G_DISPLAY_TABLE_ENTRY(ssd1309_128x64_i2c) \ // U8G_DISPLAY_TABLE_ENTRY(ssd1309_128x64_i2c) \
...@@ -40,6 +41,7 @@ ...@@ -40,6 +41,7 @@
// U8G_DISPLAY_TABLE_ENTRY(pcd8544_84x48_hw_spi) \ // U8G_DISPLAY_TABLE_ENTRY(pcd8544_84x48_hw_spi) \
// U8G_DISPLAY_TABLE_ENTRY(pcf8812_96x65_hw_spi) \ // U8G_DISPLAY_TABLE_ENTRY(pcf8812_96x65_hw_spi) \
// U8G_DISPLAY_TABLE_ENTRY(sh1106_128x64_hw_spi) \ // U8G_DISPLAY_TABLE_ENTRY(sh1106_128x64_hw_spi) \
// U8G_DISPLAY_TABLE_ENTRY(ssd1306_128x32_hw_spi) \
// U8G_DISPLAY_TABLE_ENTRY(ssd1306_128x64_hw_spi) \ // U8G_DISPLAY_TABLE_ENTRY(ssd1306_128x64_hw_spi) \
// U8G_DISPLAY_TABLE_ENTRY(ssd1306_64x48_hw_spi) \ // U8G_DISPLAY_TABLE_ENTRY(ssd1306_64x48_hw_spi) \
// U8G_DISPLAY_TABLE_ENTRY(ssd1309_128x64_hw_spi) \ // U8G_DISPLAY_TABLE_ENTRY(ssd1309_128x64_hw_spi) \
...@@ -75,6 +77,10 @@ ...@@ -75,6 +77,10 @@
U8G_DISPLAY_TABLE_ENTRY(ssd1306_128x64_hw_spi) \ U8G_DISPLAY_TABLE_ENTRY(ssd1306_128x64_hw_spi) \
#undef U8G_DISPLAY_TABLE_ENTRY #undef U8G_DISPLAY_TABLE_ENTRY
// Special display device to provide run-length encoded framebuffer contents
// to a Lua callback:
//#define U8G_DISPLAY_FB_RLE
// //
// *************************************************************************** // ***************************************************************************
......
...@@ -36,13 +36,13 @@ extern void luaL_assertfail(const char *file, int line, const char *message); ...@@ -36,13 +36,13 @@ extern void luaL_assertfail(const char *file, int line, const char *message);
#define NODE_ERROR #define NODE_ERROR
#ifdef NODE_DEBUG #ifdef NODE_DEBUG
#define NODE_DBG c_printf #define NODE_DBG dbg_printf
#else #else
#define NODE_DBG #define NODE_DBG
#endif /* NODE_DEBUG */ #endif /* NODE_DEBUG */
#ifdef NODE_ERROR #ifdef NODE_ERROR
#define NODE_ERR c_printf #define NODE_ERR dbg_printf
#else #else
#define NODE_ERR #define NODE_ERR
#endif /* NODE_ERROR */ #endif /* NODE_ERROR */
...@@ -76,6 +76,9 @@ extern void luaL_assertfail(const char *file, int line, const char *message); ...@@ -76,6 +76,9 @@ extern void luaL_assertfail(const char *file, int line, const char *message);
// maximum length of a filename // maximum length of a filename
#define FS_OBJ_NAME_LEN 31 #define FS_OBJ_NAME_LEN 31
// maximum number of open files for SPIFFS
#define SPIFFS_MAX_OPEN_FILES 4
// Uncomment this next line for fastest startup // Uncomment this next line for fastest startup
// It reduces the format time dramatically // It reduces the format time dramatically
// #define SPIFFS_MAX_FILESYSTEM_SIZE 32768 // #define SPIFFS_MAX_FILESYSTEM_SIZE 32768
......
...@@ -53,6 +53,7 @@ ...@@ -53,6 +53,7 @@
//#define LUA_USE_MODULES_RTCTIME //#define LUA_USE_MODULES_RTCTIME
//#define LUA_USE_MODULES_SIGMA_DELTA //#define LUA_USE_MODULES_SIGMA_DELTA
//#define LUA_USE_MODULES_SNTP //#define LUA_USE_MODULES_SNTP
//#define LUA_USE_MODULES_SOMFY
#define LUA_USE_MODULES_SPI #define LUA_USE_MODULES_SPI
//#define LUA_USE_MODULES_STRUCT //#define LUA_USE_MODULES_STRUCT
//#define LUA_USE_MODULES_SWITEC //#define LUA_USE_MODULES_SWITEC
......
...@@ -63,6 +63,8 @@ extern void output_redirect(const char *str); ...@@ -63,6 +63,8 @@ extern void output_redirect(const char *str);
int c_sprintf(char* s,const char *fmt, ...); int c_sprintf(char* s,const char *fmt, ...);
#endif #endif
extern void dbg_printf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
#define c_vsprintf ets_vsprintf #define c_vsprintf ets_vsprintf
#define c_printf(...) do { \ #define c_printf(...) do { \
unsigned char __print_buf[BUFSIZ]; \ unsigned char __print_buf[BUFSIZ]; \
......
/* $NetBSD: printf.c,v 1.12 1997/06/26 19:11:48 drochner Exp $ */
/*-
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
*
* @(#)printf.c 8.1 (Berkeley) 6/11/93
*/
// This version uses almost no stack, and does not suffer from buffer
// overflows. The downside is that it does not implement a wide range
// of formatting characters.
#include <c_stdlib.h>
#include <c_types.h>
#include <c_stdarg.h>
#include "driver/uart.h"
static void kprintn (void (*)(const char), uint32_t, int, int, char);
static void kdoprnt (void (*)(const char), const char *, va_list);
void
dbg_printf(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
kdoprnt(uart0_putc, fmt, ap);
va_end(ap);
}
void
dbg_vprintf(const char *fmt, va_list ap)
{
kdoprnt(uart0_putc, fmt, ap);
}
void
kdoprnt(void (*put)(const char), const char *fmt, va_list ap)
{
register char *p;
register int ch, n;
unsigned long ul;
int lflag, set;
char zwidth;
char width;
for (;;) {
while ((ch = *fmt++) != '%') {
if (ch == '\0')
return;
put(ch);
}
lflag = 0;
width = 0;
zwidth = ' ';
reswitch: switch (ch = *fmt++) {
case '\0':
/* XXX print the last format character? */
return;
case 'l':
lflag = 1;
goto reswitch;
case 'c':
ch = va_arg(ap, int);
put(ch & 0x7f);
break;
case 's':
p = va_arg(ap, char *);
if (p == 0) {
p = "<null>";
}
while ((ch = *p++))
put(ch);
break;
case 'd':
ul = lflag ?
va_arg(ap, long) : va_arg(ap, int);
if ((long)ul < 0) {
put('-');
ul = -(long)ul;
}
kprintn(put, ul, 10, width, zwidth);
break;
case 'o':
ul = lflag ?
va_arg(ap, uint32_t) : va_arg(ap, uint32_t);
kprintn(put, ul, 8, width, zwidth);
break;
case 'u':
ul = lflag ?
va_arg(ap, uint32_t) : va_arg(ap, uint32_t);
kprintn(put, ul, 10, width, zwidth);
break;
case 'x':
ul = lflag ?
va_arg(ap, uint32_t) : va_arg(ap, uint32_t);
kprintn(put, ul, 16, width, zwidth);
break;
default:
if (ch >= '0' && ch <= '9') {
if (ch == '0' && width == 0 && zwidth == ' ') {
zwidth = '0';
} else {
width = width * 10 + ch - '0';
}
goto reswitch;
}
put('%');
if (lflag)
put('l');
put(ch);
}
}
va_end(ap);
}
static void
kprintn(void (*put)(const char), unsigned long ul, int base, int width, char padchar)
{
/* hold a long in base 8 */
char *p, buf[(sizeof(long) * 8 / 3) + 2];
p = buf;
do {
*p++ = "0123456789abcdef"[ul % base];
} while (ul /= base);
while (p - buf < width--) {
put(padchar);
}
do {
put(*--p);
} while (p > buf);
}
...@@ -807,7 +807,7 @@ static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { ...@@ -807,7 +807,7 @@ static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
} }
LUALIB_API void luaL_assertfail(const char *file, int line, const char *message) { LUALIB_API void luaL_assertfail(const char *file, int line, const char *message) {
c_printf("ASSERT@%s(%d): %s\n", file, line, message); dbg_printf("ASSERT@%s(%d): %s\n", file, line, message);
} }
static int panic (lua_State *L) { static int panic (lua_State *L) {
......
...@@ -343,28 +343,19 @@ static int read_line (lua_State *L, int f) { ...@@ -343,28 +343,19 @@ static int read_line (lua_State *L, int f) {
static int read_line (lua_State *L, int f) { static int read_line (lua_State *L, int f) {
luaL_Buffer b; luaL_Buffer b;
luaL_buffinit(L, &b); luaL_buffinit(L, &b);
char *p = luaL_prepbuffer(&b); signed char c;
signed char c = EOF; do {
int i = 0;
do{
c = (signed char)vfs_getc(f); c = (signed char)vfs_getc(f);
if(c==EOF){ if (c==EOF) {
break; break;
} }
p[i++] = c; if (c != '\n') {
}while((c!=EOF) && (c!='\n') && (i<LUAL_BUFFERSIZE) ); luaL_addchar(&b, c);
}
if(i>0 && p[i-1] == '\n') } while (c != '\n');
i--; /* do not include `eol' */
if(i==0){
luaL_pushresult(&b); /* close buffer */
return (lua_objlen(L, -1) > 0); /* check whether read something */
}
luaL_addsize(&b, i);
luaL_pushresult(&b); /* close buffer */ luaL_pushresult(&b); /* close buffer */
return 1; /* read at least an `eol' */ return (lua_objlen(L, -1) > 0); /* check whether read something */
} }
#endif #endif
......
...@@ -346,7 +346,7 @@ extern int readline4lua(const char *prompt, char *buffer, int length); ...@@ -346,7 +346,7 @@ extern int readline4lua(const char *prompt, char *buffer, int length);
** (A format string with one argument is enough for Lua...) ** (A format string with one argument is enough for Lua...)
*/ */
#if !defined(LUA_USE_STDIO) #if !defined(LUA_USE_STDIO)
#define luai_writestringerror(s,p) c_printf((s), (p)) #define luai_writestringerror(s,p) dbg_printf((s), (p))
#endif // defined(LUA_USE_STDIO) #endif // defined(LUA_USE_STDIO)
...@@ -556,7 +556,7 @@ extern int readline4lua(const char *prompt, char *buffer, int length); ...@@ -556,7 +556,7 @@ extern int readline4lua(const char *prompt, char *buffer, int length);
** For example: If set to 4K a call to string.gsub will need more than ** For example: If set to 4K a call to string.gsub will need more than
** 5k C stack space. ** 5k C stack space.
*/ */
#define LUAL_BUFFERSIZE BUFSIZ #define LUAL_BUFFERSIZE 256
/* }================================================================== */ /* }================================================================== */
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
* @author Robert Foss <dev@robertfoss.se> * @author Robert Foss <dev@robertfoss.se>
* *
* Additions & fixes: Johny Mattsson <jmattsson@dius.com.au> * Additions & fixes: Johny Mattsson <jmattsson@dius.com.au>
* Jason Follas <jfollas@gmail.com>
*/ */
#include "module.h" #include "module.h"
...@@ -50,6 +51,8 @@ ...@@ -50,6 +51,8 @@
#define MIN(x, y) (((x) < (y)) ? (x) : (y)) #define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define LITLEN(strliteral) (sizeof (strliteral) -1) #define LITLEN(strliteral) (sizeof (strliteral) -1)
#define STRINGIFY(x) #x
#define NUMLEN(x) (sizeof(STRINGIFY(x)) - 1)
#define ENDUSER_SETUP_ERR_FATAL (1 << 0) #define ENDUSER_SETUP_ERR_FATAL (1 << 0)
#define ENDUSER_SETUP_ERR_NONFATAL (1 << 1) #define ENDUSER_SETUP_ERR_NONFATAL (1 << 1)
...@@ -59,7 +62,7 @@ ...@@ -59,7 +62,7 @@
#define ENDUSER_SETUP_ERR_CONNECTION_NOT_FOUND 2 #define ENDUSER_SETUP_ERR_CONNECTION_NOT_FOUND 2
#define ENDUSER_SETUP_ERR_UNKOWN_ERROR 3 #define ENDUSER_SETUP_ERR_UNKOWN_ERROR 3
#define ENDUSER_SETUP_ERR_SOCKET_ALREADY_OPEN 4 #define ENDUSER_SETUP_ERR_SOCKET_ALREADY_OPEN 4
#define ENDUSER_SETUP_ERR_MAX_NUMBER 5
/** /**
* DNS Response Packet: * DNS Response Packet:
...@@ -78,159 +81,19 @@ static const char dns_body[] = { 0x00, 0x01, 0x00, 0x01, ...@@ -78,159 +81,19 @@ static const char dns_body[] = { 0x00, 0x01, 0x00, 0x01,
0xC0, 0x0C, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x04 }; 0xC0, 0x0C, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x04 };
static const char http_html_filename[] = "enduser_setup.html"; static const char http_html_filename[] = "enduser_setup.html";
static const char http_header_200[] = "HTTP/1.1 200 OK\r\nCache-control:no-cache\r\nContent-Type: text/html\r\n"; /* Note single \r\n here! */ static const char http_header_200[] = "HTTP/1.1 200 OK\r\nCache-control:no-cache\r\nConnection:close\r\nContent-Type:text/html\r\n"; /* Note single \r\n here! */
static const char http_header_204[] = "HTTP/1.1 204 No Content\r\n\r\n"; static const char http_header_204[] = "HTTP/1.1 204 No Content\r\nContent-Length:0\r\nConnection:close\r\n\r\n";
static const char http_header_302[] = "HTTP/1.1 302 Moved\r\nLocation: /\r\n\r\n"; static const char http_header_302[] = "HTTP/1.1 302 Moved\r\nLocation: /\r\nContent-Length:0\r\nConnection:close\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_400[] = "HTTP/1.1 400 Bad request\r\nContent-Length:0\r\nConnection:close\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_404[] = "HTTP/1.1 404 Not found\r\nContent-Length:0\r\nConnection:close\r\n\r\n";
static const char http_header_500[] = "HTTP/1.1 500 Internal Error\r\n\r\n"; static const char http_header_405[] = "HTTP/1.1 405 Method Not Allowed\r\nContent-Length:0\r\nConnection:close\r\n\r\n";
static const char http_header_500[] = "HTTP/1.1 500 Internal Error\r\nContent-Length:0\r\nConnection:close\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+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:-150px;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;}
#formFrame{display: none;}
#aplist{display: block;}
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; }
</style>
</head>
<body>
<div>
<form id="credentialsForm" method="get" action="/update" target="formFrame">
<fieldset>
<iframe id="formFrame" src="" name="formFrame"></iframe> <!-- Used to submit data, needed to prevent re-direction after submission -->
<h2 class="fs-title">WiFi Login</h2>
<h3 class="fs-subtitle">Connect gadget to your WiFi network</h3>
<input id="wifi_ssid" autocorrect="off" autocapitalize="none" name="wifi_ssid" placeholder="WiFi Name">
<select id="aplist" name="aplist" size="1" disabled>
<option>Scanning for networks...</option>
</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>
<h3 id="dbg"></h3>
</form>
</div>
<script>
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;
}
}
static const char http_header_content_len_fmt[] = "Content-length:%5d\r\n\r\n";
static const char http_html_gzip_contentencoding[] = "Content-Encoding: gzip\r\n";
function new_status_repeat(stat) // Externally defined: static const char http_html_backup[] = ...
{ #include "eus/http_html_backup.def"
new_status(stat);
setTimeout(refresh_status, 750);
}
function new_ap_list(json)
{
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 = document.getElementById("aplist");
sel.innerHTML = "";
sel.setAttribute("size", Math.max(Math.min(3, list.length), 1));
sel.removeAttribute("disabled");
for (var i = 0; i < ssids.length; ++i)
{
var o = document.createElement("option");
o.innerHTML = ssids[i];
sel.options.add(o);
}
sel.style.display = 'block';
}
}
function new_ap_list_repeat(json)
{
new_ap_list(json);
setTimeout(refresh_ap_list, 3000);
}
function refresh_status()
{
fetch('/status','GET', new_status_repeat);
}
function refresh_ap_list()
{
fetch('/aplist','GET', new_ap_list_repeat);
}
function set_ssid_field() {
var sel = document.getElementById("aplist");
document.getElementById("wifi_ssid").value = sel.value;
}
window.onload = function()
{
refresh_status();
refresh_ap_list();
document.getElementById("aplist").onclick = set_ssid_field;
document.getElementById("aplist").onchange = set_ssid_field;
document.getElementById("credentialsForm").addEventListener("submit", function(){
fetch('/status','GET', new_status);
});
}
</script>
</body>
</html>
#endif
static const char http_html_backup[] =
"<!DOCTYPE html><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:-150px;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}#formFrame{display:none}#aplist{display:block}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}</style><div><form id=credentialsForm action=/update target=formFrame><fieldset><iframe id=formFrame src=''name=formFrame></iframe><h2 class=fs-title>WiFi Login</h2><h3 class=fs-subtitle>Connect gadget to your WiFi network</h3><input id=wifi_ssid autocorrect=off autocapitalize=none name=wifi_ssid placeholder='WiFi Name'><select id=aplist name=aplist size=1 disabled><option>Scanning for networks...</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><h3 id=dbg></h3></form></div><script>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}}function new_status_repeat(t){new_status(t),setTimeout(refresh_status,750)}function new_ap_list(t){if(t){var e=JSON.parse(t);e.sort(function(t,e){return e.rssi-t.rssi});var n=e.map(function(t){return t.ssid}).filter(function(t,e,n){return n.indexOf(t)==e}),s=document.getElementById('aplist');s.innerHTML='',s.setAttribute('size',Math.max(Math.min(3,e.length),1)),s.removeAttribute('disabled');for(var i=0;i<n.length;++i){var a=document.createElement('option');a.innerHTML=n[i],s.options.add(a)}s.style.display='block'}}function new_ap_list_repeat(t){new_ap_list(t),setTimeout(refresh_ap_list,3e3)}function refresh_status(){fetch('/status','GET',new_status_repeat)}function refresh_ap_list(){fetch('/aplist','GET',new_ap_list_repeat)}function set_ssid_field(){var t=document.getElementById('aplist');document.getElementById('wifi_ssid').value=t.value}window.onload=function(){refresh_status(),refresh_ap_list(),document.getElementById('aplist').onclick=set_ssid_field,document.getElementById('aplist').onchange=set_ssid_field,document.getElementById('credentialsForm').addEventListener('submit',function(){fetch('/status','GET',new_status)})}</script>";
typedef struct scan_listener typedef struct scan_listener
{ {
...@@ -250,9 +113,15 @@ typedef struct ...@@ -250,9 +113,15 @@ typedef struct
int lua_err_cb_ref; int lua_err_cb_ref;
int lua_dbg_cb_ref; int lua_dbg_cb_ref;
scan_listener_t *scan_listeners; scan_listener_t *scan_listeners;
uint8_t softAPchannel;
uint8_t success;
uint8_t callbackDone;
uint8_t lastStationStatus;
uint8_t connecting;
} enduser_setup_state_t; } enduser_setup_state_t;
static enduser_setup_state_t *state; static enduser_setup_state_t *state;
static bool manual = false; static bool manual = false;
static task_handle_t do_station_cfg_handle; static task_handle_t do_station_cfg_handle;
...@@ -340,7 +209,7 @@ static void enduser_setup_check_station_start(void) ...@@ -340,7 +209,7 @@ static void enduser_setup_check_station_start(void)
ENDUSER_SETUP_DEBUG("enduser_setup_check_station_start"); ENDUSER_SETUP_DEBUG("enduser_setup_check_station_start");
os_timer_setfn(&(state->check_station_timer), enduser_setup_check_station, NULL); os_timer_setfn(&(state->check_station_timer), enduser_setup_check_station, NULL);
os_timer_arm(&(state->check_station_timer), 1*1000, TRUE); os_timer_arm(&(state->check_station_timer), 3*1000, TRUE);
} }
...@@ -377,13 +246,60 @@ static void enduser_setup_check_station(void *p) ...@@ -377,13 +246,60 @@ static void enduser_setup_check_station(void *p)
has_ip |= ((char *) &ip)[i]; has_ip |= ((char *) &ip)[i];
} }
uint8_t currChan = wifi_get_channel();
if (has_ip == 0) if (has_ip == 0)
{ {
return; // No IP Address yet, so check the reported status
} uint8_t curr_status = wifi_station_get_connect_status();
char buf[20];
c_sprintf(buf, "status=%d,chan=%d", curr_status, currChan);
ENDUSER_SETUP_DEBUG(buf);
if (curr_status == 2 || curr_status == 3 || curr_status == 4)
{
state->connecting = 0;
// If the status is an error status and the channel changed, then cache the
// status to state since the Station won't be able to report the same status
// after switching the channel back to the SoftAP's
if (currChan != state->softAPchannel) {
state->lastStationStatus = curr_status;
ENDUSER_SETUP_DEBUG("Turning off Station due to different channel than AP");
wifi_station_disconnect();
wifi_set_opmode(SOFTAP_MODE);
enduser_setup_ap_start();
}
}
return;
}
state->success = 1;
state->lastStationStatus = 5; // We have an IP Address, so the status is 5 (as of SDK 1.5.1)
state->connecting = 0;
#if ENDUSER_SETUP_DEBUG_ENABLE
char debuginfo[100];
c_sprintf(debuginfo, "AP_CHAN: %d, STA_CHAN: %d", state->softAPchannel, currChan);
ENDUSER_SETUP_DEBUG(debuginfo);
#endif
if (currChan == state->softAPchannel)
{
enduser_setup_connected_callback();
state->callbackDone = 1;
}
else
{
ENDUSER_SETUP_DEBUG("Turning off Station due to different channel than AP");
wifi_station_disconnect();
wifi_set_opmode(SOFTAP_MODE);
enduser_setup_ap_start();
}
enduser_setup_check_station_stop(); enduser_setup_check_station_stop();
enduser_setup_connected_callback();
/* Trigger shutdown, but allow time for HTTP client to fetch last status. */ /* Trigger shutdown, but allow time for HTTP client to fetch last status. */
if (!manual) if (!manual)
...@@ -411,6 +327,8 @@ static void enduser_setup_check_station(void *p) ...@@ -411,6 +327,8 @@ static void enduser_setup_check_station(void *p)
/* Callback on timeout to hard-close a connection */ /* Callback on timeout to hard-close a connection */
static err_t force_abort (void *arg, struct tcp_pcb *pcb) static err_t force_abort (void *arg, struct tcp_pcb *pcb)
{ {
ENDUSER_SETUP_DEBUG("force_abort");
(void)arg; (void)arg;
tcp_poll (pcb, 0, 0); tcp_poll (pcb, 0, 0);
tcp_abort (pcb); tcp_abort (pcb);
...@@ -420,6 +338,8 @@ static err_t force_abort (void *arg, struct tcp_pcb *pcb) ...@@ -420,6 +338,8 @@ static err_t force_abort (void *arg, struct tcp_pcb *pcb)
/* Callback to detect a remote-close of a connection */ /* Callback to detect a remote-close of a connection */
static err_t handle_remote_close (void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) static err_t handle_remote_close (void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{ {
ENDUSER_SETUP_DEBUG("handle_remote_close");
(void)arg; (void)err; (void)arg; (void)err;
if (p) /* server sent us data, just ACK and move on */ if (p) /* server sent us data, just ACK and move on */
{ {
...@@ -438,6 +358,8 @@ static err_t handle_remote_close (void *arg, struct tcp_pcb *pcb, struct pbuf *p ...@@ -438,6 +358,8 @@ static err_t handle_remote_close (void *arg, struct tcp_pcb *pcb, struct pbuf *p
/* Set up a deferred close of a connection, as discussed above. */ /* Set up a deferred close of a connection, as discussed above. */
static inline void deferred_close (struct tcp_pcb *pcb) static inline void deferred_close (struct tcp_pcb *pcb)
{ {
ENDUSER_SETUP_DEBUG("deferred_close");
tcp_poll (pcb, force_abort, 15); /* ~3sec from now */ tcp_poll (pcb, force_abort, 15); /* ~3sec from now */
tcp_recv (pcb, handle_remote_close); tcp_recv (pcb, handle_remote_close);
tcp_sent (pcb, 0); tcp_sent (pcb, 0);
...@@ -446,6 +368,8 @@ static inline void deferred_close (struct tcp_pcb *pcb) ...@@ -446,6 +368,8 @@ static inline void deferred_close (struct tcp_pcb *pcb)
/* Convenience function to queue up a close-after-send. */ /* Convenience function to queue up a close-after-send. */
static err_t close_once_sent (void *arg, struct tcp_pcb *pcb, u16_t len) static err_t close_once_sent (void *arg, struct tcp_pcb *pcb, u16_t len)
{ {
ENDUSER_SETUP_DEBUG("close_once_sent");
(void)arg; (void)len; (void)arg; (void)len;
deferred_close (pcb); deferred_close (pcb);
return ERR_OK; return ERR_OK;
...@@ -473,7 +397,6 @@ static int enduser_setup_srch_str(const char *str, const char *srch_str) ...@@ -473,7 +397,6 @@ static int enduser_setup_srch_str(const char *str, const char *srch_str)
} }
} }
/** /**
* Load HTTP Payload * Load HTTP Payload
* *
...@@ -495,14 +418,26 @@ static int enduser_setup_http_load_payload(void) ...@@ -495,14 +418,26 @@ static int enduser_setup_http_load_payload(void)
err2 = vfs_lseek(f, 0, VFS_SEEK_SET); err2 = vfs_lseek(f, 0, VFS_SEEK_SET);
} }
const char cl_hdr[] = "Content-length:%5d\r\n\r\n"; char cl_hdr[30];
const size_t cl_len = LITLEN(cl_hdr) + 3; /* room to expand %4d */ size_t ce_len = 0;
c_sprintf(cl_hdr, http_header_content_len_fmt, file_len);
size_t cl_len = c_strlen(cl_hdr);
if (!f || err != VFS_RES_OK || err2 != VFS_RES_OK) if (!f || err == VFS_RES_ERR || err2 == VFS_RES_ERR)
{ {
ENDUSER_SETUP_DEBUG("enduser_setup_http_load_payload unable to load file enduser_setup.html, loading backup HTML."); ENDUSER_SETUP_DEBUG("enduser_setup_http_load_payload unable to load file enduser_setup.html, loading backup HTML.");
int payload_len = LITLEN(http_header_200) + cl_len + LITLEN(http_html_backup); c_sprintf(cl_hdr, http_header_content_len_fmt, sizeof(http_html_backup));
cl_len = c_strlen(cl_hdr);
if (http_html_backup[0] == 0x1f && http_html_backup[1] == 0x8b)
{
ce_len = c_strlen(http_html_gzip_contentencoding);
ENDUSER_SETUP_DEBUG("Content is gzipped");
}
int payload_len = LITLEN(http_header_200) + cl_len + ce_len + LITLEN(http_html_backup);
state->http_payload_len = payload_len; state->http_payload_len = payload_len;
state->http_payload_data = (char *) c_malloc(payload_len); state->http_payload_data = (char *) c_malloc(payload_len);
if (state->http_payload_data == NULL) if (state->http_payload_data == NULL)
...@@ -513,13 +448,25 @@ static int enduser_setup_http_load_payload(void) ...@@ -513,13 +448,25 @@ static int enduser_setup_http_load_payload(void)
int offset = 0; int offset = 0;
c_memcpy(&(state->http_payload_data[offset]), &(http_header_200), LITLEN(http_header_200)); c_memcpy(&(state->http_payload_data[offset]), &(http_header_200), LITLEN(http_header_200));
offset += LITLEN(http_header_200); offset += LITLEN(http_header_200);
offset += c_sprintf(state->http_payload_data + offset, cl_hdr, LITLEN(http_html_backup)); if (ce_len > 0)
c_memcpy(&(state->http_payload_data[offset]), &(http_html_backup), LITLEN(http_html_backup)); offset += c_sprintf(state->http_payload_data + offset, http_html_gzip_contentencoding, ce_len);
c_memcpy(&(state->http_payload_data[offset]), &(cl_hdr), cl_len);
return 1; offset += cl_len;
c_memcpy(&(state->http_payload_data[offset]), &(http_html_backup), sizeof(http_html_backup));
return 1;
} }
int payload_len = LITLEN(http_header_200) + cl_len + file_len; char magic[2];
vfs_read(f, magic, 2);
if (magic[0] == 0x1f && magic[1] == 0x8b)
{
ce_len = c_strlen(http_html_gzip_contentencoding);
ENDUSER_SETUP_DEBUG("Content is gzipped");
}
int payload_len = LITLEN(http_header_200) + cl_len + ce_len + file_len;
state->http_payload_len = payload_len; state->http_payload_len = payload_len;
state->http_payload_data = (char *) c_malloc(payload_len); state->http_payload_data = (char *) c_malloc(payload_len);
if (state->http_payload_data == NULL) if (state->http_payload_data == NULL)
...@@ -527,13 +474,19 @@ static int enduser_setup_http_load_payload(void) ...@@ -527,13 +474,19 @@ static int enduser_setup_http_load_payload(void)
return 2; return 2;
} }
vfs_lseek(f, 0, VFS_SEEK_SET);
int offset = 0; int offset = 0;
c_memcpy(&(state->http_payload_data[offset]), &(http_header_200), LITLEN(http_header_200)); c_memcpy(&(state->http_payload_data[offset]), &(http_header_200), LITLEN(http_header_200));
offset += LITLEN(http_header_200); offset += LITLEN(http_header_200);
offset += c_sprintf(state->http_payload_data + offset, cl_hdr, file_len); if (ce_len > 0)
offset += c_sprintf(state->http_payload_data + offset, http_html_gzip_contentencoding, ce_len);
c_memcpy(&(state->http_payload_data[offset]), &(cl_hdr), cl_len);
offset += cl_len;
vfs_read(f, &(state->http_payload_data[offset]), file_len); vfs_read(f, &(state->http_payload_data[offset]), file_len);
vfs_close(f); vfs_close(f);
return 0; return 0;
} }
...@@ -605,6 +558,9 @@ static int enduser_setup_http_urldecode(char *dst, const char *src, int src_len, ...@@ -605,6 +558,9 @@ static int enduser_setup_http_urldecode(char *dst, const char *src, int src_len,
*/ */
static void do_station_cfg (task_param_t param, uint8_t prio) static void do_station_cfg (task_param_t param, uint8_t prio)
{ {
ENDUSER_SETUP_DEBUG("do_station_cfg");
state->connecting = 1;
struct station_config *cnf = (struct station_config *)param; struct station_config *cnf = (struct station_config *)param;
(void)prio; (void)prio;
...@@ -635,6 +591,9 @@ static int enduser_setup_http_handle_credentials(char *data, unsigned short data ...@@ -635,6 +591,9 @@ static int enduser_setup_http_handle_credentials(char *data, unsigned short data
{ {
ENDUSER_SETUP_DEBUG("enduser_setup_http_handle_credentials"); ENDUSER_SETUP_DEBUG("enduser_setup_http_handle_credentials");
state->success = 0;
state->lastStationStatus = 0;
char *name_str = (char *) ((uint32_t)strstr(&(data[6]), "wifi_ssid=")); char *name_str = (char *) ((uint32_t)strstr(&(data[6]), "wifi_ssid="));
char *pwd_str = (char *) ((uint32_t)strstr(&(data[6]), "wifi_password=")); char *pwd_str = (char *) ((uint32_t)strstr(&(data[6]), "wifi_password="));
if (name_str == NULL || pwd_str == NULL) if (name_str == NULL || pwd_str == NULL)
...@@ -663,7 +622,7 @@ static int enduser_setup_http_handle_credentials(char *data, unsigned short data ...@@ -663,7 +622,7 @@ static int enduser_setup_http_handle_credentials(char *data, unsigned short data
int err; int err;
err = enduser_setup_http_urldecode(cnf->ssid, name_str_start, name_str_len, sizeof(cnf->ssid)); err = enduser_setup_http_urldecode(cnf->ssid, name_str_start, name_str_len, sizeof(cnf->ssid));
err |= enduser_setup_http_urldecode(cnf->password, pwd_str_start, pwd_str_len, sizeof(cnf->password)); err |= enduser_setup_http_urldecode(cnf->password, pwd_str_start, pwd_str_len, sizeof(cnf->password));
if (err != 0) if (err != 0 || c_strlen(cnf->ssid) == 0)
{ {
ENDUSER_SETUP_DEBUG("Unable to decode HTTP parameter to valid password or SSID"); ENDUSER_SETUP_DEBUG("Unable to decode HTTP parameter to valid password or SSID");
return 1; return 1;
...@@ -694,7 +653,7 @@ static int enduser_setup_http_handle_credentials(char *data, unsigned short data ...@@ -694,7 +653,7 @@ static int enduser_setup_http_handle_credentials(char *data, unsigned short data
static int enduser_setup_http_serve_header(struct tcp_pcb *http_client, const char *header, uint32_t header_len) static int enduser_setup_http_serve_header(struct tcp_pcb *http_client, const char *header, uint32_t header_len)
{ {
ENDUSER_SETUP_DEBUG("enduser_setup_http_serve_header"); ENDUSER_SETUP_DEBUG("enduser_setup_http_serve_header");
err_t err = tcp_write (http_client, header, header_len, TCP_WRITE_FLAG_COPY); err_t err = tcp_write (http_client, header, header_len, TCP_WRITE_FLAG_COPY);
if (err != ERR_OK) if (err != ERR_OK)
{ {
...@@ -708,8 +667,9 @@ static int enduser_setup_http_serve_header(struct tcp_pcb *http_client, const ch ...@@ -708,8 +667,9 @@ static int enduser_setup_http_serve_header(struct tcp_pcb *http_client, const ch
static err_t streamout_sent (void *arg, struct tcp_pcb *pcb, u16_t len) static err_t streamout_sent (void *arg, struct tcp_pcb *pcb, u16_t len)
{ {
(void)len; ENDUSER_SETUP_DEBUG("streamout_sent");
(void)len;
unsigned offs = (unsigned)arg; unsigned offs = (unsigned)arg;
if (!state || !state->http_payload_data) if (!state || !state->http_payload_data)
...@@ -754,6 +714,7 @@ static err_t streamout_sent (void *arg, struct tcp_pcb *pcb, u16_t len) ...@@ -754,6 +714,7 @@ static err_t streamout_sent (void *arg, struct tcp_pcb *pcb, u16_t len)
static int enduser_setup_http_serve_html(struct tcp_pcb *http_client) static int enduser_setup_http_serve_html(struct tcp_pcb *http_client)
{ {
ENDUSER_SETUP_DEBUG("enduser_setup_http_serve_html"); ENDUSER_SETUP_DEBUG("enduser_setup_http_serve_html");
if (state->http_payload_data == NULL) if (state->http_payload_data == NULL)
{ {
enduser_setup_http_load_payload(); enduser_setup_http_load_payload();
...@@ -774,7 +735,7 @@ static int enduser_setup_http_serve_html(struct tcp_pcb *http_client) ...@@ -774,7 +735,7 @@ static int enduser_setup_http_serve_html(struct tcp_pcb *http_client)
} }
static void serve_status(struct tcp_pcb *conn) static void enduser_setup_serve_status(struct tcp_pcb *conn)
{ {
ENDUSER_SETUP_DEBUG("enduser_setup_serve_status"); ENDUSER_SETUP_DEBUG("enduser_setup_serve_status");
...@@ -782,11 +743,12 @@ static void serve_status(struct tcp_pcb *conn) ...@@ -782,11 +743,12 @@ static void serve_status(struct tcp_pcb *conn)
"HTTP/1.1 200 OK\r\n" "HTTP/1.1 200 OK\r\n"
"Cache-control:no-cache\r\n" "Cache-control:no-cache\r\n"
"Connection:close\r\n" "Connection:close\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-type:text/plain\r\n" "Content-type:text/plain\r\n"
"Content-length: %d\r\n" "Content-length: %d\r\n"
"\r\n" "\r\n"
"%s%s"; "%s";
const char *state[] = const char *states[] =
{ {
"Idle.", "Idle.",
"Connecting to \"%s\".", "Connecting to \"%s\".",
...@@ -796,8 +758,8 @@ static void serve_status(struct tcp_pcb *conn) ...@@ -796,8 +758,8 @@ static void serve_status(struct tcp_pcb *conn)
"Connected to \"%s\" (%s)." "Connected to \"%s\" (%s)."
}; };
const size_t num_states = sizeof(state)/sizeof(state[0]); const size_t num_states = sizeof(states)/sizeof(states[0]);
uint8_t curr_state = wifi_station_get_connect_status (); uint8_t curr_state = state->lastStationStatus > 0 ? state->lastStationStatus : wifi_station_get_connect_status ();
if (curr_state < num_states) if (curr_state < num_states)
{ {
switch (curr_state) switch (curr_state)
...@@ -807,22 +769,21 @@ static void serve_status(struct tcp_pcb *conn) ...@@ -807,22 +769,21 @@ static void serve_status(struct tcp_pcb *conn)
case STATION_NO_AP_FOUND: case STATION_NO_AP_FOUND:
case STATION_GOT_IP: case STATION_GOT_IP:
{ {
const char *s = state[curr_state]; const char *s = states[curr_state];
struct station_config config; struct station_config config;
wifi_station_get_config(&config); wifi_station_get_config(&config);
config.ssid[31] = '\0'; config.ssid[31] = '\0';
struct ip_info ip_info; struct ip_info ip_info;
wifi_get_ip_info(STATION_IF , &ip_info); wifi_get_ip_info(STATION_IF , &ip_info);
char ip_addr[16];
ip_addr[0] = '\0';
if (curr_state == STATION_GOT_IP)
{
c_sprintf (ip_addr, "%d.%d.%d.%d", IP2STR(&ip_info.ip.addr));
}
char ip_addr[16];
ip_addr[0] = '\0';
if (curr_state == STATION_GOT_IP)
{
c_sprintf (ip_addr, "%d.%d.%d.%d", IP2STR(&ip_info.ip.addr));
}
int state_len = c_strlen(s); int state_len = c_strlen(s);
int ip_len = c_strlen(ip_addr); int ip_len = c_strlen(ip_addr);
...@@ -844,7 +805,7 @@ static void serve_status(struct tcp_pcb *conn) ...@@ -844,7 +805,7 @@ static void serve_status(struct tcp_pcb *conn)
/* Handle non-formatted strings */ /* Handle non-formatted strings */
default: default:
{ {
const char *s = state[curr_state]; const char *s = states[curr_state];
int status_len = c_strlen(s); int status_len = c_strlen(s);
int buf_len = sizeof(fmt) + status_len + 10; //10 = (9+1), 1 byte is '\0' and 9 are reserved for length field int buf_len = sizeof(fmt) + status_len + 10; //10 = (9+1), 1 byte is '\0' and 9 are reserved for length field
char buf[buf_len]; char buf[buf_len];
...@@ -862,12 +823,76 @@ static void serve_status(struct tcp_pcb *conn) ...@@ -862,12 +823,76 @@ static void serve_status(struct tcp_pcb *conn)
} }
} }
static void enduser_setup_serve_status_as_json (struct tcp_pcb *http_client)
{
ENDUSER_SETUP_DEBUG("enduser_setup_serve_status_as_json");
// If the station is currently shut down because of wi-fi channel issue, use the cached status
uint8_t curr_status = state->lastStationStatus > 0 ? state->lastStationStatus : wifi_station_get_connect_status ();
char json_payload[64];
c_sprintf(json_payload, "{\"deviceid\":\"%06X\", \"status\":%d}", system_get_chip_id(), curr_status);
const char fmt[] =
"HTTP/1.1 200 OK\r\n"
"Cache-Control: no-cache\r\n"
"Connection: close\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n"
"Content-Length: %d\r\n"
"\r\n"
"%s";
int len = c_strlen(json_payload);
char buf[c_strlen(fmt) + NUMLEN(len) + len - 4];
len = c_sprintf (buf, fmt, len, json_payload);
enduser_setup_http_serve_header (http_client, buf, len);
}
static void enduser_setup_handle_OPTIONS (struct tcp_pcb *http_client, char *data, unsigned short data_len)
{
ENDUSER_SETUP_DEBUG("enduser_setup_handle_OPTIONS");
const char json[] =
"HTTP/1.1 200 OK\r\n"
"Cache-Control: no-cache\r\n"
"Connection: close\r\n"
"Content-Type: application/json\r\n"
"Content-Length: 0\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Access-Control-Allow-Methods: GET\r\n"
"Access-Control-Allow-Age: 300\r\n"
"\r\n";
const char others[] =
"HTTP/1.1 200 OK\r\n"
"Cache-Control: no-cache\r\n"
"Connection: close\r\n"
"Content-Length: 0\r\n"
"\r\n";
int type = 0;
if (c_strncmp(data, "GET ", 4) == 0)
{
if (c_strncmp(data + 4, "/aplist", 7) == 0 || c_strncmp(data + 4, "/setwifi?", 9) == 0 || c_strncmp(data + 4, "/status.json", 12) == 0)
{
enduser_setup_http_serve_header (http_client, json, c_strlen(json));
return;
}
}
enduser_setup_http_serve_header (http_client, others, c_strlen(others));
return;
}
/* --- WiFi AP scanning support -------------------------------------------- */ /* --- WiFi AP scanning support -------------------------------------------- */
static void free_scan_listeners (void) static void free_scan_listeners (void)
{ {
ENDUSER_SETUP_DEBUG("free_scan_listeners");
if (!state || !state->scan_listeners) if (!state || !state->scan_listeners)
{ {
return; return;
...@@ -886,6 +911,8 @@ static void free_scan_listeners (void) ...@@ -886,6 +911,8 @@ static void free_scan_listeners (void)
static void remove_scan_listener (scan_listener_t *l) static void remove_scan_listener (scan_listener_t *l)
{ {
ENDUSER_SETUP_DEBUG("remove_scan_listener");
if (state) if (state)
{ {
scan_listener_t **sl = &state->scan_listeners; scan_listener_t **sl = &state->scan_listeners;
...@@ -921,6 +948,8 @@ static char *escape_ssid (char *dst, const char *src) ...@@ -921,6 +948,8 @@ static char *escape_ssid (char *dst, const char *src)
static void notify_scan_listeners (const char *payload, size_t sz) static void notify_scan_listeners (const char *payload, size_t sz)
{ {
ENDUSER_SETUP_DEBUG("notify_scan_listeners");
if (!state) if (!state)
{ {
return; return;
...@@ -944,6 +973,8 @@ static void notify_scan_listeners (const char *payload, size_t sz) ...@@ -944,6 +973,8 @@ static void notify_scan_listeners (const char *payload, size_t sz)
static void on_scan_done (void *arg, STATUS status) static void on_scan_done (void *arg, STATUS status)
{ {
ENDUSER_SETUP_DEBUG("on_scan_done");
if (!state || !state->scan_listeners) if (!state || !state->scan_listeners)
{ {
return; return;
...@@ -961,13 +992,14 @@ static void on_scan_done (void *arg, STATUS status) ...@@ -961,13 +992,14 @@ static void on_scan_done (void *arg, STATUS status)
"HTTP/1.1 200 OK\r\n" "HTTP/1.1 200 OK\r\n"
"Connection:close\r\n" "Connection:close\r\n"
"Cache-control:no-cache\r\n" "Cache-control:no-cache\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-type:application/json\r\n" "Content-type:application/json\r\n"
"Content-length:%4d\r\n" "Content-length:%4d\r\n"
"\r\n"; "\r\n";
const size_t hdr_sz = sizeof (header_fmt) +1 -1; /* +expand %4d, -\0 */ 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 */ /* 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 max_entry_sz = 27 + 2*32 + 6; // {"ssid":"","rssi":,"chan":}
const size_t alloc_sz = hdr_sz + num_nets * max_entry_sz + 3; const size_t alloc_sz = hdr_sz + num_nets * max_entry_sz + 3;
char *http = os_zalloc (alloc_sz); char *http = os_zalloc (alloc_sz);
if (!http) if (!http)
...@@ -996,6 +1028,12 @@ static void on_scan_done (void *arg, STATUS status) ...@@ -996,6 +1028,12 @@ static void on_scan_done (void *arg, STATUS status)
p += sizeof (entry_mid) -1; p += sizeof (entry_mid) -1;
p += c_sprintf (p, "%d", wn->rssi); p += c_sprintf (p, "%d", wn->rssi);
const char entry_chan[] = ",\"chan\":";
strcpy (p, entry_chan);
p += sizeof (entry_chan) -1;
p += c_sprintf (p, "%d", wn->channel);
*p++ = '}'; *p++ = '}';
} }
...@@ -1006,6 +1044,8 @@ static void on_scan_done (void *arg, STATUS status) ...@@ -1006,6 +1044,8 @@ static void on_scan_done (void *arg, STATUS status)
http[hdr_sz] = '['; /* Rewrite the \0 with the correct start of body */ http[hdr_sz] = '['; /* Rewrite the \0 with the correct start of body */
notify_scan_listeners (http, hdr_sz + body_sz); notify_scan_listeners (http, hdr_sz + body_sz);
ENDUSER_SETUP_DEBUG(http + hdr_sz);
c_free (http); c_free (http);
return; return;
} }
...@@ -1048,6 +1088,9 @@ static err_t enduser_setup_http_recvcb(void *arg, struct tcp_pcb *http_client, s ...@@ -1048,6 +1088,9 @@ static err_t enduser_setup_http_recvcb(void *arg, struct tcp_pcb *http_client, s
pbuf_free (p); pbuf_free (p);
err_t ret = ERR_OK; err_t ret = ERR_OK;
ENDUSER_SETUP_DEBUG(data);
if (c_strncmp(data, "GET ", 4) == 0) if (c_strncmp(data, "GET ", 4) == 0)
{ {
if (c_strncmp(data + 4, "/ ", 2) == 0) if (c_strncmp(data + 4, "/ ", 2) == 0)
...@@ -1061,38 +1104,52 @@ static err_t enduser_setup_http_recvcb(void *arg, struct tcp_pcb *http_client, s ...@@ -1061,38 +1104,52 @@ static err_t enduser_setup_http_recvcb(void *arg, struct tcp_pcb *http_client, s
goto free_out; /* streaming now in progress */ goto free_out; /* streaming now in progress */
} }
} }
else if (c_strncmp(data + 4, "/aplist ", 8) == 0) else if (c_strncmp(data + 4, "/aplist", 7) == 0)
{ {
scan_listener_t *l = os_malloc (sizeof (scan_listener_t)); // Don't do an AP Scan while station is trying to connect to Wi-Fi
if (!l) if (state->connecting == 0)
{ {
ENDUSER_SETUP_ERROR("out of memory", ENDUSER_SETUP_ERR_OUT_OF_MEMORY, ENDUSER_SETUP_ERR_NONFATAL); scan_listener_t *l = os_malloc (sizeof (scan_listener_t));
} if (!l)
{
ENDUSER_SETUP_ERROR("out of memory", ENDUSER_SETUP_ERR_OUT_OF_MEMORY, ENDUSER_SETUP_ERR_NONFATAL);
}
bool already = (state->scan_listeners != NULL); bool already = (state->scan_listeners != NULL);
tcp_arg (http_client, l); tcp_arg (http_client, l);
/* TODO: check if also need a tcp_err() cb, or if recv() is enough */ /* TODO: check if also need a tcp_err() cb, or if recv() is enough */
l->conn = http_client; l->conn = http_client;
l->next = state->scan_listeners; l->next = state->scan_listeners;
state->scan_listeners = l; state->scan_listeners = l;
if (!already) if (!already)
{
if (!wifi_station_scan(NULL, on_scan_done))
{ {
enduser_setup_http_serve_header(http_client, http_header_500, LITLEN(http_header_500)); if (!wifi_station_scan(NULL, on_scan_done))
deferred_close (l->conn); {
l->conn = 0; enduser_setup_http_serve_header(http_client, http_header_500, LITLEN(http_header_500));
free_scan_listeners(); deferred_close (l->conn);
l->conn = 0;
free_scan_listeners();
}
} }
goto free_out; /* request queued */
}
else
{
// Return No Content status to the caller
enduser_setup_http_serve_header(http_client, http_header_204, LITLEN(http_header_204));
} }
goto free_out; /* request queued */
} }
else if (c_strncmp(data + 4, "/status ", 8) == 0) else if (c_strncmp(data + 4, "/status.json", 12) == 0)
{
enduser_setup_serve_status_as_json(http_client);
}
else if (c_strncmp(data + 4, "/status", 7) == 0)
{ {
serve_status(http_client); enduser_setup_serve_status(http_client);
} }
else if (c_strncmp(data + 4, "/update?", 8) == 0) else if (c_strncmp(data + 4, "/update?", 8) == 0)
{ {
switch (enduser_setup_http_handle_credentials(data, data_len)) switch (enduser_setup_http_handle_credentials(data, data_len))
...@@ -1101,14 +1158,29 @@ static err_t enduser_setup_http_recvcb(void *arg, struct tcp_pcb *http_client, s ...@@ -1101,14 +1158,29 @@ static err_t enduser_setup_http_recvcb(void *arg, struct tcp_pcb *http_client, s
enduser_setup_http_serve_header(http_client, http_header_302, LITLEN(http_header_302)); enduser_setup_http_serve_header(http_client, http_header_302, LITLEN(http_header_302));
break; break;
case 1: case 1:
enduser_setup_http_serve_header(http_client, http_header_401, LITLEN(http_header_401)); enduser_setup_http_serve_header(http_client, http_header_400, LITLEN(http_header_400));
break; break;
default: default:
ENDUSER_SETUP_ERROR("http_recvcb failed. Failed to handle wifi credentials.", ENDUSER_SETUP_ERR_UNKOWN_ERROR, ENDUSER_SETUP_ERR_NONFATAL); ENDUSER_SETUP_ERROR("http_recvcb failed. Failed to handle wifi credentials.", ENDUSER_SETUP_ERR_UNKOWN_ERROR, ENDUSER_SETUP_ERR_NONFATAL);
break; break;
} }
} }
else if (c_strncmp(data + 4, "/generate_204 ", 14) == 0) else if (c_strncmp(data + 4, "/setwifi?", 9) == 0)
{
switch (enduser_setup_http_handle_credentials(data, data_len))
{
case 0:
enduser_setup_serve_status_as_json(http_client);
break;
case 1:
enduser_setup_http_serve_header(http_client, http_header_400, LITLEN(http_header_400));
break;
default:
ENDUSER_SETUP_ERROR("http_recvcb failed. Failed to handle wifi credentials.", ENDUSER_SETUP_ERR_UNKOWN_ERROR, ENDUSER_SETUP_ERR_NONFATAL);
break;
}
}
else if (c_strncmp(data + 4, "/generate_204", 13) == 0)
{ {
/* Convince Android devices that they have internet access to avoid pesky dialogues. */ /* Convince Android devices that they have internet access to avoid pesky dialogues. */
enduser_setup_http_serve_header(http_client, http_header_204, LITLEN(http_header_204)); enduser_setup_http_serve_header(http_client, http_header_204, LITLEN(http_header_204));
...@@ -1116,13 +1188,16 @@ static err_t enduser_setup_http_recvcb(void *arg, struct tcp_pcb *http_client, s ...@@ -1116,13 +1188,16 @@ static err_t enduser_setup_http_recvcb(void *arg, struct tcp_pcb *http_client, s
else else
{ {
ENDUSER_SETUP_DEBUG("serving 404"); ENDUSER_SETUP_DEBUG("serving 404");
ENDUSER_SETUP_DEBUG(data + 4);
enduser_setup_http_serve_header(http_client, http_header_404, LITLEN(http_header_404)); enduser_setup_http_serve_header(http_client, http_header_404, LITLEN(http_header_404));
} }
} }
else /* not GET */ else if (c_strncmp(data, "OPTIONS ", 8) == 0)
{ {
enduser_setup_http_serve_header(http_client, http_header_401, LITLEN(http_header_401)); enduser_setup_handle_OPTIONS(http_client, data, data_len);
}
else /* not GET or OPTIONS */
{
enduser_setup_http_serve_header(http_client, http_header_405, LITLEN(http_header_405));
} }
deferred_close (http_client); deferred_close (http_client);
...@@ -1135,6 +1210,7 @@ free_out: ...@@ -1135,6 +1210,7 @@ free_out:
static err_t enduser_setup_http_connectcb(void *arg, struct tcp_pcb *pcb, err_t err) static err_t enduser_setup_http_connectcb(void *arg, struct tcp_pcb *pcb, err_t err)
{ {
ENDUSER_SETUP_DEBUG("enduser_setup_http_connectcb"); ENDUSER_SETUP_DEBUG("enduser_setup_http_connectcb");
if (!state) if (!state)
{ {
ENDUSER_SETUP_DEBUG("connect callback but no state?!"); ENDUSER_SETUP_DEBUG("connect callback but no state?!");
...@@ -1208,7 +1284,7 @@ static void enduser_setup_http_stop(void) ...@@ -1208,7 +1284,7 @@ static void enduser_setup_http_stop(void)
static void enduser_setup_ap_stop(void) static void enduser_setup_ap_stop(void)
{ {
ENDUSER_SETUP_DEBUG("enduser_setup_station_stop"); ENDUSER_SETUP_DEBUG("enduser_setup_ap_stop");
wifi_set_opmode(~SOFTAP_MODE & wifi_get_opmode()); wifi_set_opmode(~SOFTAP_MODE & wifi_get_opmode());
} }
...@@ -1234,15 +1310,47 @@ static void enduser_setup_ap_start(void) ...@@ -1234,15 +1310,47 @@ static void enduser_setup_ap_start(void)
cnf.ssid[ssid_name_len] = '_'; cnf.ssid[ssid_name_len] = '_';
c_sprintf(cnf.ssid + ssid_name_len + 1, "%02X%02X%02X", mac[3], mac[4], mac[5]); c_sprintf(cnf.ssid + ssid_name_len + 1, "%02X%02X%02X", mac[3], mac[4], mac[5]);
cnf.ssid_len = ssid_name_len + 7; cnf.ssid_len = ssid_name_len + 7;
cnf.channel = 1; cnf.channel = state == NULL? 1 : state->softAPchannel;
cnf.authmode = AUTH_OPEN; cnf.authmode = AUTH_OPEN;
cnf.ssid_hidden = 0; cnf.ssid_hidden = 0;
cnf.max_connection = 5; cnf.max_connection = 5;
cnf.beacon_interval = 100; cnf.beacon_interval = 100;
wifi_set_opmode(STATIONAP_MODE); wifi_set_opmode(STATIONAP_MODE);
wifi_softap_set_config(&cnf); wifi_softap_set_config(&cnf);
#if ENDUSER_SETUP_DEBUG_ENABLE
char debuginfo[100];
c_sprintf(debuginfo, "SSID: %s, CHAN: %d", cnf.ssid, cnf.channel);
ENDUSER_SETUP_DEBUG(debuginfo);
#endif
} }
static void on_initial_scan_done (void *arg, STATUS status)
{
ENDUSER_SETUP_DEBUG("on_initial_scan_done");
if (!state)
{
return;
}
int8_t rssi = -100;
if (status == OK)
{
for (struct bss_info *wn = arg; wn; wn = wn->next.stqe_next)
{
if (wn->rssi > rssi)
{
state->softAPchannel = wn->channel;
rssi = wn->rssi;
}
}
}
enduser_setup_ap_start();
enduser_setup_check_station_start();
}
static void enduser_setup_dns_recv_callback(void *arg, char *recv_data, unsigned short recv_len) static void enduser_setup_dns_recv_callback(void *arg, char *recv_data, unsigned short recv_len)
{ {
...@@ -1255,6 +1363,31 @@ static void enduser_setup_dns_recv_callback(void *arg, char *recv_data, unsigned ...@@ -1255,6 +1363,31 @@ static void enduser_setup_dns_recv_callback(void *arg, char *recv_data, unsigned
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_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; uint32_t dns_reply_len = dns_reply_static_len + qname_len;
#if ENDUSER_SETUP_DEBUG_ENABLE
char *qname = c_malloc(qname_len + 12);
if (qname != NULL)
{
c_sprintf(qname, "DNS QUERY = %s", &(recv_data[12]));
uint32_t p;
int i, j;
for(i=12;i<(int)strlen(qname);i++)
{
p=qname[i];
for(j=0;j<(int)p;j++)
{
qname[i]=qname[i+1];
i=i+1;
}
qname[i]='.';
}
qname[i-1]='\0';
ENDUSER_SETUP_DEBUG(qname);
c_free(qname);
}
#endif
uint8_t if_mode = wifi_get_opmode(); uint8_t if_mode = wifi_get_opmode();
if ((if_mode & SOFTAP_MODE) == 0) if ((if_mode & SOFTAP_MODE) == 0)
{ {
...@@ -1305,6 +1438,14 @@ static void enduser_setup_dns_recv_callback(void *arg, char *recv_data, unsigned ...@@ -1305,6 +1438,14 @@ static void enduser_setup_dns_recv_callback(void *arg, char *recv_data, unsigned
{ {
ENDUSER_SETUP_ERROR_VOID("dns_recv_callback failed. Can't execute transmission.", ENDUSER_SETUP_ERR_CONNECTION_NOT_FOUND, ENDUSER_SETUP_ERR_FATAL); ENDUSER_SETUP_ERROR_VOID("dns_recv_callback failed. Can't execute transmission.", ENDUSER_SETUP_ERR_CONNECTION_NOT_FOUND, ENDUSER_SETUP_ERR_FATAL);
} }
else if (err == ESPCONN_MAXNUM)
{
ENDUSER_SETUP_ERROR_VOID("dns_recv_callback failed. Buffer full. Discarding...", ENDUSER_SETUP_ERR_MAX_NUMBER, ENDUSER_SETUP_ERR_NONFATAL);
}
else if (err == ESPCONN_IF)
{
ENDUSER_SETUP_ERROR_VOID("dns_recv_callback failed. Send UDP data failed", ENDUSER_SETUP_ERR_UNKOWN_ERROR, ENDUSER_SETUP_ERR_NONFATAL);
}
else if (err != 0) else if (err != 0)
{ {
ENDUSER_SETUP_ERROR_VOID("dns_recv_callback failed. espconn_send failed", ENDUSER_SETUP_ERR_UNKOWN_ERROR, ENDUSER_SETUP_ERR_FATAL); ENDUSER_SETUP_ERROR_VOID("dns_recv_callback failed. espconn_send failed", ENDUSER_SETUP_ERR_UNKOWN_ERROR, ENDUSER_SETUP_ERR_FATAL);
...@@ -1408,6 +1549,7 @@ static void enduser_setup_dns_stop(void) ...@@ -1408,6 +1549,7 @@ static void enduser_setup_dns_stop(void)
static int enduser_setup_init(lua_State *L) static int enduser_setup_init(lua_State *L)
{ {
// Note: Normal to not see this debug message on first invocation because debug callback is set below
ENDUSER_SETUP_DEBUG("enduser_setup_init"); ENDUSER_SETUP_DEBUG("enduser_setup_init");
if (state != NULL) if (state != NULL)
...@@ -1452,12 +1594,19 @@ static int enduser_setup_init(lua_State *L) ...@@ -1452,12 +1594,19 @@ static int enduser_setup_init(lua_State *L)
{ {
lua_pushvalue (L, 3); lua_pushvalue (L, 3);
state->lua_dbg_cb_ref = luaL_ref(L, LUA_REGISTRYINDEX); state->lua_dbg_cb_ref = luaL_ref(L, LUA_REGISTRYINDEX);
ENDUSER_SETUP_DEBUG("enduser_setup_init: Debug callback has been defined");
} }
else else
{ {
state->lua_dbg_cb_ref = LUA_NOREF; state->lua_dbg_cb_ref = LUA_NOREF;
} }
state->softAPchannel = 1;
state->success = 0;
state->callbackDone = 0;
state->lastStationStatus = 0;
state->connecting = 0;
return 0; return 0;
} }
...@@ -1475,6 +1624,7 @@ static int enduser_setup_manual(lua_State *L) ...@@ -1475,6 +1624,7 @@ static int enduser_setup_manual(lua_State *L)
static int enduser_setup_start(lua_State *L) static int enduser_setup_start(lua_State *L)
{ {
// Note: The debug callback is set in enduser_setup_init. It's normal to not see this debug message on first invocation.
ENDUSER_SETUP_DEBUG("enduser_setup_start"); ENDUSER_SETUP_DEBUG("enduser_setup_start");
if (!do_station_cfg_handle) if (!do_station_cfg_handle)
...@@ -1487,10 +1637,14 @@ static int enduser_setup_start(lua_State *L) ...@@ -1487,10 +1637,14 @@ static int enduser_setup_start(lua_State *L)
goto failed; goto failed;
} }
enduser_setup_check_station_start();
if (!manual) if (!manual)
{ {
enduser_setup_ap_start(); ENDUSER_SETUP_DEBUG("Performing AP Scan to identify likely AP's channel");
wifi_station_scan(NULL, on_initial_scan_done);
}
else
{
enduser_setup_check_station_start();
} }
if(enduser_setup_dns_start()) if(enduser_setup_dns_start())
...@@ -1529,6 +1683,12 @@ static int enduser_setup_stop(lua_State* L) ...@@ -1529,6 +1683,12 @@ static int enduser_setup_stop(lua_State* L)
{ {
enduser_setup_ap_stop(); enduser_setup_ap_stop();
} }
if (state->success && !state->callbackDone)
{
wifi_set_opmode(STATION_MODE | wifi_get_opmode());
wifi_station_connect();
enduser_setup_connected_callback();
}
enduser_setup_dns_stop(); enduser_setup_dns_stop();
enduser_setup_http_stop(); enduser_setup_http_stop();
enduser_setup_free(); enduser_setup_free();
......
<!DOCTYPE html>
<html>
<head>
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
<title>WiFi Login</title>
<style type=text/css>
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
font-family: sans-serif;
text-align: center;
background: #444d44;
}
#content {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 320px;
height: 480px;
margin: auto;
}
input,
button,
select {
-webkit-appearance: none;
border-radius: 0;
}
fieldset {
border: 0;
box-shadow: 0 0 15px 1px rgba(0, 0, 0, .4);
box-sizing: border-box;
padding: 20px 30px;
background: #fff;
min-height: 320px;
margin: -1px;
}
input {
border: 1px solid #ccc;
margin-bottom: 10px;
width: 100%;
box-sizing: border-box;
color: #222;
font: 16px monospace;
padding: 15px;
}
select {
font: 16px monospace;
background-color: transparent;
padding: 15px;
}
button {
color: #fff;
border: 0;
border-radius: 3px;
cursor: pointer;
display: block;
font: 16px sans-serif;
text-decoration: none;
padding: 10px 5px;
background: #31b457;
width: 100%;
}
button:focus,
button:hover {
box-shadow: 0 0 0 2px #fff, 0 0 0 3px #31b457;
}
h3 {
font-size: 16px;
color: #666;
margin-bottom: 20px;
}
h4 {
color: #ccc;
padding: 10px;
}
.utility {
float: right;
clear: both;
max-width: 75%;
font-size: 13px;
color: #222;
margin: 10px 0;
padding: 5px 10px;
background: #ccc;
}
.utility:focus,
.utility:hover {
box-shadow: 0 0 0 2px #fff, 0 0 0 3px #ccc;
}
#dropdown,
#f2,
#f3,
#bk2 {
display: none;
}
#dropdown {
position: relative;
width: 100%;
overflow: auto;
height: 51px;
margin-bottom: 10px;
}
#aplist {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
bottom: 0;
border: 1px solid #ccc;
font-family: monospace;
padding: 10px 5px;
}
#arrow {
color: #888;
position: absolute;
right: 8px;
top: 15px;
}
#i {
text-align: justify;
}
</style>
</head>
<body>
<div id=content>
<fieldset>
<div id=deviceId></div>
<div id=f1>
<h3>Connect device to your Wi-Fi</h3>
<button id=networks type=button class=utility></button>
<div id=dropdown>
<span id=arrow>&#x25bc;</span>
<select id=aplist name=aplist></select>
</div>
<input id=ssid type=text autocorrect=off autocapitalize=none placeholder='Wi-Fi Name' />
<input id=wifi_password type=text autocorrect=off autocapitalize=none autocomplete=off placeholder=Password />
<button id=submit type=button>Save</button>
</div>
<div id=f2>
<h1>Success!</h1>
<div id=i>
<h3>Your device has successfully connected to the Wi-Fi network.</h3>
</div>
</div>
<div id=f3>
<h2>Trying...</h2>
<button id=bk2 type=button class='utility'>Go Back to Wi-Fi Setup</button>
</div>
</fieldset>
<h4 id='st'>Updating Status...</h4>
</div>
<script>
var $ = function (selector) { return document.querySelector(selector); };
var ab = $('#networks'), ap = $('#aplist');
var stopAll = false, ra, rs;
function show(f, y) {
if (y == null) y = f;
$(f).style.display = y == f ? 'block' : 'none';
}
function hide(f) {
$(f).style.display = 'none';
}
function to(cb, x) {
return setTimeout(cb, 1000 * x);
}
function refr() {
if (!stopAll)
fetch('/status.json?n=' + Math.random(), 'GET', newSt, 2);
}
function cur(f) {
show('#f1', f);
show('#f2', f);
show('#f3', f);
}
function newSt(s, d) {
clearTimeout(rs);
rs = to(refr, 3);
if (s != 200) {
$('#st').innerText = 'Awaiting Status (' + s + ')';
} else {
if (typeof d === 'string') {
d = JSON.parse(d);
}
$('#deviceId').innerText = d.deviceid;
var c = d.pairing;
var s = [
'Idle',
'Connecting...',
'Failed - wrong password',
'Failed - network not found',
'Failed',
'Wi-Fi successfully connected!'
][d.status];
$('#st').innerText = s;
if (d.status === 5) {
cur('#f2');
stopAll = true;
clearTimeout(ra);
} else if (d.status > 1) {
cur('#f1');
}
}
}
function submit() {
var url = '/setwifi?wifi_ssid=' + encodeURIComponent($('#ssid').value) + '&wifi_password=' + encodeURIComponent($('#wifi_password').value);
clearTimeout(rs);
fetch(url, 'GET', newSt, 2);
cur('#f3');
}
function fetch(url, method, callback, time_out) {
var xhr = new XMLHttpRequest();
xhr.onloadend = function () {
callback(xhr.status, xhr.responseText);
}
xhr.ontimeout = function () {
callback(-1, null);
}
xhr.open(method, url, true);
xhr.setRequestHeader('Accept', 'application/json');
xhr.timeout = (time_out || 10) * 1000;
xhr.send();
}
function gotAp(s, json) {
var list;
if (s === 200 && json != null) {
if (typeof json === 'string' && json.length > 0) {
list = JSON.parse(json);
} else if (typeof json === 'object') {
list = json;
}
list.sort(function (a, b) {
return b.rssi - a.rssi;
});
var ops = '<option>Select a Network...</option>';
for (var i = 0; i < list.length; ++i) {
ops += '<option>' + list[i].ssid + '</option>';
}
ap.innerHTML = ops;
ab.disabled = false;
togAp(null, true);
ab.onclick = togAp;
} else {
ab.innerText = 'No networks found (' + s + ')';
ra = to(refrAp, 5);
}
}
function togAp(ev, force) {
if (!force || ap.style.display == 'block') {
hide('#dropdown');
show('#ssid');
ab.innerText = 'Scan for Networks';
ab.onclick = refrAp;
} else {
show('#dropdown');
hide('#ssid');
ab.innerText = 'Manual Entry';
}
}
function refrAp() {
ab.innerText = 'Searching for networks...';
ab.disabled = true;
ap.innerHTML = '<option disabled>Scanning...</option>';
if (!stopAll)
fetch('/aplist?n=' + Math.random(), 'GET', gotAp, 10);
}
window.onload = function() {
ab.innerText = 'Scan for Networks';
ab.onclick = refrAp;
$('#aplist').onchange = function () {
$('#ssid').value = $('#aplist').value;
};
$('#submit').onclick = submit;
$('#bk2').onclick = function () {
cur('#f1')
}
rs = to(refr, 0.5);
}
</script>
</body>
</html>
\ No newline at end of file
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