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
static const char http_html_backup[] = {
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x95, 0x59,
0xfd, 0x72, 0xdb, 0x36, 0x12, 0xff, 0xbb, 0x37, 0x73, 0xef, 0xb0, 0x1e,
0xf7, 0x42, 0xb9, 0xa1, 0x64, 0x7d, 0xd8, 0x69, 0xc6, 0x12, 0xd5, 0xc9,
0xe5, 0x92, 0x26, 0x37, 0x49, 0xda, 0xa9, 0xdd, 0xe9, 0x75, 0x32, 0x99,
0x0e, 0x44, 0x82, 0x26, 0x62, 0x0a, 0xe0, 0x01, 0xa0, 0x65, 0x5d, 0xea,
0x77, 0x3f, 0x2c, 0x01, 0x5a, 0x86, 0x40, 0x87, 0xb5, 0x5a, 0x57, 0x04,
0xb0, 0xdf, 0xfb, 0xc3, 0xee, 0x52, 0x5d, 0x1c, 0xfc, 0xeb, 0xa7, 0x97,
0x17, 0xbf, 0xff, 0xfc, 0x0a, 0x0a, 0xbd, 0x2e, 0x97, 0x7f, 0xff, 0xdb,
0xc2, 0x7d, 0xe3, 0x13, 0x25, 0x99, 0x79, 0xfa, 0x66, 0xb1, 0xa6, 0x9a,
0x00, 0x27, 0x6b, 0x9a, 0x44, 0xd7, 0x8c, 0x6e, 0x2a, 0x21, 0x75, 0x04,
0xa9, 0xe0, 0x9a, 0x72, 0x9d, 0x44, 0x1b, 0x96, 0xe9, 0x22, 0xc9, 0xe8,
0x35, 0x4b, 0xe9, 0xb0, 0x59, 0xc4, 0xc0, 0x38, 0xd3, 0x8c, 0x94, 0x43,
0x95, 0x92, 0x92, 0x26, 0x93, 0xd1, 0x38, 0x6a, 0x04, 0x69, 0xa6, 0x4b,
0xba, 0xfc, 0x8d, 0xbd, 0x66, 0xf0, 0x4e, 0x5c, 0x32, 0xbe, 0x38, 0xb6,
0x3b, 0x78, 0xa6, 0xf4, 0xb6, 0xa4, 0xa0, 0xb7, 0x15, 0x4d, 0x34, 0xbd,
0xd1, 0xc7, 0xa9, 0x52, 0xb8, 0xff, 0xcd, 0x77, 0xf0, 0x05, 0xbf, 0xbe,
0x59, 0x13, 0x69, 0x38, 0xce, 0x60, 0x3c, 0x6f, 0x96, 0x15, 0xc9, 0x32,
0xc6, 0x2f, 0xdb, 0xf5, 0x2d, 0xfe, 0x07, 0xff, 0xd0, 0xfc, 0x18, 0x1f,
0x56, 0x22, 0xdb, 0x3a, 0xd6, 0x82, 0xb2, 0xcb, 0x42, 0x9f, 0xc1, 0x64,
0x3c, 0xfe, 0x87, 0xe5, 0xce, 0x8d, 0xf1, 0xc3, 0x9c, 0xac, 0x59, 0xb9,
0x3d, 0x03, 0x45, 0xb8, 0x1a, 0x2a, 0x2a, 0x59, 0x6e, 0x0f, 0x51, 0xfd,
0x90, 0x94, 0xec, 0xd2, 0x68, 0x4b, 0x29, 0xd7, 0x54, 0xda, 0xfd, 0x15,
0x49, 0xaf, 0x2e, 0xa5, 0xa8, 0x79, 0x76, 0x06, 0x87, 0x27, 0x27, 0x27,
0xd9, 0xc9, 0x89, 0xaf, 0xfb, 0xd0, 0xc5, 0xc4, 0xa9, 0xad, 0x84, 0x62,
0x9a, 0x09, 0x23, 0x85, 0xac, 0x94, 0x28, 0x6b, 0x4d, 0x9d, 0x7c, 0x51,
0xdd, 0xb9, 0x21, 0xad, 0x65, 0x6e, 0xb5, 0x12, 0x5a, 0x8b, 0xf5, 0xdd,
0xb2, 0xa4, 0xf9, 0xee, 0xac, 0x89, 0xec, 0x19, 0xcc, 0xa6, 0xe3, 0xea,
0x66, 0xee, 0xb9, 0x75, 0xf2, 0x1c, 0xb7, 0xbc, 0x20, 0x91, 0x5a, 0x0b,
0xdf, 0x36, 0xc6, 0xab, 0x5a, 0xdb, 0xc0, 0xd4, 0x46, 0x09, 0x6f, 0x1e,
0x15, 0x2d, 0x69, 0xda, 0x9a, 0x3b, 0xdc, 0xd0, 0xd5, 0x15, 0x33, 0x9e,
0x57, 0x15, 0x25, 0x92, 0xf0, 0x94, 0x9e, 0x01, 0x17, 0x9c, 0xb6, 0xa6,
0xc9, 0x8c, 0xca, 0xa1, 0x24, 0x19, 0xab, 0x55, 0x10, 0xf5, 0x9c, 0xd1,
0x32, 0x53, 0xd4, 0x89, 0x72, 0xc4, 0xf7, 0xdc, 0xba, 0x19, 0xaa, 0x82,
0x64, 0x62, 0x63, 0xb6, 0xcc, 0x3f, 0x93, 0xd3, 0xea, 0x06, 0x26, 0xe6,
0x4f, 0x5e, 0xae, 0xc8, 0x60, 0x1c, 0x83, 0xfd, 0x77, 0x74, 0x72, 0x74,
0x8f, 0x9e, 0xfd, 0xaf, 0x49, 0xaf, 0xd3, 0x6b, 0xb6, 0xf6, 0xf2, 0x8e,
0x71, 0x80, 0x19, 0x7a, 0x1e, 0x26, 0x27, 0xcf, 0x73, 0x17, 0x0f, 0xc6,
0x87, 0x36, 0x4c, 0x18, 0xb9, 0x20, 0x4c, 0x43, 0x63, 0x44, 0x18, 0xa6,
0x7d, 0x2f, 0xd0, 0x52, 0x93, 0x3f, 0x96, 0xc1, 0x61, 0x9a, 0xa6, 0xf7,
0x25, 0x0c, 0xdb, 0x84, 0x4d, 0x9c, 0x68, 0x97, 0x26, 0x07, 0xb5, 0x5e,
0x67, 0x52, 0x51, 0x0a, 0x69, 0xec, 0x9d, 0x4e, 0xa7, 0x3b, 0x5c, 0x1a,
0xe6, 0x67, 0x46, 0xe3, 0x5a, 0x70, 0xa1, 0x2a, 0x92, 0x52, 0xdf, 0x6f,
0x0c, 0x9e, 0x6f, 0xb3, 0x9f, 0xc5, 0x6e, 0x09, 0x7e, 0x84, 0x86, 0x4e,
0xaf, 0x36, 0x59, 0x36, 0x04, 0x92, 0x72, 0xdd, 0xa7, 0xc4, 0xa1, 0xc6,
0x29, 0xb1, 0xfc, 0x2e, 0xce, 0x41, 0xc2, 0x03, 0xb0, 0xcc, 0xaa, 0xd6,
0xdf, 0x5a, 0x2a, 0x64, 0xac, 0x04, 0xdb, 0x5d, 0xab, 0x8c, 0xa9, 0xaa,
0x24, 0x5b, 0x13, 0x9d, 0x52, 0xa4, 0x57, 0x41, 0x1c, 0x3a, 0x6f, 0x67,
0x46, 0x53, 0x21, 0x89, 0xbd, 0x5c, 0x0e, 0xa3, 0x9e, 0xf9, 0x88, 0x8d,
0xd3, 0x4e, 0x68, 0xcc, 0x26, 0xab, 0x93, 0xd3, 0xef, 0xc3, 0x5c, 0x75,
0x38, 0x7b, 0x96, 0x8b, 0xb4, 0x56, 0xf1, 0xbd, 0x8d, 0x42, 0x5c, 0x53,
0x09, 0x5f, 0x3a, 0x41, 0x3d, 0x86, 0xa9, 0x51, 0x8a, 0x21, 0x89, 0xed,
0x1a, 0xdd, 0xde, 0xe9, 0xf3, 0x6a, 0xd4, 0xec, 0x5e, 0xb2, 0x10, 0x1c,
0xd4, 0xfa, 0xea, 0x83, 0xe2, 0xd9, 0xb3, 0x67, 0x9d, 0x58, 0xb3, 0x30,
0xf6, 0xe4, 0x9d, 0x78, 0x79, 0x71, 0x30, 0xf5, 0x23, 0x12, 0x30, 0x8d,
0x6a, 0xcd, 0x4a, 0xa6, 0xb7, 0xad, 0x29, 0xa5, 0x20, 0x26, 0xe4, 0x4d,
0x3d, 0x72, 0x76, 0x94, 0x94, 0x48, 0xc4, 0xac, 0x2e, 0x5a, 0x3b, 0x6e,
0x86, 0x2e, 0x64, 0xdf, 0x9f, 0xda, 0x88, 0x79, 0x1e, 0xcc, 0xaa, 0x6e,
0x58, 0xb7, 0x1e, 0x58, 0x2b, 0x82, 0x02, 0xde, 0x14, 0x83, 0xee, 0x7b,
0xec, 0xfc, 0x08, 0x8d, 0x76, 0xa9, 0xf1, 0xb6, 0x1e, 0x9f, 0x9c, 0x50,
0xfe, 0x61, 0x26, 0x45, 0x65, 0xb8, 0x78, 0xdc, 0xac, 0xf2, 0xa9, 0xfb,
0x9e, 0xd9, 0xef, 0xd5, 0xd5, 0xd4, 0x29, 0x70, 0xa0, 0x75, 0xe8, 0xeb,
0x96, 0x11, 0xb4, 0x01, 0x49, 0x4b, 0xa2, 0xd9, 0x35, 0x7d, 0xa0, 0x52,
0xa0, 0xfd, 0x26, 0x0d, 0x1b, 0x57, 0xbe, 0xbd, 0x1a, 0x7f, 0xea, 0x2a,
0x55, 0x77, 0xe5, 0xf1, 0xf5, 0x93, 0xaa, 0x64, 0xaa, 0xa7, 0x09, 0x85,
0xda, 0xc3, 0x26, 0xa9, 0x45, 0x15, 0xb4, 0xa2, 0xa0, 0x4d, 0xf5, 0xd4,
0x49, 0xaf, 0xd1, 0x7a, 0x05, 0x29, 0xb8, 0xae, 0xa1, 0x1f, 0x52, 0x8a,
0xcd, 0x1e, 0xb2, 0x9f, 0x3f, 0x7f, 0x3e, 0xff, 0xaa, 0x5f, 0xae, 0xa1,
0x3e, 0xb7, 0xd2, 0x9c, 0x13, 0x93, 0x50, 0x38, 0x83, 0x2f, 0x41, 0xb3,
0xff, 0x5c, 0x2b, 0xcd, 0xf2, 0xed, 0x1d, 0xe5, 0xe2, 0xb8, 0x19, 0x4a,
0x70, 0x2a, 0x3a, 0x76, 0xc3, 0x90, 0x79, 0xc4, 0xc1, 0x62, 0x89, 0xa7,
0x19, 0xbb, 0x06, 0x96, 0x25, 0xae, 0xe9, 0x2f, 0x91, 0x6b, 0xe1, 0x1a,
0xa1, 0x5d, 0xb5, 0x24, 0x6e, 0x38, 0x7a, 0x9b, 0x2d, 0x17, 0xc7, 0x66,
0xc7, 0x3f, 0xcb, 0x27, 0xb8, 0xc6, 0x8d, 0x62, 0xb6, 0x7c, 0x29, 0x38,
0xc7, 0x5a, 0x6e, 0x19, 0x40, 0x0b, 0xd8, 0x8a, 0x5a, 0xc2, 0x6f, 0x6c,
0xf8, 0x9a, 0x19, 0x1b, 0x66, 0x2d, 0xa9, 0xad, 0x47, 0xc8, 0xce, 0xa9,
0xde, 0x08, 0x79, 0xa5, 0xec, 0xe4, 0xe4, 0xf6, 0xd3, 0x92, 0x28, 0x95,
0xb8, 0x8b, 0x61, 0x94, 0xda, 0x6d, 0xc7, 0xdc, 0x2a, 0x76, 0x30, 0xb5,
0xdb, 0xb8, 0x6f, 0x52, 0xd3, 0x88, 0x6c, 0xe2, 0xbe, 0x7c, 0x72, 0x78,
0x33, 0x3d, 0x5d, 0xa5, 0x73, 0x13, 0x84, 0x8a, 0xec, 0x88, 0x6c, 0xb3,
0x41, 0x32, 0x07, 0x33, 0x9c, 0x0b, 0xdd, 0xb3, 0xd1, 0x64, 0x8f, 0x1d,
0xb5, 0xf3, 0xd6, 0x3e, 0xdb, 0xce, 0x6a, 0xf8, 0x94, 0x62, 0xd9, 0x6e,
0xce, 0x6b, 0xb0, 0x9e, 0x0a, 0x29, 0x0d, 0x5b, 0x22, 0xf2, 0xdc, 0xae,
0x49, 0xc5, 0x34, 0x29, 0x4d, 0x59, 0x49, 0xf0, 0x7e, 0x41, 0x55, 0x92,
0x94, 0x16, 0xa2, 0xcc, 0xa8, 0x4c, 0xa2, 0x26, 0x18, 0xf0, 0xc1, 0xa8,
0x8d, 0xe0, 0x38, 0x90, 0xbe, 0x61, 0x39, 0xfb, 0xa3, 0x32, 0xee, 0x9b,
0xa8, 0x3c, 0x52, 0x8d, 0xa3, 0x59, 0x57, 0x25, 0xd5, 0x14, 0x89, 0x3c,
0xbd, 0x3f, 0xb7, 0x32, 0x8f, 0xc3, 0x24, 0xa8, 0x7a, 0xb5, 0x66, 0xfa,
0x7e, 0x0a, 0x96, 0xe7, 0xe4, 0x9a, 0xfa, 0x81, 0xef, 0xca, 0xfd, 0xf4,
0x2e, 0xf7, 0x93, 0xe5, 0x79, 0x9d, 0xa6, 0x54, 0xa9, 0x03, 0x93, 0xe7,
0xc9, 0x5e, 0xaa, 0x98, 0x5d, 0x5b, 0x8c, 0xfc, 0x8e, 0x88, 0x70, 0x00,
0x29, 0x88, 0x02, 0x65, 0xf9, 0xf2, 0xba, 0x2c, 0xb7, 0x90, 0x5a, 0x00,
0xd1, 0x0c, 0xb1, 0xa3, 0x0b, 0x0a, 0x36, 0x5a, 0x0e, 0x25, 0x23, 0xc4,
0x50, 0x98, 0x9c, 0x2e, 0xcb, 0xee, 0xc8, 0x8a, 0xe9, 0xf2, 0x42, 0x6e,
0xcd, 0x3d, 0x1d, 0x8d, 0x90, 0x7d, 0x1a, 0x7a, 0x8f, 0x55, 0x31, 0x44,
0x5f, 0xe4, 0xe0, 0x17, 0x2d, 0x7f, 0x14, 0xf0, 0x4f, 0x53, 0xd5, 0xd1,
0x22, 0x6b, 0xcd, 0x39, 0xd5, 0x75, 0xd5, 0x1d, 0x1c, 0x7c, 0xf2, 0xee,
0xd0, 0xa2, 0x38, 0x41, 0x1d, 0x91, 0xd2, 0xd1, 0xf2, 0xd7, 0x2a, 0x23,
0xda, 0x58, 0x02, 0xe7, 0x9a, 0xe8, 0x5a, 0x59, 0x83, 0x4e, 0x90, 0xec,
0x8e, 0x7d, 0xa1, 0x52, 0xc9, 0x2a, 0x64, 0x05, 0xf7, 0xb9, 0x26, 0x12,
0xbe, 0x85, 0x04, 0xf2, 0x9a, 0xa7, 0x58, 0x30, 0x60, 0x60, 0x31, 0x2a,
0xe4, 0x11, 0x7c, 0x01, 0x69, 0x4c, 0x91, 0x1c, 0x32, 0x91, 0xd6, 0x6b,
0xca, 0xf5, 0xe8, 0xbf, 0x35, 0x95, 0xdb, 0x73, 0x47, 0xb0, 0xa3, 0x9c,
0xc3, 0xed, 0xdc, 0x17, 0x49, 0x56, 0x46, 0xe6, 0xb7, 0x83, 0xe8, 0xb0,
0xbd, 0x80, 0xd1, 0x51, 0x0c, 0xa4, 0x72, 0x9b, 0xf6, 0x3e, 0x44, 0x47,
0x7b, 0x4c, 0x4a, 0x8b, 0xea, 0x45, 0x59, 0xa2, 0x35, 0xa4, 0x54, 0x34,
0x06, 0x49, 0xcc, 0x9f, 0x32, 0x54, 0x77, 0x74, 0x3b, 0x3b, 0x55, 0x21,
0x36, 0x83, 0x3c, 0x86, 0xad, 0xb1, 0xd3, 0x1d, 0xbb, 0x0f, 0xcb, 0x61,
0xb0, 0x85, 0x24, 0x01, 0x6e, 0x72, 0x7e, 0x04, 0x5b, 0x94, 0x37, 0xf7,
0x48, 0x8c, 0x11, 0xf9, 0xd1, 0xa8, 0xa9, 0x5e, 0x23, 0xdb, 0xaa, 0x90,
0xa8, 0xe1, 0xc9, 0xe1, 0x07, 0x88, 0x9a, 0x51, 0x2b, 0x82, 0x33, 0x88,
0x10, 0xf8, 0xd1, 0x3d, 0xe6, 0xdb, 0x0e, 0x4b, 0x0a, 0x96, 0xd1, 0x41,
0x8e, 0x66, 0xf4, 0xea, 0xf8, 0x6b, 0x02, 0xb5, 0x18, 0xa4, 0xab, 0x18,
0x6e, 0x02, 0x91, 0x2e, 0x1d, 0x8a, 0xea, 0x0b, 0xb6, 0xa6, 0xa2, 0xd6,
0x48, 0x87, 0x2d, 0x69, 0x0c, 0xdf, 0x19, 0xf2, 0x1e, 0xb1, 0x92, 0xe6,
0x72, 0xd0, 0x19, 0xad, 0x03, 0x17, 0xf9, 0x23, 0xef, 0xc8, 0x72, 0x53,
0x9d, 0x16, 0x83, 0xe8, 0x58, 0x59, 0x4c, 0x7d, 0x56, 0x82, 0xff, 0xc0,
0x93, 0x08, 0x9e, 0xc2, 0x7b, 0xa2, 0x8b, 0x91, 0x24, 0x3c, 0x13, 0xeb,
0x81, 0x49, 0x6e, 0xf4, 0xe3, 0xab, 0x8b, 0x28, 0x06, 0x4e, 0x37, 0xe7,
0x3a, 0x86, 0x69, 0x9f, 0x31, 0x69, 0x2d, 0xc3, 0x98, 0xd9, 0xa4, 0x46,
0x87, 0xf9, 0xc4, 0x48, 0xca, 0x9d, 0x88, 0xe0, 0x70, 0xfa, 0xb5, 0xc3,
0x19, 0x1e, 0xf6, 0x28, 0xb7, 0x46, 0x0e, 0x54, 0x0c, 0x59, 0x60, 0x41,
0x33, 0xd6, 0xb5, 0xd1, 0x95, 0x6a, 0x5f, 0x8d, 0x54, 0x90, 0x60, 0x7e,
0x30, 0x96, 0x31, 0xcc, 0xf0, 0x38, 0x0c, 0xa7, 0x82, 0x83, 0xc4, 0xcc,
0xa1, 0xe3, 0x40, 0x38, 0x7e, 0x10, 0xff, 0x88, 0xfd, 0x11, 0xe3, 0x9c,
0xca, 0x0b, 0x7a, 0xa3, 0x11, 0x16, 0x2f, 0x36, 0x84, 0xdd, 0xbb, 0xbb,
0x30, 0xc0, 0x08, 0x2b, 0xf3, 0x17, 0x1d, 0x45, 0x7b, 0x26, 0xdc, 0x02,
0x2d, 0x15, 0x0d, 0x44, 0x3b, 0xdd, 0x58, 0x69, 0x44, 0x0e, 0x99, 0xc1,
0xb2, 0x11, 0xab, 0xb4, 0x34, 0x42, 0xa3, 0xc0, 0x10, 0xf7, 0x41, 0x32,
0xf8, 0xf7, 0xf9, 0x4f, 0x1f, 0x46, 0x15, 0x91, 0x8a, 0x0e, 0xb2, 0x7d,
0x77, 0x5d, 0x00, 0xbb, 0xbd, 0x68, 0xdb, 0xf6, 0x9e, 0x2f, 0xd9, 0xc8,
0x1e, 0xb0, 0x2c, 0x08, 0x4e, 0x7b, 0xd1, 0xd3, 0x86, 0xac, 0x22, 0x0c,
0xad, 0x7b, 0x90, 0x0a, 0x43, 0xfd, 0xb1, 0xdb, 0xee, 0xe8, 0x6d, 0x56,
0xd2, 0x28, 0x7e, 0xe0, 0xd0, 0x8d, 0x09, 0xb6, 0x28, 0x3f, 0x48, 0xf5,
0x9a, 0xb0, 0x92, 0x66, 0x30, 0x84, 0x8d, 0x14, 0x26, 0xf0, 0x6d, 0x53,
0xec, 0xa7, 0x77, 0x25, 0x0d, 0xb8, 0xd0, 0x90, 0x8b, 0x9a, 0xf7, 0xb1,
0x3c, 0x78, 0x6c, 0xcb, 0x7d, 0x77, 0x83, 0x3a, 0x88, 0x42, 0xa6, 0x4f,
0x1f, 0xb3, 0x91, 0xbd, 0x87, 0x9f, 0xda, 0xa0, 0xf5, 0x43, 0x4b, 0x39,
0xd2, 0x10, 0x2a, 0xad, 0xb0, 0x06, 0x2a, 0xa7, 0x0f, 0x61, 0x04, 0x6f,
0xaa, 0xbd, 0x75, 0x01, 0x38, 0xdc, 0x67, 0x57, 0xb6, 0xb5, 0xac, 0x69,
0x40, 0xd4, 0x75, 0xaf, 0x48, 0x87, 0x2c, 0x07, 0x6c, 0xdf, 0xb4, 0x25,
0x4c, 0xfa, 0x0c, 0x9b, 0x44, 0x0f, 0xa0, 0xb6, 0x7b, 0xd9, 0x59, 0x10,
0xec, 0x84, 0x12, 0x16, 0x47, 0x84, 0x61, 0x2d, 0xd1, 0x35, 0x53, 0x01,
0xa9, 0xc6, 0xe9, 0xe9, 0x87, 0x66, 0x84, 0xc2, 0x29, 0xad, 0xa9, 0x82,
0x94, 0xa7, 0x22, 0xa3, 0xbf, 0xfe, 0xf2, 0xf6, 0xa5, 0x58, 0x57, 0x82,
0x53, 0xae, 0x07, 0x98, 0x06, 0x3c, 0x37, 0x89, 0xb8, 0x26, 0x65, 0x4d,
0x8f, 0xf0, 0x1a, 0x3f, 0xf1, 0x26, 0xaf, 0xaf, 0xb1, 0x7a, 0x84, 0x77,
0x32, 0xe6, 0xbd, 0x65, 0x2a, 0xac, 0xda, 0xc6, 0xf2, 0xee, 0xba, 0x1c,
0x06, 0x71, 0x16, 0xf5, 0xd5, 0xcc, 0x7b, 0x22, 0xd7, 0x54, 0x17, 0x22,
0x8b, 0x21, 0x25, 0x65, 0x89, 0x2f, 0xa4, 0x31, 0x68, 0x63, 0xc9, 0x1f,
0xc6, 0x94, 0xce, 0x00, 0xde, 0x14, 0x12, 0x12, 0x34, 0x00, 0xfe, 0xf3,
0xfe, 0xdd, 0x1b, 0xad, 0xab, 0x5f, 0xa8, 0x99, 0x23, 0x94, 0x1e, 0xec,
0xd9, 0x82, 0x84, 0x23, 0xc1, 0x4b, 0x41, 0x32, 0xca, 0x33, 0x6f, 0x26,
0xe9, 0xc4, 0x40, 0xab, 0x7e, 0x80, 0x7c, 0x16, 0x2f, 0x71, 0x23, 0x43,
0x52, 0x65, 0xe2, 0xa9, 0x28, 0xde, 0x80, 0x7d, 0x1d, 0xb7, 0x5d, 0x2a,
0xb5, 0x0d, 0xe4, 0x23, 0x54, 0x0e, 0x27, 0xb1, 0x1d, 0x2f, 0xfe, 0x82,
0xf8, 0x8a, 0xf2, 0x41, 0x1b, 0x32, 0x8c, 0x5f, 0x73, 0x4d, 0xba, 0x7c,
0x57, 0x54, 0xbb, 0xd0, 0xbc, 0xa1, 0x24, 0xa3, 0x26, 0x31, 0x2f, 0xd2,
0x94, 0x56, 0xda, 0xa4, 0x2f, 0x22, 0x55, 0x55, 0xb2, 0x94, 0xa0, 0x6d,
0xc7, 0xd8, 0x84, 0xa3, 0x2e, 0x01, 0x3b, 0x3f, 0x06, 0x6d, 0x46, 0xe0,
0xcf, 0x3f, 0x61, 0x62, 0x3a, 0xd1, 0x77, 0xcd, 0x98, 0xd0, 0xa9, 0x94,
0x67, 0x83, 0xbe, 0xe4, 0x5f, 0x0a, 0xfd, 0xa2, 0xc2, 0x86, 0x89, 0xaa,
0x3b, 0x93, 0x8c, 0x03, 0xdd, 0xbc, 0xab, 0x15, 0x26, 0x49, 0xd3, 0x0b,
0xe1, 0xc9, 0x93, 0x86, 0x19, 0x0e, 0xdc, 0x5c, 0xd6, 0xd3, 0xc0, 0x90,
0xd6, 0xeb, 0x61, 0xad, 0x80, 0x51, 0x49, 0xf9, 0xa5, 0x2e, 0x60, 0x09,
0xe3, 0x07, 0x2b, 0x03, 0x1a, 0xe3, 0x77, 0x36, 0xe4, 0xec, 0xa9, 0x39,
0x81, 0x62, 0xb1, 0xfa, 0x4c, 0x53, 0x1d, 0xf5, 0x69, 0x41, 0x86, 0x9e,
0xb6, 0xe9, 0xb1, 0x8c, 0x94, 0x90, 0x7a, 0xb0, 0x03, 0x1a, 0x89, 0x61,
0xe5, 0xeb, 0x08, 0x27, 0xbe, 0xd5, 0x48, 0x2a, 0xc5, 0x60, 0x08, 0xa4,
0x79, 0xe8, 0x52, 0x17, 0x78, 0xe7, 0x12, 0x23, 0x2a, 0x85, 0xe5, 0x6b,
0x21, 0x2a, 0x54, 0xb7, 0xb4, 0xc3, 0x3b, 0x10, 0xf8, 0x60, 0xbb, 0x58,
0xf3, 0x96, 0xe0, 0xce, 0xa2, 0x0e, 0x11, 0xb9, 0x90, 0x30, 0x40, 0x39,
0xcc, 0x48, 0x19, 0xcf, 0xcd, 0xd7, 0xc2, 0x7a, 0x61, 0xd3, 0x30, 0x87,
0xa7, 0x4f, 0xd9, 0x83, 0xd6, 0xa3, 0xee, 0xa7, 0xf7, 0x94, 0x63, 0xd5,
0x43, 0xe6, 0x8f, 0xec, 0xd3, 0x08, 0x2b, 0x24, 0x16, 0xc6, 0xaf, 0x6a,
0xbf, 0x0d, 0xb7, 0x48, 0x65, 0xdb, 0xdb, 0x9b, 0x8b, 0xf7, 0xef, 0x20,
0x41, 0x15, 0x1d, 0x7c, 0x64, 0x85, 0x33, 0x37, 0x59, 0x95, 0x34, 0x6b,
0xdf, 0x26, 0x3a, 0xa8, 0xb4, 0xb8, 0x34, 0xa8, 0x46, 0x34, 0x76, 0xdf,
0x49, 0x27, 0x49, 0xf0, 0xb4, 0x64, 0xe9, 0x15, 0x24, 0x96, 0xa1, 0x67,
0x1c, 0xf3, 0x58, 0xbd, 0x19, 0xef, 0x83, 0x68, 0x47, 0x07, 0x65, 0xe7,
0x86, 0xae, 0x29, 0xcf, 0x4b, 0x3e, 0xd9, 0x0d, 0x9b, 0x2f, 0xaa, 0xd8,
0xf4, 0xe8, 0xf9, 0x63, 0xba, 0x9a, 0xf3, 0x8f, 0x5e, 0xc7, 0x98, 0xc5,
0x94, 0x76, 0x8f, 0xfe, 0xcd, 0x11, 0x56, 0x09, 0x52, 0xed, 0xbf, 0xad,
0x24, 0xed, 0x9b, 0x50, 0x57, 0x82, 0xed, 0x6b, 0x4f, 0xd4, 0xfe, 0x9c,
0xe7, 0x17, 0x24, 0x7f, 0x2a, 0x77, 0xdd, 0x70, 0xde, 0x1f, 0xa2, 0xf3,
0x94, 0x70, 0x34, 0xb6, 0x45, 0xa7, 0x8a, 0xfa, 0x52, 0x82, 0xb1, 0xe9,
0xc9, 0x49, 0x60, 0x50, 0x60, 0x74, 0xe8, 0xd8, 0x63, 0x8c, 0x7e, 0x4f,
0x78, 0x4d, 0x4a, 0x78, 0xc5, 0xb5, 0xdc, 0x46, 0x8f, 0xca, 0x90, 0xb3,
0x3e, 0xec, 0x35, 0x41, 0x5c, 0x28, 0x91, 0x69, 0x61, 0xca, 0x20, 0x06,
0xe7, 0x0e, 0x45, 0xe6, 0xee, 0x3a, 0x7d, 0xdd, 0xc0, 0x0f, 0xe7, 0xb1,
0xe0, 0xfa, 0xb4, 0x57, 0x13, 0x5a, 0xae, 0x25, 0xa6, 0x80, 0x1b, 0x4d,
0x61, 0x61, 0x78, 0xf4, 0x3b, 0xa3, 0x7d, 0xcd, 0xff, 0xda, 0xeb, 0xa2,
0x6d, 0x2c, 0xf8, 0x0a, 0xfb, 0x40, 0x07, 0xda, 0x30, 0xc3, 0xb0, 0x71,
0x53, 0xc1, 0xbd, 0xfe, 0xec, 0x85, 0xec, 0xf1, 0x40, 0xea, 0x81, 0x90,
0xf7, 0x23, 0x05, 0x52, 0x16, 0x84, 0x5f, 0xd2, 0xbe, 0xf1, 0x60, 0x7f,
0xee, 0xf3, 0x7f, 0xec, 0x70, 0x9b, 0x9e, 0x9a, 0xdb, 0x40, 0xa9, 0x1d,
0x44, 0xad, 0x52, 0x67, 0x9e, 0xdd, 0x0a, 0x28, 0x57, 0x57, 0x53, 0x8f,
0xac, 0xd3, 0xb4, 0x70, 0x54, 0xf6, 0xd4, 0xe3, 0xa2, 0xfb, 0xcd, 0x76,
0x3c, 0x3a, 0x0d, 0x32, 0xb2, 0x38, 0xbe, 0xfb, 0xf5, 0x68, 0x71, 0xec,
0x7e, 0xe6, 0xc5, 0xc7, 0xe6, 0x7f, 0x89, 0xff, 0x1f, 0x01, 0x02, 0x3f,
0xe6, 0x2a, 0x1f, 0x00, 0x00
};
unsigned int http_html_backup_len = 2393;
#!/bin/sh
# Uses zopfli for better gzip compression
# sudo apt-get install zopfli
zopfli --gzip ./enduser_setup.html
xxd -i ./enduser_setup.html.gz | sed 's/unsigned char/static const char/; s/__enduser_setup_html_gz/http_html_backup/' > http_html_backup.def
...@@ -2,15 +2,24 @@ ...@@ -2,15 +2,24 @@
#include "module.h" #include "module.h"
#include "lauxlib.h" #include "lauxlib.h"
#include "lmem.h"
#include "platform.h" #include "platform.h"
#include "c_types.h" #include "c_types.h"
#include "vfs.h" #include "vfs.h"
#include "c_string.h" #include "c_string.h"
#include <alloca.h>
#define FILE_READ_CHUNK 1024
static int file_fd = 0; static int file_fd = 0;
static int file_fd_ref = LUA_NOREF;
static int rtc_cb_ref = LUA_NOREF; static int rtc_cb_ref = LUA_NOREF;
typedef struct _file_fd_ud {
int fd;
} file_fd_ud;
static void table2tm( lua_State *L, vfs_time *tm ) static void table2tm( lua_State *L, vfs_time *tm )
{ {
...@@ -91,13 +100,48 @@ static int file_on(lua_State *L) ...@@ -91,13 +100,48 @@ static int file_on(lua_State *L)
// Lua: close() // Lua: close()
static int file_close( lua_State* L ) static int file_close( lua_State* L )
{ {
if(file_fd){ int need_pop = FALSE;
vfs_close(file_fd); file_fd_ud *ud;
file_fd = 0;
if (lua_type( L, 1 ) != LUA_TUSERDATA) {
// fall back to last opened file
if (file_fd_ref != LUA_NOREF) {
lua_rawgeti( L, LUA_REGISTRYINDEX, file_fd_ref );
// top of stack is now default file descriptor
ud = (file_fd_ud *)luaL_checkudata(L, -1, "file.obj");
lua_pop( L, 1 );
} else {
// no default file currently opened
return 0;
}
} else {
ud = (file_fd_ud *)luaL_checkudata(L, 1, "file.obj");
}
// unref default file descriptor
luaL_unref( L, LUA_REGISTRYINDEX, file_fd_ref );
file_fd_ref = LUA_NOREF;
if(ud->fd){
vfs_close(ud->fd);
// mark as closed
ud->fd = 0;
} }
return 0; return 0;
} }
static int file_obj_free( lua_State *L )
{
file_fd_ud *ud = (file_fd_ud *)luaL_checkudata(L, 1, "file.obj");
if (ud->fd) {
// close file if it's still open
vfs_close(ud->fd);
ud->fd = 0;
}
return 0;
}
// Lua: format() // Lua: format()
static int file_format( lua_State* L ) static int file_format( lua_State* L )
{ {
...@@ -130,10 +174,10 @@ static int file_fscfg (lua_State *L) ...@@ -130,10 +174,10 @@ static int file_fscfg (lua_State *L)
static int file_open( lua_State* L ) static int file_open( lua_State* L )
{ {
size_t len; size_t len;
if(file_fd){
vfs_close(file_fd); // unref last file descriptor to allow gc'ing if not kept by user script
file_fd = 0; luaL_unref( L, LUA_REGISTRYINDEX, file_fd_ref );
} file_fd_ref = LUA_NOREF;
const char *fname = luaL_checklstring( L, 1, &len ); const char *fname = luaL_checklstring( L, 1, &len );
const char *basename = vfs_basename( fname ); const char *basename = vfs_basename( fname );
...@@ -146,7 +190,14 @@ static int file_open( lua_State* L ) ...@@ -146,7 +190,14 @@ static int file_open( lua_State* L )
if(!file_fd){ if(!file_fd){
lua_pushnil(L); lua_pushnil(L);
} else { } else {
lua_pushboolean(L, 1); file_fd_ud *ud = (file_fd_ud *) lua_newuserdata( L, sizeof( file_fd_ud ) );
ud->fd = file_fd;
luaL_getmetatable( L, "file.obj" );
lua_setmetatable( L, -2 );
// store reference to opened file
lua_pushvalue( L, -1 );
file_fd_ref = luaL_ref( L, LUA_REGISTRYINDEX );
} }
return 1; return 1;
} }
...@@ -170,19 +221,36 @@ static int file_list( lua_State* L ) ...@@ -170,19 +221,36 @@ static int file_list( lua_State* L )
return 0; return 0;
} }
static int file_seek (lua_State *L) static int get_file_obj( lua_State *L, int *argpos )
{
if (lua_type( L, 1 ) == LUA_TUSERDATA) {
file_fd_ud *ud = (file_fd_ud *)luaL_checkudata(L, 1, "file.obj");
*argpos = 2;
return ud->fd;
} else {
*argpos = 1;
return file_fd;
}
}
#define GET_FILE_OBJ int argpos; \
int fd = get_file_obj( L, &argpos );
static int file_seek (lua_State *L)
{ {
GET_FILE_OBJ;
static const int mode[] = {VFS_SEEK_SET, VFS_SEEK_CUR, VFS_SEEK_END}; static const int mode[] = {VFS_SEEK_SET, VFS_SEEK_CUR, VFS_SEEK_END};
static const char *const modenames[] = {"set", "cur", "end", NULL}; static const char *const modenames[] = {"set", "cur", "end", NULL};
if(!file_fd) if(!fd)
return luaL_error(L, "open a file first"); return luaL_error(L, "open a file first");
int op = luaL_checkoption(L, 1, "cur", modenames); int op = luaL_checkoption(L, argpos, "cur", modenames);
long offset = luaL_optlong(L, 2, 0); long offset = luaL_optlong(L, ++argpos, 0);
op = vfs_lseek(file_fd, offset, mode[op]); op = vfs_lseek(fd, offset, mode[op]);
if (op < 0) if (op < 0)
lua_pushnil(L); /* error */ lua_pushnil(L); /* error */
else else
lua_pushinteger(L, vfs_tell(file_fd)); lua_pushinteger(L, vfs_tell(fd));
return 1; return 1;
} }
...@@ -210,7 +278,6 @@ static int file_remove( lua_State* L ) ...@@ -210,7 +278,6 @@ static int file_remove( lua_State* L )
const char *fname = luaL_checklstring( L, 1, &len ); const char *fname = luaL_checklstring( L, 1, &len );
const char *basename = vfs_basename( fname ); const char *basename = vfs_basename( fname );
luaL_argcheck(L, c_strlen(basename) <= FS_OBJ_NAME_LEN && c_strlen(fname) == len, 1, "filename invalid"); luaL_argcheck(L, c_strlen(basename) <= FS_OBJ_NAME_LEN && c_strlen(fname) == len, 1, "filename invalid");
file_close(L);
vfs_remove((char *)fname); vfs_remove((char *)fname);
return 0; return 0;
} }
...@@ -218,9 +285,11 @@ static int file_remove( lua_State* L ) ...@@ -218,9 +285,11 @@ static int file_remove( lua_State* L )
// Lua: flush() // Lua: flush()
static int file_flush( lua_State* L ) static int file_flush( lua_State* L )
{ {
if(!file_fd) GET_FILE_OBJ;
if(!fd)
return luaL_error(L, "open a file first"); return luaL_error(L, "open a file first");
if(vfs_flush(file_fd) == 0) if(vfs_flush(fd) == 0)
lua_pushboolean(L, 1); lua_pushboolean(L, 1);
else else
lua_pushnil(L); lua_pushnil(L);
...@@ -231,10 +300,6 @@ static int file_flush( lua_State* L ) ...@@ -231,10 +300,6 @@ static int file_flush( lua_State* L )
static int file_rename( lua_State* L ) static int file_rename( lua_State* L )
{ {
size_t len; size_t len;
if(file_fd){
vfs_close(file_fd);
file_fd = 0;
}
const char *oldname = luaL_checklstring( L, 1, &len ); const char *oldname = luaL_checklstring( L, 1, &len );
const char *basename = vfs_basename( oldname ); const char *basename = vfs_basename( oldname );
...@@ -253,38 +318,64 @@ static int file_rename( lua_State* L ) ...@@ -253,38 +318,64 @@ static int file_rename( lua_State* L )
} }
// g_read() // g_read()
static int file_g_read( lua_State* L, int n, int16_t end_char ) static int file_g_read( lua_State* L, int n, int16_t end_char, int fd )
{ {
if(n <= 0 || n > LUAL_BUFFERSIZE) static char *heap_mem = NULL;
n = LUAL_BUFFERSIZE; // free leftover memory
if (heap_mem) {
luaM_free(L, heap_mem);
heap_mem = NULL;
}
if(n <= 0)
n = FILE_READ_CHUNK;
if(end_char < 0 || end_char >255) if(end_char < 0 || end_char >255)
end_char = EOF; end_char = EOF;
luaL_Buffer b;
if(!file_fd) if(!fd)
return luaL_error(L, "open a file first"); return luaL_error(L, "open a file first");
luaL_buffinit(L, &b); char *p;
char *p = luaL_prepbuffer(&b);
int i; int i;
n = vfs_read(file_fd, p, n); if (n > LUAL_BUFFERSIZE) {
for (i = 0; i < n; ++i) // get buffer from heap
if (p[i] == end_char) p = heap_mem = luaM_malloc(L, n);
{ } else {
++i; // small chunks go onto the stack
break; p = alloca(n);
} }
if(i==0){ n = vfs_read(fd, p, n);
luaL_pushresult(&b); /* close buffer */ // bypass search if no end character provided
return (lua_objlen(L, -1) > 0); /* check whether read something */ if (n > 0 && end_char != EOF) {
for (i = 0; i < n; ++i)
if (p[i] == end_char)
{
++i;
break;
}
} else {
i = n;
} }
vfs_lseek(file_fd, -(n - i), VFS_SEEK_CUR); if (i == 0 || n == VFS_RES_ERR) {
luaL_addsize(&b, i); if (heap_mem) {
luaL_pushresult(&b); /* close buffer */ luaM_free(L, heap_mem);
return 1; /* read at least an `eol' */ heap_mem = NULL;
}
return 0;
}
vfs_lseek(fd, -(n - i), VFS_SEEK_CUR);
lua_pushlstring(L, p, i);
if (heap_mem) {
luaM_free(L, heap_mem);
heap_mem = NULL;
}
return 1;
} }
// Lua: read() // Lua: read()
...@@ -293,42 +384,46 @@ static int file_g_read( lua_State* L, int n, int16_t end_char ) ...@@ -293,42 +384,46 @@ static int file_g_read( lua_State* L, int n, int16_t end_char )
// file.read('q') will read until 'q' or EOF is reached. // file.read('q') will read until 'q' or EOF is reached.
static int file_read( lua_State* L ) static int file_read( lua_State* L )
{ {
unsigned need_len = LUAL_BUFFERSIZE; unsigned need_len = FILE_READ_CHUNK;
int16_t end_char = EOF; int16_t end_char = EOF;
size_t el; size_t el;
if( lua_type( L, 1 ) == LUA_TNUMBER )
GET_FILE_OBJ;
if( lua_type( L, argpos ) == LUA_TNUMBER )
{ {
need_len = ( unsigned )luaL_checkinteger( L, 1 ); need_len = ( unsigned )luaL_checkinteger( L, argpos );
if( need_len > LUAL_BUFFERSIZE ){
need_len = LUAL_BUFFERSIZE;
}
} }
else if(lua_isstring(L, 1)) else if(lua_isstring(L, argpos))
{ {
const char *end = luaL_checklstring( L, 1, &el ); const char *end = luaL_checklstring( L, argpos, &el );
if(el!=1){ if(el!=1){
return luaL_error( L, "wrong arg range" ); return luaL_error( L, "wrong arg range" );
} }
end_char = (int16_t)end[0]; end_char = (int16_t)end[0];
} }
return file_g_read(L, need_len, end_char); return file_g_read(L, need_len, end_char, fd);
} }
// Lua: readline() // Lua: readline()
static int file_readline( lua_State* L ) static int file_readline( lua_State* L )
{ {
return file_g_read(L, LUAL_BUFFERSIZE, '\n'); GET_FILE_OBJ;
return file_g_read(L, LUAL_BUFFERSIZE, '\n', fd);
} }
// Lua: write("string") // Lua: write("string")
static int file_write( lua_State* L ) static int file_write( lua_State* L )
{ {
if(!file_fd) GET_FILE_OBJ;
if(!fd)
return luaL_error(L, "open a file first"); return luaL_error(L, "open a file first");
size_t l, rl; size_t l, rl;
const char *s = luaL_checklstring(L, 1, &l); const char *s = luaL_checklstring(L, argpos, &l);
rl = vfs_write(file_fd, s, l); rl = vfs_write(fd, s, l);
if(rl==l) if(rl==l)
lua_pushboolean(L, 1); lua_pushboolean(L, 1);
else else
...@@ -339,13 +434,15 @@ static int file_write( lua_State* L ) ...@@ -339,13 +434,15 @@ static int file_write( lua_State* L )
// Lua: writeline("string") // Lua: writeline("string")
static int file_writeline( lua_State* L ) static int file_writeline( lua_State* L )
{ {
if(!file_fd) GET_FILE_OBJ;
if(!fd)
return luaL_error(L, "open a file first"); return luaL_error(L, "open a file first");
size_t l, rl; size_t l, rl;
const char *s = luaL_checklstring(L, 1, &l); const char *s = luaL_checklstring(L, argpos, &l);
rl = vfs_write(file_fd, s, l); rl = vfs_write(fd, s, l);
if(rl==l){ if(rl==l){
rl = vfs_write(file_fd, "\n", 1); rl = vfs_write(fd, "\n", 1);
if(rl==1) if(rl==1)
lua_pushboolean(L, 1); lua_pushboolean(L, 1);
else else
...@@ -420,6 +517,20 @@ static int file_vol_umount( lua_State *L ) ...@@ -420,6 +517,20 @@ static int file_vol_umount( lua_State *L )
} }
static const LUA_REG_TYPE file_obj_map[] =
{
{ LSTRKEY( "close" ), LFUNCVAL( file_close ) },
{ LSTRKEY( "read" ), LFUNCVAL( file_read ) },
{ LSTRKEY( "readline" ), LFUNCVAL( file_readline ) },
{ LSTRKEY( "write" ), LFUNCVAL( file_write ) },
{ LSTRKEY( "writeline" ), LFUNCVAL( file_writeline ) },
{ LSTRKEY( "seek" ), LFUNCVAL( file_seek ) },
{ LSTRKEY( "flush" ), LFUNCVAL( file_flush ) },
{ LSTRKEY( "__gc" ), LFUNCVAL( file_obj_free ) },
{ LSTRKEY( "__index" ), LROVAL( file_obj_map ) },
{ LNILKEY, LNILVAL }
};
static const LUA_REG_TYPE file_vol_map[] = static const LUA_REG_TYPE file_vol_map[] =
{ {
{ LSTRKEY( "umount" ), LFUNCVAL( file_vol_umount )}, { LSTRKEY( "umount" ), LFUNCVAL( file_vol_umount )},
...@@ -459,6 +570,7 @@ static const LUA_REG_TYPE file_map[] = { ...@@ -459,6 +570,7 @@ static const LUA_REG_TYPE file_map[] = {
int luaopen_file( lua_State *L ) { int luaopen_file( lua_State *L ) {
luaL_rometatable( L, "file.vol", (void *)file_vol_map ); luaL_rometatable( L, "file.vol", (void *)file_vol_map );
luaL_rometatable( L, "file.obj", (void *)file_obj_map );
return 0; return 0;
} }
......
...@@ -190,19 +190,20 @@ static void seroutasync_done (task_param_t arg) ...@@ -190,19 +190,20 @@ static void seroutasync_done (task_param_t arg)
{ {
lua_State *L = lua_getstate(); lua_State *L = lua_getstate();
luaM_freearray(L, serout.delay_table, serout.tablelen, uint32); luaM_freearray(L, serout.delay_table, serout.tablelen, uint32);
if (serout.lua_done_ref != LUA_REFNIL) { // we're here so serout.lua_done_ref != LUA_NOREF serout.delay_table = NULL;
if (serout.lua_done_ref != LUA_NOREF) {
lua_rawgeti (L, LUA_REGISTRYINDEX, serout.lua_done_ref); lua_rawgeti (L, LUA_REGISTRYINDEX, serout.lua_done_ref);
luaL_unref (L, LUA_REGISTRYINDEX, serout.lua_done_ref);
serout.lua_done_ref = LUA_NOREF;
if (lua_pcall(L, 0, 0, 0)) { if (lua_pcall(L, 0, 0, 0)) {
// Uncaught Error. Print instead of sudden reset // Uncaught Error. Print instead of sudden reset
luaL_error(L, "error: %s", lua_tostring(L, -1)); luaL_error(L, "error: %s", lua_tostring(L, -1));
} }
luaL_unref (L, LUA_REGISTRYINDEX, serout.lua_done_ref);
} }
} }
static void ICACHE_RAM_ATTR seroutasync_cb(os_param_t p) { static void ICACHE_RAM_ATTR seroutasync_cb(os_param_t p) {
(void) p; (void) p;
NODE_DBG("%d\t%d\t%d\t%d\t%d\t%d\t%d\n", serout.repeats, serout.index, serout.level, serout.pin, serout.tablelen, serout.delay_table[serout.index], system_get_time()); // timing is delayed for short timings when debug output is enabled
if (serout.index < serout.tablelen) { if (serout.index < serout.tablelen) {
GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[serout.pin]), serout.level); GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[serout.pin]), serout.level);
serout.level = serout.level==LOW ? HIGH : LOW; serout.level = serout.level==LOW ? HIGH : LOW;
...@@ -220,17 +221,25 @@ static int lgpio_serout( lua_State* L ) ...@@ -220,17 +221,25 @@ static int lgpio_serout( lua_State* L )
serout.pin = luaL_checkinteger( L, 1 ); serout.pin = luaL_checkinteger( L, 1 );
serout.level = luaL_checkinteger( L, 2 ); serout.level = luaL_checkinteger( L, 2 );
serout.repeats = luaL_optint( L, 4, 1 )-1; serout.repeats = luaL_optint( L, 4, 1 )-1;
luaL_unref (L, LUA_REGISTRYINDEX, serout.lua_done_ref);
uint8_t is_async = FALSE;
if (!lua_isnoneornil(L, 5)) { if (!lua_isnoneornil(L, 5)) {
if (lua_isnumber(L, 5)) { if (lua_isnumber(L, 5)) {
serout.lua_done_ref = LUA_REFNIL; serout.lua_done_ref = LUA_NOREF;
} else { } else {
lua_pushvalue(L, 5); lua_pushvalue(L, 5);
serout.lua_done_ref = luaL_ref(L, LUA_REGISTRYINDEX); serout.lua_done_ref = luaL_ref(L, LUA_REGISTRYINDEX);
} }
is_async = TRUE;
} else { } else {
serout.lua_done_ref = LUA_NOREF; serout.lua_done_ref = LUA_NOREF;
} }
if (serout.delay_table) {
luaM_freearray(L, serout.delay_table, serout.tablelen, uint32);
serout.delay_table = NULL;
}
luaL_argcheck(L, platform_gpio_exists(serout.pin), 1, "Invalid pin"); luaL_argcheck(L, platform_gpio_exists(serout.pin), 1, "Invalid pin");
luaL_argcheck(L, serout.level==HIGH || serout.level==LOW, 2, "Wrong level type" ); luaL_argcheck(L, serout.level==HIGH || serout.level==LOW, 2, "Wrong level type" );
luaL_argcheck(L, lua_istable( L, 3 ) && luaL_argcheck(L, lua_istable( L, 3 ) &&
...@@ -244,7 +253,7 @@ static int lgpio_serout( lua_State* L ) ...@@ -244,7 +253,7 @@ static int lgpio_serout( lua_State* L )
lua_pop( L, 1 ); lua_pop( L, 1 );
} }
if (serout.lua_done_ref != LUA_NOREF) { // async version for duration above 15 mSec if (is_async) { // async version for duration above 15 mSec
if (!platform_hw_timer_init(TIMER_OWNER, FRC1_SOURCE, TRUE)) { if (!platform_hw_timer_init(TIMER_OWNER, FRC1_SOURCE, TRUE)) {
// Failed to init the timer // Failed to init the timer
luaL_error(L, "Unable to initialize timer"); luaL_error(L, "Unable to initialize timer");
...@@ -296,6 +305,7 @@ int luaopen_gpio( lua_State *L ) { ...@@ -296,6 +305,7 @@ int luaopen_gpio( lua_State *L ) {
platform_gpio_init(task_get_id(gpio_intr_callback_task)); platform_gpio_init(task_get_id(gpio_intr_callback_task));
#endif #endif
serout.done_taskid = task_get_id((task_callback_t) seroutasync_done); serout.done_taskid = task_get_id((task_callback_t) seroutasync_done);
serout.lua_done_ref = LUA_NOREF;
return 0; return 0;
} }
......
...@@ -14,13 +14,13 @@ static int http_callback_registry = LUA_NOREF; ...@@ -14,13 +14,13 @@ static int http_callback_registry = LUA_NOREF;
static void http_callback( char * response, int http_status, char * full_response ) static void http_callback( char * response, int http_status, char * full_response )
{ {
#if defined(HTTPCLIENT_DEBUG_ON) #if defined(HTTPCLIENT_DEBUG_ON)
c_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 )
{ {
if (full_response != NULL) { if (full_response != NULL) {
c_printf( "strlen(full_response)=%d\n", strlen( full_response ) ); dbg_printf( "strlen(full_response)=%d\n", strlen( full_response ) );
} }
c_printf( "response=%s<EOF>\n", response ); dbg_printf( "response=%s<EOF>\n", response );
} }
#endif #endif
if (http_callback_registry != LUA_NOREF) if (http_callback_registry != LUA_NOREF)
......
...@@ -72,6 +72,7 @@ typedef struct lmqtt_userdata ...@@ -72,6 +72,7 @@ typedef struct lmqtt_userdata
uint8_t secure; uint8_t secure;
#endif #endif
bool connected; // indicate socket connected, not mqtt prot connected. bool connected; // indicate socket connected, not mqtt prot connected.
bool keepalive_sent;
ETSTimer mqttTimer; ETSTimer mqttTimer;
tConnState connState; tConnState connState;
}lmqtt_userdata; }lmqtt_userdata;
...@@ -212,9 +213,9 @@ static void mqtt_connack_fail(lmqtt_userdata * mud, int reason_code) ...@@ -212,9 +213,9 @@ static void mqtt_connack_fail(lmqtt_userdata * mud, int reason_code)
{ {
return; return;
} }
lua_State *L = lua_getstate(); lua_State *L = lua_getstate();
lua_rawgeti(L, LUA_REGISTRYINDEX, mud->cb_connect_fail_ref); lua_rawgeti(L, LUA_REGISTRYINDEX, mud->cb_connect_fail_ref);
lua_rawgeti(L, LUA_REGISTRYINDEX, mud->self_ref); // pass the userdata(client) to callback func in lua lua_rawgeti(L, LUA_REGISTRYINDEX, mud->self_ref); // pass the userdata(client) to callback func in lua
lua_pushinteger(L, reason_code); lua_pushinteger(L, reason_code);
...@@ -241,12 +242,12 @@ static sint8 mqtt_send_if_possible(struct espconn *pesp_conn) ...@@ -241,12 +242,12 @@ static sint8 mqtt_send_if_possible(struct espconn *pesp_conn)
#ifdef CLIENT_SSL_ENABLE #ifdef CLIENT_SSL_ENABLE
if( mud->secure ) if( mud->secure )
{ {
espconn_status = espconn_secure_send( pesp_conn, pending_msg->msg.data, pending_msg->msg.length ); espconn_status = espconn_secure_send( pesp_conn, pending_msg->msg.data, pending_msg->msg.length );
} }
else else
#endif #endif
{ {
espconn_status = espconn_send( pesp_conn, pending_msg->msg.data, pending_msg->msg.length ); espconn_status = espconn_send( pesp_conn, pending_msg->msg.data, pending_msg->msg.length );
} }
mud->keep_alive_tick = 0; mud->keep_alive_tick = 0;
} }
...@@ -275,7 +276,7 @@ static void mqtt_socket_received(void *arg, char *pdata, unsigned short len) ...@@ -275,7 +276,7 @@ static void mqtt_socket_received(void *arg, char *pdata, unsigned short len)
READPACKET: READPACKET:
if(length > MQTT_BUF_SIZE || length <= 0) if(length > MQTT_BUF_SIZE || length <= 0)
return; return;
// c_memcpy(in_buffer, pdata, length); // c_memcpy(in_buffer, pdata, length);
uint8_t temp_buffer[MQTT_BUF_SIZE]; uint8_t temp_buffer[MQTT_BUF_SIZE];
...@@ -287,7 +288,7 @@ READPACKET: ...@@ -287,7 +288,7 @@ READPACKET:
case MQTT_CONNECT_SENDING: case MQTT_CONNECT_SENDING:
case MQTT_CONNECT_SENT: case MQTT_CONNECT_SENT:
mud->event_timeout = 0; mud->event_timeout = 0;
if(mqtt_get_type(in_buffer) != MQTT_MSG_TYPE_CONNACK){ if(mqtt_get_type(in_buffer) != MQTT_MSG_TYPE_CONNACK){
NODE_DBG("MQTT: Invalid packet\r\n"); NODE_DBG("MQTT: Invalid packet\r\n");
mud->connState = MQTT_INIT; mud->connState = MQTT_INIT;
...@@ -301,16 +302,16 @@ READPACKET: ...@@ -301,16 +302,16 @@ READPACKET:
{ {
espconn_disconnect(pesp_conn); espconn_disconnect(pesp_conn);
} }
mqtt_connack_fail(mud, MQTT_CONN_FAIL_NOT_A_CONNACK_MSG); mqtt_connack_fail(mud, MQTT_CONN_FAIL_NOT_A_CONNACK_MSG);
break; break;
} else if (mqtt_get_connect_ret_code(in_buffer) != MQTT_CONNACK_ACCEPTED) { } else if (mqtt_get_connect_ret_code(in_buffer) != MQTT_CONNACK_ACCEPTED) {
NODE_DBG("MQTT: CONNACK REFUSED (CODE: %d)\n", mqtt_get_connect_ret_code(in_buffer)); NODE_DBG("MQTT: CONNACK REFUSED (CODE: %d)\n", mqtt_get_connect_ret_code(in_buffer));
mud->connState = MQTT_INIT; mud->connState = MQTT_INIT;
#ifdef CLIENT_SSL_ENABLE #ifdef CLIENT_SSL_ENABLE
if(mud->secure) if(mud->secure)
{ {
...@@ -320,12 +321,12 @@ READPACKET: ...@@ -320,12 +321,12 @@ READPACKET:
#endif #endif
{ {
espconn_disconnect(pesp_conn); espconn_disconnect(pesp_conn);
} }
mqtt_connack_fail(mud, mqtt_get_connect_ret_code(in_buffer)); mqtt_connack_fail(mud, mqtt_get_connect_ret_code(in_buffer));
break; break;
} else { } else {
mud->connState = MQTT_DATA; mud->connState = MQTT_DATA;
NODE_DBG("MQTT: Connected\r\n"); NODE_DBG("MQTT: Connected\r\n");
...@@ -454,6 +455,7 @@ READPACKET: ...@@ -454,6 +455,7 @@ READPACKET:
break; break;
case MQTT_MSG_TYPE_PINGRESP: case MQTT_MSG_TYPE_PINGRESP:
// Ignore // Ignore
mud->keepalive_sent = 0;
NODE_DBG("MQTT: PINGRESP received\r\n"); NODE_DBG("MQTT: PINGRESP received\r\n");
break; break;
} }
...@@ -585,7 +587,7 @@ void mqtt_socket_timer(void *arg) ...@@ -585,7 +587,7 @@ void mqtt_socket_timer(void *arg)
NODE_DBG("timer, queue size: %d\n", msg_size(&(mud->mqtt_state.pending_msg_q))); NODE_DBG("timer, queue size: %d\n", msg_size(&(mud->mqtt_state.pending_msg_q)));
if(mud->event_timeout > 0){ if(mud->event_timeout > 0){
NODE_DBG("event_timeout: %d.\n", mud->event_timeout); NODE_DBG("event_timeout: %d.\n", mud->event_timeout);
mud->event_timeout --; mud->event_timeout --;
if(mud->event_timeout > 0){ if(mud->event_timeout > 0){
return; return;
} else { } else {
...@@ -605,7 +607,7 @@ void mqtt_socket_timer(void *arg) ...@@ -605,7 +607,7 @@ void mqtt_socket_timer(void *arg)
NODE_DBG("sSend MQTT_CONNECT failed.\n"); NODE_DBG("sSend MQTT_CONNECT failed.\n");
mud->connState = MQTT_INIT; mud->connState = MQTT_INIT;
mqtt_connack_fail(mud, MQTT_CONN_FAIL_TIMEOUT_SENDING); mqtt_connack_fail(mud, MQTT_CONN_FAIL_TIMEOUT_SENDING);
#ifdef CLIENT_SSL_ENABLE #ifdef CLIENT_SSL_ENABLE
if(mud->secure) if(mud->secure)
{ {
...@@ -620,7 +622,7 @@ void mqtt_socket_timer(void *arg) ...@@ -620,7 +622,7 @@ void mqtt_socket_timer(void *arg)
} else if(mud->connState == MQTT_CONNECT_SENT) { // wait for CONACK time out. } else if(mud->connState == MQTT_CONNECT_SENT) { // wait for CONACK time out.
NODE_DBG("MQTT_CONNECT timeout.\n"); NODE_DBG("MQTT_CONNECT timeout.\n");
mud->connState = MQTT_INIT; mud->connState = MQTT_INIT;
#ifdef CLIENT_SSL_ENABLE #ifdef CLIENT_SSL_ENABLE
if(mud->secure) if(mud->secure)
{ {
...@@ -630,7 +632,7 @@ void mqtt_socket_timer(void *arg) ...@@ -630,7 +632,7 @@ void mqtt_socket_timer(void *arg)
#endif #endif
{ {
espconn_disconnect(mud->pesp_conn); espconn_disconnect(mud->pesp_conn);
} }
mqtt_connack_fail(mud, MQTT_CONN_FAIL_TIMEOUT_RECEIVING); mqtt_connack_fail(mud, MQTT_CONN_FAIL_TIMEOUT_RECEIVING);
} else if(mud->connState == MQTT_DATA){ } else if(mud->connState == MQTT_DATA){
msg_queue_t *pending_msg = msg_peek(&(mud->mqtt_state.pending_msg_q)); msg_queue_t *pending_msg = msg_peek(&(mud->mqtt_state.pending_msg_q));
...@@ -640,13 +642,20 @@ void mqtt_socket_timer(void *arg) ...@@ -640,13 +642,20 @@ void mqtt_socket_timer(void *arg)
// no queued event. // no queued event.
mud->keep_alive_tick ++; mud->keep_alive_tick ++;
if(mud->keep_alive_tick > mud->mqtt_state.connect_info->keepalive){ if(mud->keep_alive_tick > mud->mqtt_state.connect_info->keepalive){
uint8_t temp_buffer[MQTT_BUF_SIZE]; if (mud->keepalive_sent) {
mqtt_msg_init(&mud->mqtt_state.mqtt_connection, temp_buffer, MQTT_BUF_SIZE); // Oh dear -- keepalive timer expired and still no ack of previous message
NODE_DBG("\r\nMQTT: Send keepalive packet\r\n"); mqtt_socket_reconnected(mud->pesp_conn, 0);
mqtt_message_t* temp_msg = mqtt_msg_pingreq(&mud->mqtt_state.mqtt_connection); } else {
msg_queue_t *node = msg_enqueue( &(mud->mqtt_state.pending_msg_q), temp_msg, uint8_t temp_buffer[MQTT_BUF_SIZE];
0, MQTT_MSG_TYPE_PINGREQ, (int)mqtt_get_qos(temp_msg->data) ); mqtt_msg_init(&mud->mqtt_state.mqtt_connection, temp_buffer, MQTT_BUF_SIZE);
mqtt_send_if_possible(mud->pesp_conn); NODE_DBG("\r\nMQTT: Send keepalive packet\r\n");
mqtt_message_t* temp_msg = mqtt_msg_pingreq(&mud->mqtt_state.mqtt_connection);
msg_queue_t *node = msg_enqueue( &(mud->mqtt_state.pending_msg_q), temp_msg,
0, MQTT_MSG_TYPE_PINGREQ, (int)mqtt_get_qos(temp_msg->data) );
mud->keepalive_sent = 1;
mud->keep_alive_tick = 0; // Need to reset to zero in case flow control stopped.
mqtt_send_if_possible(mud->pesp_conn);
}
} }
} }
} }
...@@ -675,6 +684,7 @@ static int mqtt_socket_client( lua_State* L ) ...@@ -675,6 +684,7 @@ static int mqtt_socket_client( lua_State* L )
// create a object // create a object
mud = (lmqtt_userdata *)lua_newuserdata(L, sizeof(lmqtt_userdata)); mud = (lmqtt_userdata *)lua_newuserdata(L, sizeof(lmqtt_userdata));
c_memset(mud, 0, sizeof(*mud));
// pre-initialize it, in case of errors // pre-initialize it, in case of errors
mud->self_ref = LUA_NOREF; mud->self_ref = LUA_NOREF;
mud->cb_connect_ref = LUA_NOREF; mud->cb_connect_ref = LUA_NOREF;
...@@ -685,18 +695,8 @@ static int mqtt_socket_client( lua_State* L ) ...@@ -685,18 +695,8 @@ static int mqtt_socket_client( lua_State* L )
mud->cb_suback_ref = LUA_NOREF; mud->cb_suback_ref = LUA_NOREF;
mud->cb_unsuback_ref = LUA_NOREF; mud->cb_unsuback_ref = LUA_NOREF;
mud->cb_puback_ref = LUA_NOREF; mud->cb_puback_ref = LUA_NOREF;
mud->pesp_conn = NULL;
#ifdef CLIENT_SSL_ENABLE
mud->secure = 0;
#endif
mud->keep_alive_tick = 0;
mud->event_timeout = 0;
mud->connState = MQTT_INIT; mud->connState = MQTT_INIT;
mud->connected = false;
c_memset(&mud->mqttTimer, 0, sizeof(ETSTimer));
c_memset(&mud->mqtt_state, 0, sizeof(mqtt_state_t));
c_memset(&mud->connect_info, 0, sizeof(mqtt_connect_info_t));
// set its metatable // set its metatable
luaL_getmetatable(L, "mqtt.socket"); luaL_getmetatable(L, "mqtt.socket");
...@@ -761,7 +761,7 @@ static int mqtt_socket_client( lua_State* L ) ...@@ -761,7 +761,7 @@ static int mqtt_socket_client( lua_State* L )
c_free(mud->connect_info.password); c_free(mud->connect_info.password);
mud->connect_info.password = NULL; mud->connect_info.password = NULL;
} }
return luaL_error(L, "not enough memory"); return luaL_error(L, "not enough memory");
} }
c_memcpy(mud->connect_info.client_id, clientId, idl); c_memcpy(mud->connect_info.client_id, clientId, idl);
...@@ -819,8 +819,8 @@ static int mqtt_delete( lua_State* L ) ...@@ -819,8 +819,8 @@ static int mqtt_delete( lua_State* L )
// ---- alloc-ed in mqtt_socket_lwt() // ---- alloc-ed in mqtt_socket_lwt()
if(mud->connect_info.will_topic){ if(mud->connect_info.will_topic){
c_free(mud->connect_info.will_topic); c_free(mud->connect_info.will_topic);
mud->connect_info.will_topic = NULL; mud->connect_info.will_topic = NULL;
} }
if(mud->connect_info.will_message){ if(mud->connect_info.will_message){
...@@ -926,7 +926,7 @@ static sint8 socket_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) ...@@ -926,7 +926,7 @@ static sint8 socket_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
if( dns_reconn_count >= 5 ){ if( dns_reconn_count >= 5 ){
NODE_ERR( "DNS Fail!\n" ); NODE_ERR( "DNS Fail!\n" );
// Note: should delete the pesp_conn or unref self_ref here. // Note: should delete the pesp_conn or unref self_ref here.
struct espconn *pesp_conn = arg; struct espconn *pesp_conn = arg;
if(pesp_conn != NULL) { if(pesp_conn != NULL) {
lmqtt_userdata *mud = (lmqtt_userdata *)pesp_conn->reverse; lmqtt_userdata *mud = (lmqtt_userdata *)pesp_conn->reverse;
...@@ -934,7 +934,7 @@ static sint8 socket_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) ...@@ -934,7 +934,7 @@ static sint8 socket_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
mqtt_connack_fail(mud, MQTT_CONN_FAIL_DNS); mqtt_connack_fail(mud, MQTT_CONN_FAIL_DNS);
} }
} }
mqtt_socket_disconnected(arg); // although not connected, but fire disconnect callback to release every thing. mqtt_socket_disconnected(arg); // although not connected, but fire disconnect callback to release every thing.
return -1; return -1;
} }
...@@ -1070,7 +1070,7 @@ static int mqtt_socket_connect( lua_State* L ) ...@@ -1070,7 +1070,7 @@ static int mqtt_socket_connect( lua_State* L )
} }
stack++; stack++;
// call back function when a connection fails // call back function when a connection fails
if ((stack<=top) && (lua_type(L, stack) == LUA_TFUNCTION || lua_type(L, stack) == LUA_TLIGHTFUNCTION)){ if ((stack<=top) && (lua_type(L, stack) == LUA_TFUNCTION || lua_type(L, stack) == LUA_TLIGHTFUNCTION)){
lua_pushvalue(L, stack); // copy argument (func) to the top of stack lua_pushvalue(L, stack); // copy argument (func) to the top of stack
...@@ -1135,7 +1135,7 @@ static int mqtt_socket_close( lua_State* L ) ...@@ -1135,7 +1135,7 @@ static int mqtt_socket_close( lua_State* L )
// Send disconnect message // Send disconnect message
mqtt_message_t* temp_msg = mqtt_msg_disconnect(&mud->mqtt_state.mqtt_connection); mqtt_message_t* temp_msg = mqtt_msg_disconnect(&mud->mqtt_state.mqtt_connection);
NODE_DBG("Send MQTT disconnect infomation, data len: %d, d[0]=%d \r\n", temp_msg->length, temp_msg->data[0]); NODE_DBG("Send MQTT disconnect infomation, data len: %d, d[0]=%d \r\n", temp_msg->length, temp_msg->data[0]);
#ifdef CLIENT_SSL_ENABLE #ifdef CLIENT_SSL_ENABLE
if(mud->secure) { if(mud->secure) {
espconn_status = espconn_secure_send(mud->pesp_conn, temp_msg->data, temp_msg->length); espconn_status = espconn_secure_send(mud->pesp_conn, temp_msg->data, temp_msg->length);
...@@ -1150,7 +1150,7 @@ static int mqtt_socket_close( lua_State* L ) ...@@ -1150,7 +1150,7 @@ static int mqtt_socket_close( lua_State* L )
} }
} }
mud->connected = 0; mud->connected = 0;
while (mud->mqtt_state.pending_msg_q) { while (mud->mqtt_state.pending_msg_q) {
msg_destroy(msg_dequeue(&(mud->mqtt_state.pending_msg_q))); msg_destroy(msg_dequeue(&(mud->mqtt_state.pending_msg_q)));
} }
...@@ -1595,7 +1595,7 @@ static const LUA_REG_TYPE mqtt_socket_map[] = { ...@@ -1595,7 +1595,7 @@ static const LUA_REG_TYPE mqtt_socket_map[] = {
{ LNILKEY, LNILVAL } { LNILKEY, LNILVAL }
}; };
static const LUA_REG_TYPE mqtt_map[] = { static const LUA_REG_TYPE mqtt_map[] = {
{ LSTRKEY( "Client" ), LFUNCVAL( mqtt_socket_client ) }, { LSTRKEY( "Client" ), LFUNCVAL( mqtt_socket_client ) },
...@@ -1609,7 +1609,7 @@ static const LUA_REG_TYPE mqtt_map[] = { ...@@ -1609,7 +1609,7 @@ static const LUA_REG_TYPE mqtt_map[] = {
{ LSTRKEY( "CONNACK_REFUSED_ID_REJECTED" ), LNUMVAL( MQTT_CONNACK_REFUSED_ID_REJECTED ) }, { LSTRKEY( "CONNACK_REFUSED_ID_REJECTED" ), LNUMVAL( MQTT_CONNACK_REFUSED_ID_REJECTED ) },
{ LSTRKEY( "CONNACK_REFUSED_SERVER_UNAVAILABLE" ), LNUMVAL( MQTT_CONNACK_REFUSED_SERVER_UNAVAILABLE ) }, { LSTRKEY( "CONNACK_REFUSED_SERVER_UNAVAILABLE" ), LNUMVAL( MQTT_CONNACK_REFUSED_SERVER_UNAVAILABLE ) },
{ LSTRKEY( "CONNACK_REFUSED_BAD_USER_OR_PASS" ), LNUMVAL( MQTT_CONNACK_REFUSED_BAD_USER_OR_PASS ) }, { LSTRKEY( "CONNACK_REFUSED_BAD_USER_OR_PASS" ), LNUMVAL( MQTT_CONNACK_REFUSED_BAD_USER_OR_PASS ) },
{ LSTRKEY( "CONNACK_REFUSED_NOT_AUTHORIZED" ), LNUMVAL( MQTT_CONNACK_REFUSED_NOT_AUTHORIZED ) }, { LSTRKEY( "CONNACK_REFUSED_NOT_AUTHORIZED" ), LNUMVAL( MQTT_CONNACK_REFUSED_NOT_AUTHORIZED ) },
{ LSTRKEY( "__metatable" ), LROVAL( mqtt_map ) }, { LSTRKEY( "__metatable" ), LROVAL( mqtt_map ) },
{ LNILKEY, LNILVAL } { LNILKEY, LNILVAL }
......
...@@ -134,6 +134,8 @@ static int ow_read_bytes( lua_State *L ) ...@@ -134,6 +134,8 @@ static int ow_read_bytes( lua_State *L )
if( size == 0 ) if( size == 0 )
return 0; return 0;
luaL_argcheck(L, size <= LUAL_BUFFERSIZE, 2, "Attempt to read too many characters");
luaL_Buffer b; luaL_Buffer b;
luaL_buffinit( L, &b ); luaL_buffinit( L, &b );
char *p = luaL_prepbuffer(&b); char *p = luaL_prepbuffer(&b);
......
...@@ -53,7 +53,7 @@ ...@@ -53,7 +53,7 @@
#define MAX_ATTEMPTS 5 #define MAX_ATTEMPTS 5
#if 0 #if 0
# define sntp_dbg(...) c_printf(__VA_ARGS__) # define sntp_dbg(...) dbg_printf(__VA_ARGS__)
#else #else
# define sntp_dbg(...) # define sntp_dbg(...)
#endif #endif
......
// ***************************************************************************
// Somfy module for ESP8266 with NodeMCU
//
// Written by Lukas Voborsky, @voborsky
// based on https://github.com/Nickduino/Somfy_Remote
// Somfy protocol description: https://pushstack.wordpress.com/somfy-rts-protocol/
// and discussion: https://forum.arduino.cc/index.php?topic=208346.0
//
// MIT license, http://opensource.org/licenses/MIT
// ***************************************************************************
//#define NODE_DEBUG
#include "os_type.h"
#include "osapi.h"
#include "sections.h"
#include "module.h"
#include "lauxlib.h"
#include "lmem.h"
#include "platform.h"
#include "hw_timer.h"
#include "user_interface.h"
#define SYMBOL 640 // symbol width in microseconds
#define SOMFY_UP 0x2
#define SOMFY_STOP 0x1
#define SOMFY_DOWN 0x4
#define SOMFY_PROG 0x8
#define DIRECT_WRITE_LOW(pin) (GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[pin]), 0))
#define DIRECT_WRITE_HIGH(pin) (GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[pin]), 1))
static const os_param_t TIMER_OWNER = 0x736f6d66; // "somf"
static task_handle_t done_taskid;
static uint8_t pin;
static uint8_t frame[7];
static uint8_t sync;
static uint8_t repeat;
//static uint32_t delay[10] = {9415, 89565, 4*SYMBOL, 4*SYMBOL, 4*SYMBOL, 4550, SYMBOL, SYMBOL, SYMBOL, 30415}; // in us
// the `delay` array of constants must be in RAM as it is accessed from the timer interrupt
static const RAM_CONST_SECTION_ATTR uint32_t delay[10] = {US_TO_RTC_TIMER_TICKS(9415), US_TO_RTC_TIMER_TICKS(89565), US_TO_RTC_TIMER_TICKS(4*SYMBOL), US_TO_RTC_TIMER_TICKS(4*SYMBOL), US_TO_RTC_TIMER_TICKS(4*SYMBOL), US_TO_RTC_TIMER_TICKS(4550), US_TO_RTC_TIMER_TICKS(SYMBOL), US_TO_RTC_TIMER_TICKS(SYMBOL), US_TO_RTC_TIMER_TICKS(SYMBOL), US_TO_RTC_TIMER_TICKS(30415)}; // in ticks (no need to recalculate)
static uint8_t repeatindex;
static uint8_t signalindex;
static uint8_t subindex;
static uint8_t bitcondition;
int lua_done_ref; // callback when transmission is done
void buildFrame(uint8_t *frame, uint64_t remote, uint8_t button, uint16_t code) {
// NODE_DBG("remote: %x\n", remote);
// NODE_DBG("button: %x\n", button);
// NODE_DBG("rolling code: %x\n", code);
frame[0] = 0xA7; // Encryption key. Doesn't matter much
frame[1] = button << 4; // Which button did you press? The 4 LSB will be the checksum
frame[2] = code >> 8; // Rolling code (big endian)
frame[3] = code; // Rolling code
frame[4] = remote >> 16; // Remote address
frame[5] = remote >> 8; // Remote address
frame[6] = remote; // Remote address
// frame[7] = 0x80;
// frame[8] = 0x0;
// frame[9] = 0x0;
// NODE_DBG("Frame:\t\t\t%02x %02x %02x %02x %02x %02x %02x\n", frame[0], frame[1], frame[2], frame[3], frame[4], frame[5], frame[6]);
// Checksum calculation: a XOR of all the nibbles
uint8_t checksum = 0;
for(uint8_t i = 0; i < 7; i++) {
checksum = checksum ^ frame[i] ^ (frame[i] >> 4);
}
checksum &= 0b1111; // We keep the last 4 bits only
//Checksum integration
frame[1] |= checksum; // If a XOR of all the nibbles is equal to 0, the blinds will consider the checksum ok.
// NODE_DBG("With checksum:\t%02x %02x %02x %02x %02x %02x %02x\n", frame[0], frame[1], frame[2], frame[3], frame[4], frame[5], frame[6]);
// Obfuscation: a XOR of all the uint8_ts
for(uint8_t i = 1; i < 7; i++) {
frame[i] ^= frame[i-1];
}
// NODE_DBG("Obfuscated:\t\t%02x %02x %02x %02x %02x %02x %02x\n", frame[0], frame[1], frame[2], frame[3], frame[4], frame[5], frame[6]);
}
static void somfy_transmissionDone (task_param_t arg)
{
lua_State *L = lua_getstate();
lua_rawgeti (L, LUA_REGISTRYINDEX, lua_done_ref);
luaL_unref (L, LUA_REGISTRYINDEX, lua_done_ref);
lua_done_ref = LUA_NOREF;
lua_call (L, 0, 0);
}
static void ICACHE_RAM_ATTR sendCommand(os_param_t p) {
(void) p;
// NODE_DBG("%d\t%d\n", signalindex, subindex);
switch (signalindex) {
case 0:
subindex = 0;
if(sync == 2) { // Only with the first frame.
//Wake-up pulse & Silence
DIRECT_WRITE_HIGH(pin);
signalindex++;
// delayMicroseconds(9415);
break;
} else {
signalindex++; signalindex++; //no break means: go directly to step 3
}
case 1:
//Wake-up pulse & Silence
DIRECT_WRITE_LOW(pin);
signalindex++;
// delayMicroseconds(89565);
break;
case 2:
signalindex++;
// no break means go directly to step 3
// a "useless" step to allow repeating the hardware sync w/o the silence after wake-up pulse
case 3:
// Hardware sync: two sync for the first frame, seven for the following ones.
DIRECT_WRITE_HIGH(pin);
signalindex++;
// delayMicroseconds(4*SYMBOL);
break;
case 4:
DIRECT_WRITE_LOW(pin);
subindex++;
if (subindex < sync) {signalindex--;} else {signalindex++;}
// delayMicroseconds(4*SYMBOL);
break;
case 5:
// Software sync
DIRECT_WRITE_HIGH(pin);
signalindex++;
// delayMicroseconds(4550);
break;
case 6:
DIRECT_WRITE_LOW(pin);
signalindex++;
subindex=0;
// delayMicroseconds(SYMBOL);
break;
case 7:
//Data: bits are sent one by one, starting with the MSB.
bitcondition = ((frame[subindex/8] >> (7 - (subindex%8))) & 1) == 1;
if(bitcondition) {
DIRECT_WRITE_LOW(pin);
}
else {
DIRECT_WRITE_HIGH(pin);
}
signalindex++;
// delayMicroseconds(SYMBOL);
break;
case 8:
//Data: bits are sent one by one, starting with the MSB.
if(bitcondition) {
DIRECT_WRITE_HIGH(pin);
}
else {
DIRECT_WRITE_LOW(pin);
}
if (subindex<56) {
subindex++;
signalindex--;
}
else {
signalindex++;
}
// delayMicroseconds(SYMBOL);
break;
case 9:
DIRECT_WRITE_LOW(pin);
signalindex++;
// delayMicroseconds(30415); // Inter-frame silence
break;
case 10:
repeatindex++;
if (repeatindex<repeat) {
DIRECT_WRITE_HIGH(pin); //start repeat from step 3, but don't wait as after step 1
signalindex=4; subindex=0; sync=7;
} else {
platform_hw_timer_close(TIMER_OWNER);
if (lua_done_ref != LUA_NOREF) {
task_post_low (done_taskid, (task_param_t)0);
}
}
break;
}
if (signalindex<10) {
platform_hw_timer_arm_ticks(TIMER_OWNER, delay[signalindex-1]);
}
}
static int somfy_lua_sendcommand(lua_State* L) { // pin, remote, command, rolling_code, num_repeat, callback
if (!lua_isnumber(L, 4)) {
return luaL_error(L, "wrong arg range");
}
pin = luaL_checkinteger(L, 1);
uint64_t remote = luaL_checkinteger(L, 2);
uint8_t cmd = luaL_checkinteger(L, 3);
uint16_t code = luaL_checkinteger(L, 4);
repeat=luaL_optint( L, 5, 2 );
luaL_argcheck(L, platform_gpio_exists(pin), 1, "Invalid pin");
luaL_unref(L, LUA_REGISTRYINDEX, lua_done_ref);
if (!lua_isnoneornil(L, 6)) {
lua_pushvalue(L, 6);
lua_done_ref = luaL_ref(L, LUA_REGISTRYINDEX);
} else {
lua_done_ref = LUA_NOREF;
}
MOD_CHECK_ID(gpio, pin);
platform_gpio_mode(pin, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_PULLUP);
buildFrame(frame, remote, cmd, code);
if (!platform_hw_timer_init(TIMER_OWNER, FRC1_SOURCE, TRUE)) {
// Failed to init the timer
luaL_error(L, "Unable to initialize timer");
}
platform_hw_timer_set_func(TIMER_OWNER, sendCommand, 0);
sync=2;
signalindex=0; repeatindex=0;
sendCommand(0);
return 0;
}
static const LUA_REG_TYPE somfy_map[] = {
{ LSTRKEY( "UP" ), LNUMVAL( SOMFY_UP ) },
{ LSTRKEY( "DOWN" ), LNUMVAL( SOMFY_DOWN ) },
{ LSTRKEY( "PROG" ), LNUMVAL( SOMFY_PROG ) },
{ LSTRKEY( "STOP" ), LNUMVAL( SOMFY_STOP ) },
{ LSTRKEY( "sendcommand" ), LFUNCVAL(somfy_lua_sendcommand)},
{ LNILKEY, LNILVAL}
};
int luaopen_somfy( lua_State *L ) {
done_taskid = task_get_id((task_callback_t) somfy_transmissionDone);
return 0;
}
NODEMCU_MODULE(SOMFY, "somfy", somfy_map, luaopen_somfy);
\ No newline at end of file
...@@ -2,24 +2,13 @@ ...@@ -2,24 +2,13 @@
#include "module.h" #include "module.h"
#include "lauxlib.h" #include "lauxlib.h"
#include "platform.h" #include "lmem.h"
#include "c_stdlib.h"
#include "u8g.h" #include "u8g.h"
#include "u8g_glue.h"
#include "u8g_config.h" #include "u8g_config.h"
struct _lu8g_userdata_t
{
u8g_t u8g;
};
typedef struct _lu8g_userdata_t lu8g_userdata_t;
// shorthand macro for the u8g structure inside the userdata
#define LU8G (&(lud->u8g))
// helper function: retrieve and check userdata argument // helper function: retrieve and check userdata argument
static lu8g_userdata_t *get_lud( lua_State *L ) static lu8g_userdata_t *get_lud( lua_State *L )
...@@ -780,214 +769,6 @@ static int lu8g_setFontLineSpacingFactor( lua_State *L ) ...@@ -780,214 +769,6 @@ static int lu8g_setFontLineSpacingFactor( lua_State *L )
} }
// ------------------------------------------------------------
// comm functions
//
#define I2C_CMD_MODE 0x000
#define I2C_DATA_MODE 0x040
#define ESP_I2C_ID 0
static uint8_t do_i2c_start(uint8_t id, uint8_t sla)
{
platform_i2c_send_start( id );
// ignore return value -> tolerate missing ACK
platform_i2c_send_address( id, sla, PLATFORM_I2C_DIRECTION_TRANSMITTER );
return 1;
}
static uint8_t u8g_com_esp8266_ssd_start_sequence(u8g_t *u8g)
{
/* are we requested to set the a0 state? */
if ( u8g->pin_list[U8G_PI_SET_A0] == 0 )
return 1;
/* setup bus, might be a repeated start */
if ( do_i2c_start( ESP_I2C_ID, u8g->i2c_addr ) == 0 )
return 0;
if ( u8g->pin_list[U8G_PI_A0_STATE] == 0 )
{
// ignore return value -> tolerate missing ACK
if ( platform_i2c_send_byte( ESP_I2C_ID, I2C_CMD_MODE ) == 0 )
; //return 0;
}
else
{
platform_i2c_send_byte( ESP_I2C_ID, I2C_DATA_MODE );
}
u8g->pin_list[U8G_PI_SET_A0] = 0;
return 1;
}
static void lu8g_digital_write( u8g_t *u8g, uint8_t pin_index, uint8_t value )
{
uint8_t pin;
pin = u8g->pin_list[pin_index];
if ( pin != U8G_PIN_NONE )
platform_gpio_write( pin, value );
}
void u8g_Delay(u8g_t *u8g, uint16_t msec)
{
const uint16_t chunk = 50;
if (u8g->use_delay == 0)
return;
while (msec > chunk)
{
os_delay_us( chunk*1000 );
msec -= chunk;
}
if (msec > 0)
os_delay_us( msec*1000 );
}
void u8g_MicroDelay(void)
{
os_delay_us( 1 );
}
void u8g_10MicroDelay(void)
{
os_delay_us( 10 );
}
uint8_t u8g_com_esp8266_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
{
switch(msg)
{
case U8G_COM_MSG_STOP:
break;
case U8G_COM_MSG_INIT:
// we assume that the SPI interface was already initialized
// just care for the /CS and D/C pins
lu8g_digital_write( u8g, U8G_PI_CS, PLATFORM_GPIO_HIGH );
platform_gpio_mode( u8g->pin_list[U8G_PI_CS], PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT );
platform_gpio_mode( u8g->pin_list[U8G_PI_A0], PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT );
break;
case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */
lu8g_digital_write( u8g, U8G_PI_A0, arg_val == 0 ? PLATFORM_GPIO_LOW : PLATFORM_GPIO_HIGH );
break;
case U8G_COM_MSG_CHIP_SELECT:
if (arg_val == 0)
{
/* disable */
lu8g_digital_write( u8g, U8G_PI_CS, PLATFORM_GPIO_HIGH );
}
else
{
/* enable */
//u8g_com_arduino_digital_write(u8g, U8G_PI_SCK, LOW);
lu8g_digital_write( u8g, U8G_PI_CS, PLATFORM_GPIO_LOW );
}
break;
case U8G_COM_MSG_RESET:
if ( u8g->pin_list[U8G_PI_RESET] != U8G_PIN_NONE )
lu8g_digital_write( u8g, U8G_PI_RESET, arg_val == 0 ? PLATFORM_GPIO_LOW : PLATFORM_GPIO_HIGH );
break;
case U8G_COM_MSG_WRITE_BYTE:
platform_spi_send( 1, 8, arg_val );
break;
case U8G_COM_MSG_WRITE_SEQ:
case U8G_COM_MSG_WRITE_SEQ_P:
{
register uint8_t *ptr = arg_ptr;
while( arg_val > 0 )
{
platform_spi_send( 1, 8, *ptr++ );
arg_val--;
}
}
break;
}
return 1;
}
uint8_t u8g_com_esp8266_ssd_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
{
switch(msg)
{
case U8G_COM_MSG_INIT:
// we assume that the i2c bus was already initialized
//u8g_i2c_init(u8g->pin_list[U8G_PI_I2C_OPTION]);
break;
case U8G_COM_MSG_STOP:
break;
case U8G_COM_MSG_RESET:
/* Currently disabled, but it could be enable. Previous restrictions have been removed */
/* u8g_com_arduino_digital_write(u8g, U8G_PI_RESET, arg_val); */
break;
case U8G_COM_MSG_CHIP_SELECT:
u8g->pin_list[U8G_PI_A0_STATE] = 0;
u8g->pin_list[U8G_PI_SET_A0] = 1; /* force a0 to set again, also forces start condition */
if ( arg_val == 0 )
{
/* disable chip, send stop condition */
platform_i2c_send_stop( ESP_I2C_ID );
}
else
{
/* enable, do nothing: any byte writing will trigger the i2c start */
}
break;
case U8G_COM_MSG_WRITE_BYTE:
//u8g->pin_list[U8G_PI_SET_A0] = 1;
if ( u8g_com_esp8266_ssd_start_sequence(u8g) == 0 )
return platform_i2c_send_stop( ESP_I2C_ID ), 0;
// ignore return value -> tolerate missing ACK
if ( platform_i2c_send_byte( ESP_I2C_ID, arg_val) == 0 )
; //return platform_i2c_send_stop( ESP_I2C_ID ), 0;
// platform_i2c_send_stop( ESP_I2C_ID );
break;
case U8G_COM_MSG_WRITE_SEQ:
case U8G_COM_MSG_WRITE_SEQ_P:
//u8g->pin_list[U8G_PI_SET_A0] = 1;
if ( u8g_com_esp8266_ssd_start_sequence(u8g) == 0 )
return platform_i2c_send_stop( ESP_I2C_ID ), 0;
{
register uint8_t *ptr = arg_ptr;
while( arg_val > 0 )
{
// ignore return value -> tolerate missing ACK
if ( platform_i2c_send_byte( ESP_I2C_ID, *ptr++) == 0 )
; //return platform_i2c_send_stop( ESP_I2C_ID ), 0;
arg_val--;
}
}
// platform_i2c_send_stop( ESP_I2C_ID );
break;
case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */
u8g->pin_list[U8G_PI_A0_STATE] = arg_val;
u8g->pin_list[U8G_PI_SET_A0] = 1; /* force a0 to set again */
break;
}
return 1;
}
// device destructor // device destructor
static int lu8g_close_display( lua_State *L ) static int lu8g_close_display( lua_State *L )
{ {
...@@ -996,6 +777,19 @@ static int lu8g_close_display( lua_State *L ) ...@@ -996,6 +777,19 @@ static int lu8g_close_display( lua_State *L )
if ((lud = get_lud( L )) == NULL) if ((lud = get_lud( L )) == NULL)
return 0; return 0;
if (lud->cb_ref != LUA_NOREF) {
// this is the fb_rle device
u8g_dev_t *fb_dev = LU8G->dev;
u8g_pb_t *fb_dev_pb = (u8g_pb_t *)(fb_dev->dev_mem);
uint8_t *fb_dev_buf = fb_dev_pb->buf;
luaM_free( L, fb_dev_buf );
luaM_free( L, fb_dev_pb );
luaM_free( L, fb_dev );
luaL_unref( L, lud->cb_ref, LUA_REGISTRYINDEX );
}
return 0; return 0;
} }
...@@ -1016,9 +810,10 @@ static int lu8g_close_display( lua_State *L ) ...@@ -1016,9 +810,10 @@ static int lu8g_close_display( lua_State *L )
return luaL_error( L, "i2c address required" ); \ return luaL_error( L, "i2c address required" ); \
\ \
lu8g_userdata_t *lud = (lu8g_userdata_t *) lua_newuserdata( L, sizeof( lu8g_userdata_t ) ); \ lu8g_userdata_t *lud = (lu8g_userdata_t *) lua_newuserdata( L, sizeof( lu8g_userdata_t ) ); \
lud->cb_ref = LUA_NOREF; \
\ \
lud->u8g.i2c_addr = (uint8_t)addr; \ lud->i2c_addr = (uint8_t)addr; \
lud->u8g.use_delay = del > 0 ? 1 : 0; \ lud->use_delay = del > 0 ? 1 : 0; \
\ \
u8g_InitI2C( LU8G, &u8g_dev_ ## device, U8G_I2C_OPT_NONE); \ u8g_InitI2C( LU8G, &u8g_dev_ ## device, U8G_I2C_OPT_NONE); \
\ \
...@@ -1049,8 +844,9 @@ U8G_DISPLAY_TABLE_I2C ...@@ -1049,8 +844,9 @@ U8G_DISPLAY_TABLE_I2C
unsigned del = luaL_optinteger( L, 4, 0 ); \ unsigned del = luaL_optinteger( L, 4, 0 ); \
\ \
lu8g_userdata_t *lud = (lu8g_userdata_t *) lua_newuserdata( L, sizeof( lu8g_userdata_t ) ); \ lu8g_userdata_t *lud = (lu8g_userdata_t *) lua_newuserdata( L, sizeof( lu8g_userdata_t ) ); \
lud->cb_ref = LUA_NOREF; \
\ \
lud->u8g.use_delay = del > 0 ? 1 : 0; \ lud->use_delay = del > 0 ? 1 : 0; \
\ \
u8g_InitHWSPI( LU8G, &u8g_dev_ ## device, cs, dc, res ); \ u8g_InitHWSPI( LU8G, &u8g_dev_ ## device, cs, dc, res ); \
\ \
...@@ -1064,6 +860,53 @@ U8G_DISPLAY_TABLE_I2C ...@@ -1064,6 +860,53 @@ U8G_DISPLAY_TABLE_I2C
// Unroll the display table and insert binding functions for SPI based displays. // Unroll the display table and insert binding functions for SPI based displays.
U8G_DISPLAY_TABLE_SPI U8G_DISPLAY_TABLE_SPI
// //
//
//
// This display forwards the framebuffer contents as run-length encoded chunks to a Lua callback
static int lu8g_fb_rle( lua_State *L ) {
lu8g_userdata_t *lud;
if ((lua_type( L, 1 ) != LUA_TFUNCTION) &&
(lua_type( L, 1 ) != LUA_TLIGHTFUNCTION)) {
luaL_typerror( L, 1, "function" );
}
int width = luaL_checkint( L, 2 );
int height = luaL_checkint( L, 3 );
luaL_argcheck( L, (width > 0) && (width < 256) && ((width % 8) == 0), 2, "invalid width" );
luaL_argcheck( L, (height > 0) && (height < 256) && ((height % 8) == 0), 3, "invalid height" );
// construct display device structures manually because width and height are configurable
uint8_t *fb_dev_buf = (uint8_t *)luaM_malloc( L, width );
u8g_pb_t *fb_dev_pb = (u8g_pb_t *)luaM_malloc( L, sizeof( u8g_pb_t ) );
fb_dev_pb->p.page_height = 8;
fb_dev_pb->p.total_height = height;
fb_dev_pb->p.page_y0 = 0;
fb_dev_pb->p.page_y1 = 0;
fb_dev_pb->p.page = 0;
fb_dev_pb->width = width;
fb_dev_pb->buf = fb_dev_buf;
u8g_dev_t *fb_dev = (u8g_dev_t *)luaM_malloc( L, sizeof( u8g_dev_t ) );
fb_dev->dev_fn = u8g_dev_gen_fb_fn;
fb_dev->dev_mem = fb_dev_pb;
fb_dev->com_fn = u8g_com_esp8266_fbrle_fn;
lud = (lu8g_userdata_t *) lua_newuserdata( L, sizeof( lu8g_userdata_t ) );
lua_pushvalue( L, 1 ); // copy argument (func) to the top of stack
lud->cb_ref = luaL_ref( L, LUA_REGISTRYINDEX );
/* set metatable for userdata */
luaL_getmetatable(L, "u8g.display");
lua_setmetatable(L, -2);
u8g_Init8BitFixedPort( LU8G, fb_dev, width, height, 0, 0, 0);
return 1;
}
//
// *************************************************************************** // ***************************************************************************
...@@ -1137,6 +980,8 @@ static const LUA_REG_TYPE lu8g_map[] = { ...@@ -1137,6 +980,8 @@ static const LUA_REG_TYPE lu8g_map[] = {
#define U8G_FONT_TABLE_ENTRY(font) \ #define U8G_FONT_TABLE_ENTRY(font) \
{ LSTRKEY( #font ), LUDATA( (void *)(u8g_ ## font) ) }, { LSTRKEY( #font ), LUDATA( (void *)(u8g_ ## font) ) },
U8G_FONT_TABLE U8G_FONT_TABLE
//
{ LSTRKEY( "fb_rle" ), LFUNCVAL( lu8g_fb_rle ) },
// Options for circle/ ellipse drawing // Options for circle/ ellipse drawing
{ LSTRKEY( "DRAW_UPPER_RIGHT" ), LNUMVAL( U8G_DRAW_UPPER_RIGHT ) }, { LSTRKEY( "DRAW_UPPER_RIGHT" ), LNUMVAL( U8G_DRAW_UPPER_RIGHT ) },
{ LSTRKEY( "DRAW_UPPER_LEFT" ), LNUMVAL( U8G_DRAW_UPPER_LEFT ) }, { LSTRKEY( "DRAW_UPPER_LEFT" ), LNUMVAL( U8G_DRAW_UPPER_LEFT ) },
......
/*
Functions for integrating U8glib into the nodemcu platform.
*/
#include "lauxlib.h"
#include "platform.h"
#include "c_stdlib.h"
#include "u8g.h"
#include "u8g_glue.h"
// ------------------------------------------------------------
// comm functions
//
#define I2C_CMD_MODE 0x000
#define I2C_DATA_MODE 0x040
#define ESP_I2C_ID 0
static uint8_t do_i2c_start(uint8_t id, uint8_t sla)
{
platform_i2c_send_start( id );
// ignore return value -> tolerate missing ACK
platform_i2c_send_address( id, sla, PLATFORM_I2C_DIRECTION_TRANSMITTER );
return 1;
}
static uint8_t u8g_com_esp8266_ssd_start_sequence(struct _lu8g_userdata_t *lu8g)
{
/* are we requested to set the a0 state? */
if ( lu8g->u8g.pin_list[U8G_PI_SET_A0] == 0 )
return 1;
/* setup bus, might be a repeated start */
if ( do_i2c_start( ESP_I2C_ID, lu8g->i2c_addr ) == 0 )
return 0;
if ( lu8g->u8g.pin_list[U8G_PI_A0_STATE] == 0 )
{
// ignore return value -> tolerate missing ACK
if ( platform_i2c_send_byte( ESP_I2C_ID, I2C_CMD_MODE ) == 0 )
; //return 0;
}
else
{
platform_i2c_send_byte( ESP_I2C_ID, I2C_DATA_MODE );
}
lu8g->u8g.pin_list[U8G_PI_SET_A0] = 0;
return 1;
}
static void lu8g_digital_write( struct _lu8g_userdata_t *lu8g, uint8_t pin_index, uint8_t value )
{
uint8_t pin;
pin = lu8g->u8g.pin_list[pin_index];
if ( pin != U8G_PIN_NONE )
platform_gpio_write( pin, value );
}
void u8g_Delay(u8g_t *u8g, uint16_t msec)
{
struct _lu8g_userdata_t *lu8g = (struct _lu8g_userdata_t *)u8g;
const uint16_t chunk = 50;
if (lu8g->use_delay == 0)
return;
while (msec > chunk)
{
os_delay_us( chunk*1000 );
msec -= chunk;
}
if (msec > 0)
os_delay_us( msec*1000 );
}
void u8g_MicroDelay(void)
{
os_delay_us( 1 );
}
void u8g_10MicroDelay(void)
{
os_delay_us( 10 );
}
uint8_t u8g_com_esp8266_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
{
struct _lu8g_userdata_t *lu8g = (struct _lu8g_userdata_t *)u8g;
switch(msg)
{
case U8G_COM_MSG_STOP:
break;
case U8G_COM_MSG_INIT:
// we assume that the SPI interface was already initialized
// just care for the /CS and D/C pins
lu8g_digital_write( lu8g, U8G_PI_CS, PLATFORM_GPIO_HIGH );
platform_gpio_mode( lu8g->u8g.pin_list[U8G_PI_CS], PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT );
platform_gpio_mode( lu8g->u8g.pin_list[U8G_PI_A0], PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT );
break;
case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */
lu8g_digital_write( lu8g, U8G_PI_A0, arg_val == 0 ? PLATFORM_GPIO_LOW : PLATFORM_GPIO_HIGH );
break;
case U8G_COM_MSG_CHIP_SELECT:
if (arg_val == 0)
{
/* disable */
lu8g_digital_write( lu8g, U8G_PI_CS, PLATFORM_GPIO_HIGH );
}
else
{
/* enable */
lu8g_digital_write( lu8g, U8G_PI_CS, PLATFORM_GPIO_LOW );
}
break;
case U8G_COM_MSG_RESET:
if ( lu8g->u8g.pin_list[U8G_PI_RESET] != U8G_PIN_NONE )
lu8g_digital_write( lu8g, U8G_PI_RESET, arg_val == 0 ? PLATFORM_GPIO_LOW : PLATFORM_GPIO_HIGH );
break;
case U8G_COM_MSG_WRITE_BYTE:
platform_spi_send( 1, 8, arg_val );
break;
case U8G_COM_MSG_WRITE_SEQ:
case U8G_COM_MSG_WRITE_SEQ_P:
{
register uint8_t *ptr = arg_ptr;
while( arg_val > 0 )
{
platform_spi_send( 1, 8, *ptr++ );
arg_val--;
}
}
break;
}
return 1;
}
uint8_t u8g_com_esp8266_ssd_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
{
struct _lu8g_userdata_t *lu8g = (struct _lu8g_userdata_t *)u8g;
switch(msg)
{
case U8G_COM_MSG_INIT:
// we assume that the i2c bus was already initialized
//u8g_i2c_init(u8g->pin_list[U8G_PI_I2C_OPTION]);
break;
case U8G_COM_MSG_STOP:
break;
case U8G_COM_MSG_RESET:
/* Currently disabled, but it could be enable. Previous restrictions have been removed */
/* u8g_com_arduino_digital_write(u8g, U8G_PI_RESET, arg_val); */
break;
case U8G_COM_MSG_CHIP_SELECT:
lu8g->u8g.pin_list[U8G_PI_A0_STATE] = 0;
lu8g->u8g.pin_list[U8G_PI_SET_A0] = 1; /* force a0 to set again, also forces start condition */
if ( arg_val == 0 )
{
/* disable chip, send stop condition */
platform_i2c_send_stop( ESP_I2C_ID );
}
else
{
/* enable, do nothing: any byte writing will trigger the i2c start */
}
break;
case U8G_COM_MSG_WRITE_BYTE:
//u8g->pin_list[U8G_PI_SET_A0] = 1;
if ( u8g_com_esp8266_ssd_start_sequence(lu8g) == 0 )
return platform_i2c_send_stop( ESP_I2C_ID ), 0;
// ignore return value -> tolerate missing ACK
if ( platform_i2c_send_byte( ESP_I2C_ID, arg_val) == 0 )
; //return platform_i2c_send_stop( ESP_I2C_ID ), 0;
// platform_i2c_send_stop( ESP_I2C_ID );
break;
case U8G_COM_MSG_WRITE_SEQ:
case U8G_COM_MSG_WRITE_SEQ_P:
//u8g->pin_list[U8G_PI_SET_A0] = 1;
if ( u8g_com_esp8266_ssd_start_sequence(lu8g) == 0 )
return platform_i2c_send_stop( ESP_I2C_ID ), 0;
{
register uint8_t *ptr = arg_ptr;
while( arg_val > 0 )
{
// ignore return value -> tolerate missing ACK
if ( platform_i2c_send_byte( ESP_I2C_ID, *ptr++) == 0 )
; //return platform_i2c_send_stop( ESP_I2C_ID ), 0;
arg_val--;
}
}
// platform_i2c_send_stop( ESP_I2C_ID );
break;
case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */
lu8g->u8g.pin_list[U8G_PI_A0_STATE] = arg_val;
lu8g->u8g.pin_list[U8G_PI_SET_A0] = 1; /* force a0 to set again */
break;
}
return 1;
}
// ***************************************************************************
// Generic framebuffer device and RLE comm driver
//
uint8_t u8g_dev_gen_fb_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg)
{
switch(msg)
{
case U8G_DEV_MSG_PAGE_FIRST:
// tell comm driver to start new framebuffer
u8g_SetChipSelect(u8g, dev, 1);
break;
case U8G_DEV_MSG_PAGE_NEXT:
{
u8g_pb_t *pb = (u8g_pb_t *)(dev->dev_mem);
if ( u8g_pb_WriteBuffer(pb, u8g, dev) == 0 )
return 0;
}
break;
}
return u8g_dev_pb8v1_base_fn(u8g, dev, msg, arg);
}
static int bit_at( uint8_t *buf, int line, int x )
{
uint8_t byte = buf[x];
return buf[x] & (1 << line) ? 1 : 0;
}
struct _lu8g_fbrle_item
{
uint8_t start_x;
uint8_t len;
};
struct _lu8g_fbrle_line
{
uint8_t num_valid;
struct _lu8g_fbrle_item items[0];
};
uint8_t u8g_com_esp8266_fbrle_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
{
struct _lu8g_userdata_t *lud = (struct _lu8g_userdata_t *)u8g;
switch(msg)
{
case U8G_COM_MSG_INIT:
// allocate memory -> done
// init buffer
break;
case U8G_COM_MSG_CHIP_SELECT:
if (arg_val == 1) {
// new frame starts
if (lud->cb_ref != LUA_NOREF) {
// fire callback with nil argument
lua_State *L = lua_getstate();
lua_rawgeti( L, LUA_REGISTRYINDEX, lud->cb_ref );
lua_pushnil( L );
lua_call( L, 1, 0 );
}
}
break;
case U8G_COM_MSG_WRITE_SEQ:
case U8G_COM_MSG_WRITE_SEQ_P:
{
uint8_t xwidth = u8g->pin_list[U8G_PI_EN];
size_t fbrle_line_size = sizeof( struct _lu8g_fbrle_line ) + sizeof( struct _lu8g_fbrle_item ) * (xwidth/2);
int num_lines = arg_val / (xwidth/8);
uint8_t *buf = (uint8_t *)arg_ptr;
struct _lu8g_fbrle_line *fbrle_line;
if (!(fbrle_line = (struct _lu8g_fbrle_line *)c_malloc( fbrle_line_size ))) {
break;
}
for (int line = 0; line < num_lines; line++) {
int start_run = -1;
fbrle_line->num_valid = 0;
for (int x = 0; x < xwidth; x++) {
if (bit_at( buf, line, x ) == 0) {
if (start_run >= 0) {
// inside run, end it and enter result
fbrle_line->items[fbrle_line->num_valid].start_x = start_run;
fbrle_line->items[fbrle_line->num_valid++].len = x - start_run;
//NODE_ERR( " line: %d x: %d len: %d\n", line, start_run, x - start_run );
start_run = -1;
}
} else {
if (start_run < 0) {
// outside run, start it
start_run = x;
}
}
if (fbrle_line->num_valid >= xwidth/2) break;
}
// active run?
if (start_run >= 0 && fbrle_line->num_valid < xwidth/2) {
fbrle_line->items[fbrle_line->num_valid].start_x = start_run;
fbrle_line->items[fbrle_line->num_valid++].len = xwidth - start_run;
}
// line done, trigger callback
if (lud->cb_ref != LUA_NOREF) {
lua_State *L = lua_getstate();
lua_rawgeti( L, LUA_REGISTRYINDEX, lud->cb_ref );
lua_pushlstring( L, (const char *)fbrle_line, fbrle_line_size );
lua_call( L, 1, 0 );
}
}
c_free( fbrle_line );
}
break;
}
return 1;
}
#ifndef _U8G_GLUE_H_
#define _U8G_GLUE_H_
#include "u8g.h"
struct _lu8g_userdata_t
{
u8g_t u8g;
uint8_t i2c_addr;
uint8_t use_delay;
int cb_ref;
};
typedef struct _lu8g_userdata_t lu8g_userdata_t;
// shorthand macro for the u8g structure inside the userdata
#define LU8G (&(lud->u8g))
uint8_t u8g_com_esp8266_fbrle_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr);
uint8_t u8g_dev_gen_fb_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg);
#endif
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "c_types.h" #include "c_types.h"
#include "c_string.h" #include "c_string.h"
#include "c_stdlib.h"
#include "websocketclient.h" #include "websocketclient.h"
...@@ -45,7 +46,7 @@ static void websocketclient_onConnectionCallback(ws_info *ws) { ...@@ -45,7 +46,7 @@ static void websocketclient_onConnectionCallback(ws_info *ws) {
} }
} }
static void websocketclient_onReceiveCallback(ws_info *ws, char *message, int opCode) { static void websocketclient_onReceiveCallback(ws_info *ws, int len, char *message, int opCode) {
NODE_DBG("websocketclient_onReceiveCallback\n"); NODE_DBG("websocketclient_onReceiveCallback\n");
lua_State *L = lua_getstate(); lua_State *L = lua_getstate();
...@@ -59,7 +60,7 @@ static void websocketclient_onReceiveCallback(ws_info *ws, char *message, int op ...@@ -59,7 +60,7 @@ static void websocketclient_onReceiveCallback(ws_info *ws, char *message, int op
if (data->onReceive != LUA_NOREF) { if (data->onReceive != LUA_NOREF) {
lua_rawgeti(L, LUA_REGISTRYINDEX, data->onReceive); // load the callback function lua_rawgeti(L, LUA_REGISTRYINDEX, data->onReceive); // load the callback function
lua_rawgeti(L, LUA_REGISTRYINDEX, data->self_ref); // pass itself, #1 callback argument lua_rawgeti(L, LUA_REGISTRYINDEX, data->self_ref); // pass itself, #1 callback argument
lua_pushstring(L, message); // #2 callback argument lua_pushlstring(L, message, len); // #2 callback argument
lua_pushnumber(L, opCode); // #3 callback argument lua_pushnumber(L, opCode); // #3 callback argument
lua_call(L, 3, 0); lua_call(L, 3, 0);
} }
...@@ -102,6 +103,7 @@ static int websocket_createClient(lua_State *L) { ...@@ -102,6 +103,7 @@ static int websocket_createClient(lua_State *L) {
ws_info *ws = (ws_info *) lua_newuserdata(L, sizeof(ws_info)); ws_info *ws = (ws_info *) lua_newuserdata(L, sizeof(ws_info));
ws->connectionState = 0; ws->connectionState = 0;
ws->extraHeaders = NULL;
ws->onConnection = &websocketclient_onConnectionCallback; ws->onConnection = &websocketclient_onConnectionCallback;
ws->onReceive = &websocketclient_onReceiveCallback; ws->onReceive = &websocketclient_onReceiveCallback;
ws->onFailure = &websocketclient_onCloseCallback; ws->onFailure = &websocketclient_onCloseCallback;
...@@ -118,7 +120,6 @@ static int websocketclient_on(lua_State *L) { ...@@ -118,7 +120,6 @@ static int websocketclient_on(lua_State *L) {
NODE_DBG("websocketclient_on\n"); NODE_DBG("websocketclient_on\n");
ws_info *ws = (ws_info *) luaL_checkudata(L, 1, METATABLE_WSCLIENT); ws_info *ws = (ws_info *) luaL_checkudata(L, 1, METATABLE_WSCLIENT);
luaL_argcheck(L, ws, 1, "Client websocket expected");
ws_data *data = (ws_data *) ws->reservedData; ws_data *data = (ws_data *) ws->reservedData;
...@@ -170,7 +171,6 @@ static int websocketclient_connect(lua_State *L) { ...@@ -170,7 +171,6 @@ static int websocketclient_connect(lua_State *L) {
NODE_DBG("websocketclient_connect is called.\n"); NODE_DBG("websocketclient_connect is called.\n");
ws_info *ws = (ws_info *) luaL_checkudata(L, 1, METATABLE_WSCLIENT); ws_info *ws = (ws_info *) luaL_checkudata(L, 1, METATABLE_WSCLIENT);
luaL_argcheck(L, ws, 1, "Client websocket expected");
ws_data *data = (ws_data *) ws->reservedData; ws_data *data = (ws_data *) ws->reservedData;
...@@ -188,11 +188,61 @@ static int websocketclient_connect(lua_State *L) { ...@@ -188,11 +188,61 @@ static int websocketclient_connect(lua_State *L) {
return 0; return 0;
} }
static header_t *realloc_headers(header_t *headers, int new_size) {
if(headers) {
for(header_t *header = headers; header->key; header++) {
c_free(header->value);
c_free(header->key);
}
c_free(headers);
}
if(!new_size)
return NULL;
return (header_t *)c_malloc(sizeof(header_t) * (new_size + 1));
}
static int websocketclient_config(lua_State *L) {
NODE_DBG("websocketclient_config is called.\n");
ws_info *ws = (ws_info *) luaL_checkudata(L, 1, METATABLE_WSCLIENT);
ws_data *data = (ws_data *) ws->reservedData;
luaL_checktype(L, 2, LUA_TTABLE);
lua_getfield(L, 2, "headers");
if(lua_istable(L, -1)) {
lua_pushnil(L);
int size = 0;
while(lua_next(L, -2)) {
size++;
lua_pop(L, 1);
}
ws->extraHeaders = realloc_headers(ws->extraHeaders, size);
if(ws->extraHeaders) {
header_t *header = ws->extraHeaders;
lua_pushnil(L);
while(lua_next(L, -2)) {
header->key = c_strdup(lua_tostring(L, -2));
header->value = c_strdup(lua_tostring(L, -1));
header++;
lua_pop(L, 1);
}
header->key = header->value = NULL;
}
}
lua_pop(L, 1); // pop headers
return 0;
}
static int websocketclient_send(lua_State *L) { static int websocketclient_send(lua_State *L) {
NODE_DBG("websocketclient_send is called.\n"); NODE_DBG("websocketclient_send is called.\n");
ws_info *ws = (ws_info *) luaL_checkudata(L, 1, METATABLE_WSCLIENT); ws_info *ws = (ws_info *) luaL_checkudata(L, 1, METATABLE_WSCLIENT);
luaL_argcheck(L, ws, 1, "Client websocket expected");
ws_data *data = (ws_data *) ws->reservedData; ws_data *data = (ws_data *) ws->reservedData;
...@@ -225,7 +275,8 @@ static int websocketclient_gc(lua_State *L) { ...@@ -225,7 +275,8 @@ static int websocketclient_gc(lua_State *L) {
NODE_DBG("websocketclient_gc\n"); NODE_DBG("websocketclient_gc\n");
ws_info *ws = (ws_info *) luaL_checkudata(L, 1, METATABLE_WSCLIENT); ws_info *ws = (ws_info *) luaL_checkudata(L, 1, METATABLE_WSCLIENT);
luaL_argcheck(L, ws, 1, "Client websocket expected");
ws->extraHeaders = realloc_headers(ws->extraHeaders, 0);
ws_data *data = (ws_data *) ws->reservedData; ws_data *data = (ws_data *) ws->reservedData;
...@@ -265,6 +316,7 @@ static const LUA_REG_TYPE websocket_map[] = ...@@ -265,6 +316,7 @@ static const LUA_REG_TYPE websocket_map[] =
static const LUA_REG_TYPE websocketclient_map[] = static const LUA_REG_TYPE websocketclient_map[] =
{ {
{ LSTRKEY("on"), LFUNCVAL(websocketclient_on) }, { LSTRKEY("on"), LFUNCVAL(websocketclient_on) },
{ LSTRKEY("config"), LFUNCVAL(websocketclient_config) },
{ LSTRKEY("connect"), LFUNCVAL(websocketclient_connect) }, { LSTRKEY("connect"), LFUNCVAL(websocketclient_connect) },
{ LSTRKEY("send"), LFUNCVAL(websocketclient_send) }, { LSTRKEY("send"), LFUNCVAL(websocketclient_send) },
{ LSTRKEY("close"), LFUNCVAL(websocketclient_close) }, { LSTRKEY("close"), LFUNCVAL(websocketclient_close) },
......
// Module for interfacing with WIFI // Module for interfacing with WIFI
// FIXME: sprintf->snprintf everywhere.
#include "module.h" #include "module.h"
#include "lauxlib.h" #include "lauxlib.h"
#include "platform.h" #include "platform.h"
...@@ -76,12 +78,8 @@ static void wifi_smart_succeed_cb(sc_status status, void *pdata){ ...@@ -76,12 +78,8 @@ static void wifi_smart_succeed_cb(sc_status status, void *pdata){
#endif // WIFI_SMART_ENABLE #endif // WIFI_SMART_ENABLE
static int wifi_scan_succeed = LUA_NOREF; static int wifi_scan_succeed = LUA_NOREF;
/**
* @brief Wifi ap scan over callback to display. // callback for wifi_station_listap
* @param arg: contain the aps information
* @param status: scan over status
* @retval None
*/
static void wifi_scan_done(void *arg, STATUS status) static void wifi_scan_done(void *arg, STATUS status)
{ {
lua_State* L = lua_getstate(); lua_State* L = lua_getstate();
...@@ -215,23 +213,26 @@ static int wifi_exit_smart( lua_State* L ) ...@@ -215,23 +213,26 @@ static int wifi_exit_smart( lua_State* L )
} }
#endif // WIFI_SMART_ENABLE #endif // WIFI_SMART_ENABLE
// Lua: realmode = setmode(mode) // Lua: wifi.setmode(mode, save_to_flash)
static int wifi_setmode( lua_State* L ) static int wifi_setmode( lua_State* L )
{ {
unsigned mode; unsigned mode;
bool save_to_flash=true;
mode = luaL_checkinteger( L, 1 ); mode = luaL_checkinteger( L, 1 );
luaL_argcheck(L, mode == STATION_MODE || mode == SOFTAP_MODE || mode == STATIONAP_MODE || mode == NULL_MODE, 1, "Invalid mode");
if ( mode != STATION_MODE && mode != SOFTAP_MODE && mode != STATIONAP_MODE && mode != NULL_MODE ) if(!lua_isnoneornil(L, 2))
return luaL_error( L, "wrong arg type" ); {
wifi_set_opmode( (uint8_t)mode); if(!lua_isboolean(L, 2)) luaL_typerror(L, 2, lua_typename(L, LUA_TBOOLEAN));
save_to_flash=lua_toboolean(L, 2);
}
if(save_to_flash) wifi_set_opmode( (uint8_t)mode);
else wifi_set_opmode_current( (uint8_t)mode);
mode = (unsigned)wifi_get_opmode(); mode = (unsigned)wifi_get_opmode();
lua_pushinteger( L, mode ); lua_pushinteger( L, mode );
return 1; return 1;
} }
// Lua: realmode = getmode() // Lua: wifi.getmode()
static int wifi_getmode( lua_State* L ) static int wifi_getmode( lua_State* L )
{ {
unsigned mode; unsigned mode;
...@@ -239,20 +240,17 @@ static int wifi_getmode( lua_State* L ) ...@@ -239,20 +240,17 @@ static int wifi_getmode( lua_State* L )
lua_pushinteger( L, mode ); lua_pushinteger( L, mode );
return 1; return 1;
} }
/**
* wifi.getchannel()
* Description:
* Get current wifi Channel
*
* Syntax:
* wifi.getchannel()
* Parameters:
* nil
*
* Returns:
* Current wifi channel
*/
// Lua: wifi.getdefaultmode()
static int wifi_getdefaultmode( lua_State* L )
{
unsigned mode;
mode = (unsigned)wifi_get_opmode_default();
lua_pushinteger( L, mode );
return 1;
}
// Lua: wifi.getchannel()
static int wifi_getchannel( lua_State* L ) static int wifi_getchannel( lua_State* L )
{ {
unsigned channel; unsigned channel;
...@@ -261,22 +259,7 @@ static int wifi_getchannel( lua_State* L ) ...@@ -261,22 +259,7 @@ static int wifi_getchannel( lua_State* L )
return 1; return 1;
} }
/** // Lua: wifi.setphymode()
* wifi.setphymode()
* Description:
* Set wifi physical mode(802.11 b/g/n)
* Note: SoftAP only supports 802.11 b/g.
* Syntax:
* wifi.setphymode(mode)
* Parameters:
* mode:
* wifi.PHYMODE_B
* wifi.PHYMODE_G
* wifi.PHYMODE_N
* Returns:
* Current physical mode after setup
*/
static int wifi_setphymode( lua_State* L ) static int wifi_setphymode( lua_State* L )
{ {
unsigned mode; unsigned mode;
...@@ -291,18 +274,7 @@ static int wifi_setphymode( lua_State* L ) ...@@ -291,18 +274,7 @@ static int wifi_setphymode( lua_State* L )
return 1; return 1;
} }
/** // Lua: wifi.getphymode()
* wifi.getphymode()
* Description:
* Get wifi physical mode(802.11 b/g/n)
* Syntax:
* wifi.getphymode()
* Parameters:
* nil
* Returns:
* Current physical mode.
*
*/
static int wifi_getphymode( lua_State* L ) static int wifi_getphymode( lua_State* L )
{ {
unsigned mode; unsigned mode;
...@@ -311,7 +283,7 @@ static int wifi_getphymode( lua_State* L ) ...@@ -311,7 +283,7 @@ static int wifi_getphymode( lua_State* L )
return 1; return 1;
} }
//wifi.sleep() // Lua: wifi.sleep()
static int wifi_sleep(lua_State* L) static int wifi_sleep(lua_State* L)
{ {
uint8 desired_sleep_state = 2; uint8 desired_sleep_state = 2;
...@@ -372,7 +344,7 @@ static int wifi_sleep(lua_State* L) ...@@ -372,7 +344,7 @@ static int wifi_sleep(lua_State* L)
return 2; return 2;
} }
//wifi.nullmodesleep() // Lua: wifi.nullmodesleep()
static int wifi_null_mode_auto_sleep(lua_State* L) static int wifi_null_mode_auto_sleep(lua_State* L)
{ {
if (!lua_isnone(L, 1)) if (!lua_isnone(L, 1))
...@@ -459,7 +431,7 @@ static int wifi_getbroadcast( lua_State* L, uint8_t mode ) ...@@ -459,7 +431,7 @@ static int wifi_getbroadcast( lua_State* L, uint8_t mode )
} }
} }
// Used by wifi_setip
static uint32_t parse_key(lua_State* L, const char * key){ static uint32_t parse_key(lua_State* L, const char * key){
lua_getfield(L, 1, key); lua_getfield(L, 1, key);
if( lua_isstring(L, -1) ) // deal with the ip/netmask/gw string if( lua_isstring(L, -1) ) // deal with the ip/netmask/gw string
...@@ -506,24 +478,86 @@ static int wifi_setip( lua_State* L, uint8_t mode ) ...@@ -506,24 +478,86 @@ static int wifi_setip( lua_State* L, uint8_t mode )
return 1; return 1;
} }
// Lua: realtype = sleeptype(type) // Lua: wifi.sta.getaplist
static int wifi_sleeptype( lua_State* L ) static int wifi_station_get_ap_info4lua( lua_State* L )
{ {
unsigned type; struct station_config config[5];
char temp[sizeof(config[0].password)+1]; //max password length + '\0'
if ( lua_isnumber(L, 1) ){ uint8 number_of_aps = wifi_station_get_ap_info(config);
type = lua_tointeger(L, 1);
if ( type != NONE_SLEEP_T && type != LIGHT_SLEEP_T && type != MODEM_SLEEP_T ) #if defined(WIFI_DEBUG)
return luaL_error( L, "wrong arg type" ); char debug_temp[128];
if(!wifi_set_sleep_type(type)){ #endif
lua_pushnil(L); lua_newtable(L);
return 1; lua_pushnumber(L, number_of_aps);
lua_setfield(L, -2, "qty");
WIFI_DBG("\n\t# of APs stored in flash:%d\n", number_of_aps);
WIFI_DBG(" %-6s %-32s %-64s %-17s\n", "index:", "ssid:", "password:", "bssid:");
for(int i=0;i<number_of_aps;i++)
{
lua_newtable(L);
memset(temp, 0, sizeof(temp));
memcpy(temp, config[i].ssid, sizeof(config[i].ssid));
lua_pushstring(L, temp);
lua_setfield(L, -2, "ssid");
#if defined(WIFI_DEBUG)
c_sprintf(debug_temp, " %-6d %-32s ", i, temp);
#endif
memset(temp, 0, sizeof(temp));
if(strlen(config[i].password) >= 8)
{
memcpy(temp, config[i].password, sizeof(config[i].password));
lua_pushstring(L, temp);
lua_setfield(L, -2, "pwd");
} }
#if defined(WIFI_DEBUG)
c_sprintf(debug_temp + strlen(debug_temp), "%-64s ", temp);
#endif
memset(temp, 0, sizeof(temp));
if (config[i].bssid_set)
{
c_sprintf(temp, MACSTR, MAC2STR(config[i].bssid));
lua_pushstring(L, temp);
lua_setfield(L, -2, "bssid");
}
#if defined(WIFI_DEBUG)
WIFI_DBG("%s%-17s \n", debug_temp, temp);
#endif
lua_pushnumber(L, i+1); //Add one, so that AP index follows Lua Conventions
lua_insert(L, -2);
lua_settable(L, -3);
} }
return 1;
}
type = wifi_get_sleep_type(); // Lua: wifi.setapnumber(number_of_aps_to_save)
lua_pushinteger( L, type ); static int wifi_station_ap_number_set4lua( lua_State* L )
return 1; {
unsigned limit=luaL_checkinteger(L, 1);
luaL_argcheck(L, (limit >= 1 && limit <= 5), 1, "Valid range: 1-5");
lua_pushboolean(L, wifi_station_ap_number_set((uint8)limit));
return 1;
}
// Lua: wifi.setapnumber(number_of_aps_to_save)
static int wifi_station_change_ap( lua_State* L )
{
uint8 ap_index=luaL_checkinteger(L, 1);
luaL_argcheck(L, (ap_index >= 1 && ap_index <= 5), 1, "Valid range: 1-5");
lua_pushboolean(L, wifi_station_ap_change(ap_index-1));
return 1;
}
// Lua: wifi.setapnumber(number_of_aps_to_save)
static int wifi_station_get_ap_index( lua_State* L )
{
lua_pushnumber(L, wifi_station_get_current_ap_id()+1);
return 1;
} }
// Lua: wifi.sta.getmac() // Lua: wifi.sta.getmac()
...@@ -551,161 +585,230 @@ static int wifi_station_getbroadcast( lua_State* L ){ ...@@ -551,161 +585,230 @@ static int wifi_station_getbroadcast( lua_State* L ){
return wifi_getbroadcast(L, STATION_IF); return wifi_getbroadcast(L, STATION_IF);
} }
/** // Used by wifi_station_getconfig_xxx
* wifi.sta.getconfig() static int wifi_station_getconfig( lua_State* L, bool get_flash_cfg)
* Description:
* Get current Station configuration.
* Note: if bssid_set==1 STATION is configured to connect to specified BSSID
* if bssid_set==0 specified BSSID address is irrelevant.
* Syntax:
* ssid, pwd, bssid_set, bssid=wifi.sta.getconfig()
* Parameters:
* none
* Returns:
* SSID, Password, BSSID_set, BSSID
*/
static int wifi_station_getconfig( lua_State* L )
{ {
struct station_config sta_conf;
char bssid[17];
wifi_station_get_config(&sta_conf);
if(sta_conf.ssid==0)
{
lua_pushnil(L);
return 1;
}
else
{
lua_pushstring( L, sta_conf.ssid );
lua_pushstring( L, sta_conf.password );
lua_pushinteger( L, sta_conf.bssid_set);
c_sprintf(bssid, MACSTR, MAC2STR(sta_conf.bssid));
lua_pushstring( L, bssid);
return 4;
}
}
/**
* wifi.sta.config()
* Description:
* Set current Station configuration.
* Note: If there are multiple APs with the same ssid, you can connect to a specific one by entering it's MAC address into the "bssid" field.
* Syntax:
* wifi.sta.getconfig(ssid, password) --Set STATION configuration, Auto-connect by default, Connects to any BSSID
* wifi.sta.getconfig(ssid, password, Auto_connect) --Set STATION configuration, Auto-connect(0 or 1), Connects to any BSSID
* wifi.sta.getconfig(ssid, password, bssid) --Set STATION configuration, Auto-connect by default, Connects to specific BSSID
* wifi.sta.getconfig(ssid, password, Auto_connect, bssid) --Set STATION configuration, Auto-connect(0 or 1), Connects to specific BSSID
* Parameters:
* ssid: string which is less than 32 bytes.
* Password: string which is less than 64 bytes.
* Auto_connect: 0 (disable Auto-connect) or 1 (to enable Auto-connect).
* bssid: MAC address of Access Point you would like to connect to.
* Returns:
* Nothing.
*
* Example:
--Connect to Access Point automatically when in range
wifi.sta.getconfig("myssid", "password")
--Connect to Access Point, User decides when to connect/disconnect to/from AP
wifi.sta.getconfig("myssid", "mypassword", 0)
wifi.sta.connect()
--do some wifi stuff
wifi.sta.disconnect()
--Connect to specific Access Point automatically when in range
wifi.sta.getconfig("myssid", "mypassword", "12:34:56:78:90:12")
--Connect to specific Access Point, User decides when to connect/disconnect to/from AP
wifi.sta.getconfig("myssid", "mypassword", 0)
wifi.sta.connect()
--do some wifi stuff
wifi.sta.disconnect()
*
*/
static int wifi_station_config( lua_State* L )
{
size_t sl, pl, ml;
struct station_config sta_conf; struct station_config sta_conf;
int auto_connect=0; char temp[sizeof(sta_conf.password)+1]; //max password length + '\0'
const char *ssid = luaL_checklstring( L, 1, &sl ); if(get_flash_cfg) wifi_station_get_config_default(&sta_conf);
if (sl>32 || ssid == NULL) else wifi_station_get_config(&sta_conf);
return luaL_error( L, "ssid:<32" ); if(sta_conf.ssid==0)
const char *password = luaL_checklstring( L, 2, &pl );
if ((pl!=0 && (pl<8 || pl>64)) || password == NULL)
return luaL_error( L, "pwd:0,8~64" );
if(lua_isnumber(L, 3))
{ {
auto_connect=luaL_checkinteger( L, 3 );; lua_pushnil(L);
if ( auto_connect != 0 && auto_connect != 1) return 1;
return luaL_error( L, "wrong arg type" );
}
else if (lua_isstring(L, 3)&& !(lua_isnumber(L, 3)))
{
lua_pushnil(L);
lua_insert(L, 3);
auto_connect=1;
} }
else else
{ {
if(lua_isnil(L, 3)) if(lua_isboolean(L, 1) && lua_toboolean(L, 1)==true)
return luaL_error( L, "wrong arg type" ); {
auto_connect=1; lua_newtable(L);
memset(temp, 0, sizeof(temp));
memcpy(temp, sta_conf.ssid, sizeof(sta_conf.ssid));
lua_pushstring(L, temp);
lua_setfield(L, -2, "ssid");
if(strlen(sta_conf.password) >= 8)
{
memset(temp, 0, sizeof(temp));
memcpy(temp, sta_conf.password, sizeof(sta_conf.password));
lua_pushstring(L, temp);
lua_setfield(L, -2, "pwd");
}
if(sta_conf.bssid_set==1)
{
memset(temp, 0, sizeof(temp));
c_sprintf(temp, MACSTR, MAC2STR(sta_conf.bssid));
lua_pushstring( L, temp);
lua_setfield(L, -2, "bssid");
}
return 1;
}
else
{
memset(temp, 0, sizeof(temp));
memcpy(temp, sta_conf.ssid, sizeof(sta_conf.ssid));
lua_pushstring(L, temp);
memset(temp, 0, sizeof(temp));
memcpy(temp, sta_conf.password, sizeof(sta_conf.password));
lua_pushstring(L, temp);
lua_pushinteger( L, sta_conf.bssid_set);
c_sprintf(temp, MACSTR, MAC2STR(sta_conf.bssid));
lua_pushstring( L, temp);
return 4;
}
} }
}
// Lua: wifi.sta.getconfig()
static int wifi_station_getconfig_current(lua_State *L)
{
return wifi_station_getconfig(L, false);
}
// Lua: wifi.sta.getdefaultconfig()
static int wifi_station_getconfig_default(lua_State *L)
{
return wifi_station_getconfig(L, true);
}
// Lua: wifi.sta.config()
static int wifi_station_config( lua_State* L )
{
struct station_config sta_conf;
bool auto_connect=true;
bool save_to_flash=true;
size_t sl, pl, ml;
memset(sta_conf.ssid, 0, sizeof(sta_conf.ssid));
memset(sta_conf.password, 0, sizeof(sta_conf.password));
memset(sta_conf.bssid, 0, sizeof(sta_conf.bssid));
sta_conf.bssid_set=0;
if(lua_isnumber(L, 4)) if(lua_istable(L, 1))
{ {
sta_conf.bssid_set = 0; lua_getfield(L, 1, "ssid");
c_memset(sta_conf.bssid, 0, 6); if (!lua_isnil(L, -1))
{
if( lua_isstring(L, -1) )
{
const char *ssid = luaL_checklstring( L, -1, &sl );
luaL_argcheck(L, ((sl>=1 && sl<=sizeof(sta_conf.ssid)) ), 1, "ssid: length:1-32");
memcpy(sta_conf.ssid, ssid, sl);
}
else return luaL_argerror( L, 1, "ssid:not string" );
}
else return luaL_argerror( L, 1, "ssid required" );
lua_pop(L, 1);
lua_getfield(L, 1, "pwd");
if (!lua_isnil(L, -1))
{
if( lua_isstring(L, -1) )
{
const char *pwd = luaL_checklstring( L, -1, &pl );
luaL_argcheck(L, ((pl>=8 && pl<=sizeof(sta_conf.password)) ), 1, "pwd: length:8-64");
memcpy(sta_conf.password, pwd, pl);
}
else return luaL_argerror( L, 1, "pwd:not string" );
}
lua_pop(L, 1);
lua_getfield(L, 1, "bssid");
if (!lua_isnil(L, -1))
{
if (lua_isstring(L, -1))
{
const char *macaddr = luaL_checklstring( L, -1, &ml );
luaL_argcheck(L, ((ml==sizeof("AA:BB:CC:DD:EE:FF")-1) ), 1, "bssid: FF:FF:FF:FF:FF:FF");
ets_str2macaddr(sta_conf.bssid, macaddr);
sta_conf.bssid_set = 1;
}
else return luaL_argerror(L, 1, "bssid:not string");
}
lua_pop(L, 1);
lua_getfield(L, 1, "auto");
if (!lua_isnil(L, -1))
{
if (lua_isboolean(L, -1))
{
auto_connect=lua_toboolean(L, -1);
}
else return luaL_argerror(L, 1, "auto:not boolean");
}
lua_pop(L, 1);
lua_getfield(L, 1, "save");
if (!lua_isnil(L, -1))
{
if (lua_isboolean(L, -1)) save_to_flash=lua_toboolean(L, -1);
else return luaL_argerror(L, 1, "save:not boolean");
}
else save_to_flash=false;
lua_pop(L, 1);
} }
else else //to be depreciated
{ {
if (lua_isstring(L, 4)) const char *ssid = luaL_checklstring( L, 1, &sl );
{ luaL_argcheck(L, ((sl>=1 && sl<sizeof(sta_conf.ssid)) ), 1, "length:1-32");
const char *macaddr = luaL_checklstring( L, 4, &ml );
luaL_argcheck(L, ml==17, 1, INVALID_MAC_STR); memcpy(sta_conf.ssid, ssid, sl);
c_memset(sta_conf.bssid, 0, 6);
ets_str2macaddr(sta_conf.bssid, macaddr); const char *password = luaL_checklstring( L, 2, &pl );
sta_conf.bssid_set = 1; luaL_argcheck(L, (pl==0||(pl>=8 && pl<sizeof(sta_conf.password)) ), 2, "length:0 or 8-64");
}
else memcpy(sta_conf.password, password, pl);
{
sta_conf.bssid_set = 0; if(lua_isnumber(L, 3))
c_memset(sta_conf.bssid, 0, 6); {
} lua_Integer lint=luaL_checkinteger( L, 3 );
if ( lint != 0 && lint != 1)
return luaL_error( L, "wrong arg type" );
auto_connect=(bool)lint;
}
else if (lua_isstring(L, 3)&& !(lua_isnumber(L, 3)))
{
lua_pushnil(L);
lua_insert(L, 3);
}
else
{
if(lua_isnil(L, 3))
return luaL_error( L, "wrong arg type" );
auto_connect=1;
}
if(lua_isnumber(L, 4))
{
sta_conf.bssid_set = 0;
memset(sta_conf.bssid, 0, sizeof(sta_conf.bssid));
}
else
{
if (lua_isstring(L, 4))
{
const char *macaddr = luaL_checklstring( L, 4, &ml );
luaL_argcheck(L, ml==sizeof("AA:BB:CC:DD:EE:FF")-1, 1, INVALID_MAC_STR);
memset(sta_conf.bssid, 0, sizeof(sta_conf.bssid));
ets_str2macaddr(sta_conf.bssid, macaddr);
sta_conf.bssid_set = 1;
}
else
{
sta_conf.bssid_set = 0;
memset(sta_conf.bssid, 0, sizeof(sta_conf.bssid));
}
}
} }
c_memset(sta_conf.ssid, 0, 32); #if defined(WIFI_DEBUG)
c_memset(sta_conf.password, 0, 64); char debug_temp[sizeof(sta_conf.password)+1]; //max password length + '\0'
c_memcpy(sta_conf.ssid, ssid, sl);
c_memcpy(sta_conf.password, password, pl);
NODE_DBG(sta_conf.ssid);
NODE_DBG(" %d\n", sl);
NODE_DBG(sta_conf.password);
NODE_DBG(" %d\n", pl);
NODE_DBG(" %d\n", sta_conf.bssid_set);
NODE_DBG( MACSTR, MAC2STR(sta_conf.bssid));
NODE_DBG("\n");
memset(debug_temp, 0, sizeof(debug_temp));
memcpy(debug_temp, sta_conf.ssid, sizeof(sta_conf.ssid));
WIFI_DBG("\n\tsta_conf.ssid=\"%s\" len=%d\n", debug_temp, sl);
memset(debug_temp, 0, sizeof(debug_temp));
memcpy(debug_temp, sta_conf.password, sizeof(sta_conf.password));
WIFI_DBG("\tsta_conf.password=\"%s\" len=%d\n", debug_temp, pl);
WIFI_DBG("\tsta_conf.bssid=\""MACSTR"\"\tbssid_set=%d\n", MAC2STR(sta_conf.bssid), sta_conf.bssid_set);
WIFI_DBG("\tsave_to_flash=%s\n", save_to_flash ? "true":"false");
#endif
wifi_station_disconnect(); wifi_station_disconnect();
wifi_station_set_config(&sta_conf);
if(auto_connect==0) bool config_success;
{ if(save_to_flash) config_success = wifi_station_set_config(&sta_conf);
wifi_station_set_auto_connect(false); else config_success = wifi_station_set_config_current(&sta_conf);
} wifi_station_set_auto_connect((uint8)auto_connect);
else if(auto_connect) wifi_station_connect();
{
wifi_station_set_auto_connect(true); lua_pushboolean(L, config_success);
wifi_station_connect(); return 1;
}
// station_check_connect(0);
return 0;
} }
// Lua: wifi.sta.connect() // Lua: wifi.sta.connect()
...@@ -730,45 +833,10 @@ static int wifi_station_setauto( lua_State* L ) ...@@ -730,45 +833,10 @@ static int wifi_station_setauto( lua_State* L )
a = luaL_checkinteger( L, 1 ); a = luaL_checkinteger( L, 1 );
luaL_argcheck(L, ( a == 0 || a == 1 ), 1, "0 or 1"); luaL_argcheck(L, ( a == 0 || a == 1 ), 1, "0 or 1");
wifi_station_set_auto_connect(a); wifi_station_set_auto_connect(a);
return 0; return 0;
} }
/** // Lua: wifi.sta.listap()
* wifi.sta.listap()
* Description:
* scan and get ap list as a lua table into callback function.
* Syntax:
* wifi.sta.getap(function(table))
* wifi.sta.getap(format, function(table))
* wifi.sta.getap(cfg, function(table))
* wifi.sta.getap(cfg, format, function(table))
* Parameters:
* cfg: table that contains scan configuration
* Format:Select output table format.
* 0 for the old format (SSID : Authmode, RSSI, BSSID, Channel) (Default)
* 1 for the new format (BSSID : SSID, RSSI, Authmode, Channel)
* function(table): a callback function to receive ap table when scan is done
this function receive a table, the key is the ssid,
value is other info in format: authmode,rssi,bssid,channel
* Returns:
* nil
*
* Example:
--original function left intact to preserve backward compatibility
wifi.sta.getap(function(T) for k,v in pairs(T) do print(k..":"..v) end end)
--if no scan configuration is desired cfg can be set to nil or previous example can be used
wifi.sta.getap(nil, function(T) for k,v in pairs(T) do print(k..":"..v) end end)
--scan configuration
scan_cfg={}
scan_cfg.ssid="myssid" --if set to nil, ssid is not filtered
scan_cfg.bssid="AA:AA:AA:AA:AA:AA" --if set to nil, MAC address is not filtered
scan_cfg.channel=0 --if set to nil, channel will default to 0(scans all channels), if set scan will be faster
scan_cfg.show_hidden=1 --if set to nil, show_hidden will default to 0
wifi.sta.getap(scan_cfg, function(T) for k,v in pairs(T) do print(k..":"..v) end end)
*/
static int wifi_station_listap( lua_State* L ) static int wifi_station_listap( lua_State* L )
{ {
if(wifi_get_opmode() == SOFTAP_MODE) if(wifi_get_opmode() == SOFTAP_MODE)
...@@ -915,6 +983,7 @@ static int wifi_station_listap( lua_State* L ) ...@@ -915,6 +983,7 @@ static int wifi_station_listap( lua_State* L )
{ {
unregister_lua_cb(L, &wifi_scan_succeed); unregister_lua_cb(L, &wifi_scan_succeed);
} }
return 0;
} }
// Lua: wifi.sta.gethostname() // Lua: wifi.sta.gethostname()
...@@ -925,6 +994,7 @@ static int wifi_sta_gethostname( lua_State* L ) ...@@ -925,6 +994,7 @@ static int wifi_sta_gethostname( lua_State* L )
return 1; return 1;
} }
// Used by wifi_sta_sethostname_lua and wifi_change_default_hostname
static bool wifi_sta_sethostname(const char *hostname, size_t len) static bool wifi_sta_sethostname(const char *hostname, size_t len)
{ {
//this function follows RFC 952 & RFC 1123 host name standards. //this function follows RFC 952 & RFC 1123 host name standards.
...@@ -945,6 +1015,7 @@ static bool wifi_sta_sethostname(const char *hostname, size_t len) ...@@ -945,6 +1015,7 @@ static bool wifi_sta_sethostname(const char *hostname, size_t len)
return wifi_station_set_hostname((char*)hostname); return wifi_station_set_hostname((char*)hostname);
} }
// Lua: wifi.sta.sethostname()
static int wifi_sta_sethostname_lua( lua_State* L ) static int wifi_sta_sethostname_lua( lua_State* L )
{ {
size_t len; size_t len;
...@@ -953,6 +1024,25 @@ static int wifi_sta_sethostname_lua( lua_State* L ) ...@@ -953,6 +1024,25 @@ static int wifi_sta_sethostname_lua( lua_State* L )
return 0; return 0;
} }
// Lua: wifi.sta.sleeptype(type)
static int wifi_station_sleeptype( lua_State* L )
{
unsigned type;
if ( lua_isnumber(L, 1) ){
type = lua_tointeger(L, 1);
luaL_argcheck(L, (type == NONE_SLEEP_T || type == LIGHT_SLEEP_T || type == MODEM_SLEEP_T), 1, "range:0-2");
if(!wifi_set_sleep_type(type)){
lua_pushnil(L);
return 1;
}
}
type = wifi_get_sleep_type();
lua_pushinteger( L, type );
return 1;
}
// Lua: wifi.sta.status() // Lua: wifi.sta.status()
static int wifi_station_status( lua_State* L ) static int wifi_station_status( lua_State* L )
{ {
...@@ -1021,140 +1111,241 @@ static int wifi_ap_getbroadcast( lua_State* L ){ ...@@ -1021,140 +1111,241 @@ static int wifi_ap_getbroadcast( lua_State* L ){
} }
// Lua: wifi.ap.getconfig() // Lua: wifi.ap.getconfig()
static int wifi_ap_getconfig( lua_State* L ) static int wifi_ap_getconfig( lua_State* L, bool get_flash_cfg)
{ {
struct softap_config config; struct softap_config config;
wifi_softap_get_config(&config); char temp[sizeof(config.password)+1]; //max password length + '\0'
lua_pushstring( L, config.ssid ); if (get_flash_cfg) wifi_softap_get_config_default(&config);
if(config.authmode == AUTH_OPEN) else wifi_softap_get_config(&config);
lua_pushnil(L); if(lua_isboolean(L, 1) && lua_toboolean(L, 1)==true)
{
lua_newtable(L);
memset(temp, 0, sizeof(temp));
memcpy(temp, config.ssid, sizeof(config.ssid));
lua_pushstring(L, temp);
lua_setfield(L, -2, "ssid");
if(config.authmode!=AUTH_OPEN)
{
memset(temp, 0, sizeof(temp));
memcpy(temp, config.password, sizeof(config.password));
lua_pushstring(L, temp);
lua_setfield(L, -2, "pwd");
}
lua_pushnumber(L, config.authmode);
lua_setfield(L, -2, "auth");
lua_pushnumber(L, config.channel);
lua_setfield(L, -2, "channel");
lua_pushboolean(L, (bool)config.ssid_hidden);
lua_setfield(L, -2, "hidden");
lua_pushnumber(L, config.max_connection);
lua_setfield(L, -2, "max");
lua_pushnumber(L, config.beacon_interval);
lua_setfield(L, -2, "beacon");
return 1;
}
else else
lua_pushstring( L, config.password ); {
memset(temp, 0, sizeof(temp));
memcpy(temp, config.ssid, sizeof(config.ssid));
lua_pushstring(L, temp);
if(config.authmode == AUTH_OPEN) lua_pushnil(L);
else
{
memset(temp, 0, sizeof(temp));
memcpy(temp, config.password, sizeof(config.password));
lua_pushstring(L, temp);
}
return 2; return 2;
}
}
// Lua: wifi.sta.getconfig()
static int wifi_ap_getconfig_current(lua_State *L)
{
return wifi_ap_getconfig(L, false);
}
// Lua: wifi.sta.getdefaultconfig()
static int wifi_ap_getconfig_default(lua_State *L)
{
return wifi_ap_getconfig(L, true);
} }
// Lua: wifi.ap.config(table) // Lua: wifi.ap.config(table)
static int wifi_ap_config( lua_State* L ) static int wifi_ap_config( lua_State* L )
{ {
if (!lua_istable(L, 1)) if (!lua_istable(L, 1))
return luaL_error( L, "wrong arg type" ); return luaL_typerror(L, 1, lua_typename(L, LUA_TTABLE));
struct softap_config config; struct softap_config config;
wifi_softap_get_config(&config); bool save_to_flash=true;
size_t sl = 0 , pl = 0;
lua_Integer lint=0;
int Ltype_tmp=LUA_TNONE;
size_t len; memset(config.ssid, 0, sizeof(config.ssid));
memset(config.password, 0, sizeof(config.password));
lua_getfield(L, 1, "ssid"); lua_getfield(L, 1, "ssid");
if (!lua_isnil(L, -1)){ /* found? */ if (!lua_isnil(L, -1)){ /* found? */
if( lua_isstring(L, -1) ) // deal with the ssid string if( lua_isstring(L, -1) ) // deal with the ssid string
{ {
const char *ssid = luaL_checklstring( L, -1, &len ); const char *ssid = luaL_checklstring( L, -1, &sl );
if(len<1 || len>32 || ssid == NULL) luaL_argcheck(L, ((sl>=1 && sl<=sizeof(config.ssid)) ), 1, "ssid: length:1-32");
return luaL_error( L, "ssid:1~32" ); memcpy(config.ssid, ssid, sl);
c_memset(config.ssid, 0, 32); config.ssid_len = sl;
c_memcpy(config.ssid, ssid, len);
NODE_DBG(config.ssid);
NODE_DBG("\n");
config.ssid_len = len;
config.ssid_hidden = 0; config.ssid_hidden = 0;
} }
else else return luaL_argerror( L, 1, "ssid: not string" );
return luaL_error( L, "wrong arg type" );
} }
else else return luaL_argerror( L, 1, "ssid: required" );
return luaL_error( L, "ssid required" ); lua_pop(L, 1);
lua_getfield(L, 1, "pwd"); lua_getfield(L, 1, "pwd");
if (!lua_isnil(L, -1)){ /* found? */ if (!lua_isnil(L, -1)){ /* found? */
if( lua_isstring(L, -1) ) // deal with the password string if( lua_isstring(L, -1) ) // deal with the password string
{ {
const char *pwd = luaL_checklstring( L, -1, &len ); const char *pwd = luaL_checklstring( L, -1, &pl );
if(len<8 || len>64 || pwd == NULL) luaL_argcheck(L, (pl>=8 && pl<=sizeof(config.password)), 1, "pwd: length:0 or 8-64");
return luaL_error( L, "pwd:8~64" ); memcpy(config.password, pwd, pl);
c_memset(config.password, 0, 64);
c_memcpy(config.password, pwd, len);
NODE_DBG(config.password);
NODE_DBG("\n");
config.authmode = AUTH_WPA_WPA2_PSK; config.authmode = AUTH_WPA_WPA2_PSK;
} }
else else
return luaL_error( L, "wrong arg type" ); return luaL_argerror( L, 1, "pwd: not string" );
} }
else{ else{
config.authmode = AUTH_OPEN; config.authmode = AUTH_OPEN;
} }
lua_pop(L, 1);
lua_getfield(L, 1, "auth"); lua_getfield(L, 1, "auth");
if (!lua_isnil(L, -1)) if (!lua_isnil(L, -1))
{ {
config.authmode = (uint8_t)luaL_checkinteger(L, -1); if(lua_isnumber(L, -1))
NODE_DBG("%d\n", config.authmode); {
} lint=luaL_checkinteger(L, -1);
else luaL_argcheck(L, (lint >= 0 && lint < AUTH_MAX), 1, "auth: Range:0-4");
{ config.authmode = (uint8_t)luaL_checkinteger(L, -1);
// keep whatever value resulted from "pwd" logic above }
else return luaL_argerror(L, 1, "auth: not number");
} }
lua_pop(L, 1);
lua_getfield(L, 1, "channel"); lua_getfield(L, 1, "channel");
if (!lua_isnil(L, -1)) if (!lua_isnil(L, -1))
{ {
unsigned channel = luaL_checkinteger(L, -1); if(lua_isnumber(L, -1))
if (channel < 1 || channel > 13) {
return luaL_error( L, "channel:1~13" ); lint=luaL_checkinteger(L, -1);
luaL_argcheck(L, (lint >= 1 && lint <= 13), 1, "channel: Range:1-13");
config.channel = (uint8_t)lint;
}
else luaL_argerror(L, 1, "channel: not number");
config.channel = (uint8_t)channel;
NODE_DBG("%d\n", config.channel);
} }
else else
{ {
config.channel = 6; config.channel = 6;
} }
lua_pop(L, 1);
lua_getfield(L, 1, "hidden"); lua_getfield(L, 1, "hidden");
if (!lua_isnil(L, -1)) if (!lua_isnil(L, -1))
{ {
config.ssid_hidden = (uint8_t)luaL_checkinteger(L, -1); Ltype_tmp=lua_type(L, -1);
NODE_DBG("%d\n", config.ssid_hidden); if(Ltype_tmp==LUA_TNUMBER||Ltype_tmp==LUA_TBOOLEAN)
NODE_DBG("\n"); {
if(Ltype_tmp==LUA_TNUMBER)lint=luaL_checkinteger(L, -1);
if(Ltype_tmp==LUA_TBOOLEAN)lint=(lua_Number)lua_toboolean(L, -1);
luaL_argcheck(L, (lint == 0 || lint==1), 1, "hidden: 0 or 1");
config.ssid_hidden = (uint8_t)lint;
}
else return luaL_argerror(L, 1, "hidden: not boolean");
} }
else else
{ {
config.ssid_hidden = 0; config.ssid_hidden = 0;
} }
lua_pop(L, 1);
lua_getfield(L, 1, "max"); lua_getfield(L, 1, "max");
if (!lua_isnil(L, -1)) if (!lua_isnil(L, -1))
{ {
unsigned max = luaL_checkinteger(L, -1); if(lua_isnumber(L, -1))
if (max < 1 || max > 4) {
return luaL_error( L, "max:1~4" ); lint=luaL_checkinteger(L, -1);
luaL_argcheck(L, (lint >= 1 && lint <= 4), 1, "max: 1-4");
config.max_connection = (uint8_t)max; config.max_connection = (uint8_t)lint;
NODE_DBG("%d\n", config.max_connection); }
else return luaL_argerror(L, 1, "max: not number");
} }
else else
{ {
config.max_connection = 4; config.max_connection = 4;
} }
lua_pop(L, 1);
lua_getfield(L, 1, "beacon"); lua_getfield(L, 1, "beacon");
if (!lua_isnil(L, -1)) if (!lua_isnil(L, -1))
{ {
unsigned beacon = luaL_checkinteger(L, -1); if(lua_isnumber(L, -1))
if (beacon < 100 || beacon > 60000) {
return luaL_error( L, "beacon:100~60000" ); lint=luaL_checkinteger(L, -1);
luaL_argcheck(L, (lint >= 100 && lint <= 60000), 1, "beacon: 100-60000");
config.beacon_interval = (uint16_t)beacon; config.beacon_interval = (uint16_t)lint;
NODE_DBG("%d\n", config.beacon_interval); }
else return luaL_argerror(L, 1, "beacon: not number");
} }
else else
{ {
config.beacon_interval = 100; config.beacon_interval = 100;
} }
lua_pop(L, 1);
wifi_softap_set_config(&config);
// system_restart(); lua_getfield(L, 1, "save");
return 0; if (!lua_isnil(L, -1))
{
if (lua_isboolean(L, -1))
{
save_to_flash=lua_toboolean(L, -1);
}
else return luaL_argerror(L, 1, "save: not boolean");
}
lua_pop(L, 1);
#if defined(WIFI_DEBUG)
char debug_temp[sizeof(config.password)+1];
memset(debug_temp, 0, sizeof(debug_temp));
memcpy(debug_temp, config.ssid, sizeof(config.ssid));
WIFI_DBG("\n\tconfig.ssid=\"%s\" len=%d\n", debug_temp, sl);
memset(debug_temp, 0, sizeof(debug_temp));
memcpy(debug_temp, config.password, sizeof(config.password));
WIFI_DBG("\tconfig.password=\"%s\" len=%d\n", debug_temp, pl);
WIFI_DBG("\tconfig.authmode=%d\n", config.authmode);
WIFI_DBG("\tconfig.channel=%d\n", config.channel);
WIFI_DBG("\tconfig.ssid_hidden=%d\n", config.ssid_hidden);
WIFI_DBG("\tconfig.max_connection=%d\n", config.max_connection);
WIFI_DBG("\tconfig.beacon_interval=%d\n", config.beacon_interval);
WIFI_DBG("\tsave_to_flash=%s\n", save_to_flash ? "true":"false");
#endif
bool config_success;
if(save_to_flash) config_success = wifi_softap_set_config(&config);
else config_success = wifi_softap_set_config_current(&config);
lua_pushboolean(L, config_success);
return 1;
} }
// Lua: table = wifi.ap.getclient() // Lua: table = wifi.ap.getclient()
...@@ -1183,6 +1374,7 @@ static int wifi_ap_listclient( lua_State* L ) ...@@ -1183,6 +1374,7 @@ static int wifi_ap_listclient( lua_State* L )
return 1; return 1;
} }
// Lua: ip = wifi.ap.dhcp.config() // Lua: ip = wifi.ap.dhcp.config()
static int wifi_ap_dhcp_config( lua_State* L ) static int wifi_ap_dhcp_config( lua_State* L )
{ {
...@@ -1220,6 +1412,7 @@ static int wifi_ap_dhcp_config( lua_State* L ) ...@@ -1220,6 +1412,7 @@ static int wifi_ap_dhcp_config( lua_State* L )
return 2; return 2;
} }
// Lua: wifi.ap.dhcp.start() // Lua: wifi.ap.dhcp.start()
static int wifi_ap_dhcp_start( lua_State* L ) static int wifi_ap_dhcp_start( lua_State* L )
{ {
...@@ -1227,6 +1420,7 @@ static int wifi_ap_dhcp_start( lua_State* L ) ...@@ -1227,6 +1420,7 @@ static int wifi_ap_dhcp_start( lua_State* L )
return 1; return 1;
} }
// Lua: wifi.ap.dhcp.stop() // Lua: wifi.ap.dhcp.stop()
static int wifi_ap_dhcp_stop( lua_State* L ) static int wifi_ap_dhcp_stop( lua_State* L )
{ {
...@@ -1234,28 +1428,35 @@ static int wifi_ap_dhcp_stop( lua_State* L ) ...@@ -1234,28 +1428,35 @@ static int wifi_ap_dhcp_stop( lua_State* L )
return 1; return 1;
} }
// Module function map // Module function map
static const LUA_REG_TYPE wifi_station_map[] = { static const LUA_REG_TYPE wifi_station_map[] = {
{ LSTRKEY( "getconfig" ), LFUNCVAL( wifi_station_getconfig ) }, { LSTRKEY( "autoconnect" ), LFUNCVAL( wifi_station_setauto ) },
{ LSTRKEY( "config" ), LFUNCVAL( wifi_station_config ) }, { LSTRKEY( "changeap" ), LFUNCVAL( wifi_station_change_ap ) },
{ LSTRKEY( "connect" ), LFUNCVAL( wifi_station_connect4lua ) }, { LSTRKEY( "config" ), LFUNCVAL( wifi_station_config ) },
{ LSTRKEY( "disconnect" ), LFUNCVAL( wifi_station_disconnect4lua ) }, { LSTRKEY( "connect" ), LFUNCVAL( wifi_station_connect4lua ) },
{ LSTRKEY( "autoconnect" ), LFUNCVAL( wifi_station_setauto ) }, { LSTRKEY( "disconnect" ), LFUNCVAL( wifi_station_disconnect4lua ) },
{ LSTRKEY( "getip" ), LFUNCVAL( wifi_station_getip ) },
{ LSTRKEY( "setip" ), LFUNCVAL( wifi_station_setip ) },
{ LSTRKEY( "getbroadcast" ), LFUNCVAL( wifi_station_getbroadcast) },
{ LSTRKEY( "getmac" ), LFUNCVAL( wifi_station_getmac ) },
{ LSTRKEY( "setmac" ), LFUNCVAL( wifi_station_setmac ) },
{ LSTRKEY( "getap" ), LFUNCVAL( wifi_station_listap ) },
{ LSTRKEY( "sethostname" ), LFUNCVAL( wifi_sta_sethostname_lua ) },
{ LSTRKEY( "gethostname" ), LFUNCVAL( wifi_sta_gethostname ) },
{ LSTRKEY( "getrssi" ), LFUNCVAL( wifi_station_getrssi ) },
{ LSTRKEY( "status" ), LFUNCVAL( wifi_station_status ) },
#if defined(WIFI_STATION_STATUS_MONITOR_ENABLE) #if defined(WIFI_STATION_STATUS_MONITOR_ENABLE)
{ LSTRKEY( "eventMonReg" ), LFUNCVAL( wifi_station_event_mon_reg ) }, //declared in wifi_eventmon.c { LSTRKEY( "eventMonReg" ), LFUNCVAL( wifi_station_event_mon_reg ) }, //defined in wifi_eventmon.c
{ LSTRKEY( "eventMonStart" ), LFUNCVAL( wifi_station_event_mon_start ) }, //declared in wifi_eventmon.c { LSTRKEY( "eventMonStart" ), LFUNCVAL( wifi_station_event_mon_start ) }, //defined in wifi_eventmon.c
{ LSTRKEY( "eventMonStop" ), LFUNCVAL( wifi_station_event_mon_stop ) }, //declared in wifi_eventmon.c { LSTRKEY( "eventMonStop" ), LFUNCVAL( wifi_station_event_mon_stop ) }, //defined in wifi_eventmon.c
#endif #endif
{ LSTRKEY( "getap" ), LFUNCVAL( wifi_station_listap ) },
{ LSTRKEY( "getapindex" ), LFUNCVAL( wifi_station_get_ap_index ) },
{ LSTRKEY( "getapinfo" ), LFUNCVAL( wifi_station_get_ap_info4lua ) },
{ LSTRKEY( "getbroadcast" ), LFUNCVAL( wifi_station_getbroadcast) },
{ LSTRKEY( "getconfig" ), LFUNCVAL( wifi_station_getconfig_current ) },
{ LSTRKEY( "getdefaultconfig" ), LFUNCVAL( wifi_station_getconfig_default ) },
{ LSTRKEY( "gethostname" ), LFUNCVAL( wifi_sta_gethostname ) },
{ LSTRKEY( "getip" ), LFUNCVAL( wifi_station_getip ) },
{ LSTRKEY( "getmac" ), LFUNCVAL( wifi_station_getmac ) },
{ LSTRKEY( "getrssi" ), LFUNCVAL( wifi_station_getrssi ) },
{ LSTRKEY( "setaplimit" ), LFUNCVAL( wifi_station_ap_number_set4lua ) },
{ LSTRKEY( "sethostname" ), LFUNCVAL( wifi_sta_sethostname_lua ) },
{ LSTRKEY( "setip" ), LFUNCVAL( wifi_station_setip ) },
{ LSTRKEY( "setmac" ), LFUNCVAL( wifi_station_setmac ) },
{ LSTRKEY( "sleeptype" ), LFUNCVAL( wifi_station_sleeptype ) },
{ LSTRKEY( "status" ), LFUNCVAL( wifi_station_status ) },
{ LNILKEY, LNILVAL } { LNILKEY, LNILVAL }
}; };
...@@ -1267,23 +1468,25 @@ static const LUA_REG_TYPE wifi_ap_dhcp_map[] = { ...@@ -1267,23 +1468,25 @@ static const LUA_REG_TYPE wifi_ap_dhcp_map[] = {
}; };
static const LUA_REG_TYPE wifi_ap_map[] = { static const LUA_REG_TYPE wifi_ap_map[] = {
{ LSTRKEY( "config" ), LFUNCVAL( wifi_ap_config ) }, { LSTRKEY( "config" ), LFUNCVAL( wifi_ap_config ) },
{ LSTRKEY( "deauth" ), LFUNCVAL( wifi_ap_deauth ) }, { LSTRKEY( "deauth" ), LFUNCVAL( wifi_ap_deauth ) },
{ LSTRKEY( "getip" ), LFUNCVAL( wifi_ap_getip ) }, { LSTRKEY( "getip" ), LFUNCVAL( wifi_ap_getip ) },
{ LSTRKEY( "setip" ), LFUNCVAL( wifi_ap_setip ) }, { LSTRKEY( "setip" ), LFUNCVAL( wifi_ap_setip ) },
{ LSTRKEY( "getbroadcast" ), LFUNCVAL( wifi_ap_getbroadcast) }, { LSTRKEY( "getbroadcast" ), LFUNCVAL( wifi_ap_getbroadcast) },
{ LSTRKEY( "getmac" ), LFUNCVAL( wifi_ap_getmac ) }, { LSTRKEY( "getmac" ), LFUNCVAL( wifi_ap_getmac ) },
{ LSTRKEY( "setmac" ), LFUNCVAL( wifi_ap_setmac ) }, { LSTRKEY( "setmac" ), LFUNCVAL( wifi_ap_setmac ) },
{ LSTRKEY( "getclient" ), LFUNCVAL( wifi_ap_listclient ) }, { LSTRKEY( "getclient" ), LFUNCVAL( wifi_ap_listclient ) },
{ LSTRKEY( "getconfig" ), LFUNCVAL( wifi_ap_getconfig ) }, { LSTRKEY( "getconfig" ), LFUNCVAL( wifi_ap_getconfig_current ) },
{ LSTRKEY( "dhcp" ), LROVAL( wifi_ap_dhcp_map ) }, { LSTRKEY( "getdefaultconfig" ), LFUNCVAL( wifi_ap_getconfig_default ) },
//{ LSTRKEY( "__metatable" ), LROVAL( wifi_ap_map ) }, { LSTRKEY( "dhcp" ), LROVAL( wifi_ap_dhcp_map ) },
//{ LSTRKEY( "__metatable" ), LROVAL( wifi_ap_map ) },
{ LNILKEY, LNILVAL } { LNILKEY, LNILVAL }
}; };
static const LUA_REG_TYPE wifi_map[] = { static const LUA_REG_TYPE wifi_map[] = {
{ LSTRKEY( "setmode" ), LFUNCVAL( wifi_setmode ) }, { LSTRKEY( "setmode" ), LFUNCVAL( wifi_setmode ) },
{ LSTRKEY( "getmode" ), LFUNCVAL( wifi_getmode ) }, { LSTRKEY( "getmode" ), LFUNCVAL( wifi_getmode ) },
{ LSTRKEY( "getdefaultmode" ), LFUNCVAL( wifi_getdefaultmode ) },
{ LSTRKEY( "getchannel" ), LFUNCVAL( wifi_getchannel ) }, { LSTRKEY( "getchannel" ), LFUNCVAL( wifi_getchannel ) },
{ LSTRKEY( "setphymode" ), LFUNCVAL( wifi_setphymode ) }, { LSTRKEY( "setphymode" ), LFUNCVAL( wifi_setphymode ) },
{ LSTRKEY( "getphymode" ), LFUNCVAL( wifi_getphymode ) }, { LSTRKEY( "getphymode" ), LFUNCVAL( wifi_getphymode ) },
...@@ -1293,7 +1496,7 @@ static const LUA_REG_TYPE wifi_map[] = { ...@@ -1293,7 +1496,7 @@ static const LUA_REG_TYPE wifi_map[] = {
{ LSTRKEY( "startsmart" ), LFUNCVAL( wifi_start_smart ) }, { LSTRKEY( "startsmart" ), LFUNCVAL( wifi_start_smart ) },
{ LSTRKEY( "stopsmart" ), LFUNCVAL( wifi_exit_smart ) }, { LSTRKEY( "stopsmart" ), LFUNCVAL( wifi_exit_smart ) },
#endif #endif
{ LSTRKEY( "sleeptype" ), LFUNCVAL( wifi_sleeptype ) }, { LSTRKEY( "sleeptype" ), LFUNCVAL( wifi_station_sleeptype ) },
{ LSTRKEY( "sta" ), LROVAL( wifi_station_map ) }, { LSTRKEY( "sta" ), LROVAL( wifi_station_map ) },
{ LSTRKEY( "ap" ), LROVAL( wifi_ap_map ) }, { LSTRKEY( "ap" ), LROVAL( wifi_ap_map ) },
...@@ -1330,6 +1533,7 @@ static const LUA_REG_TYPE wifi_map[] = { ...@@ -1330,6 +1533,7 @@ static const LUA_REG_TYPE wifi_map[] = {
{ LNILKEY, LNILVAL } { LNILKEY, LNILVAL }
}; };
// Used by user_rf_pre_init(user_main.c)
void wifi_change_default_host_name(void) void wifi_change_default_host_name(void)
{ {
uint8 opmode_temp=wifi_get_opmode(); uint8 opmode_temp=wifi_get_opmode();
......
...@@ -13,6 +13,9 @@ ...@@ -13,6 +13,9 @@
#include "c_stdio.h" #include "c_stdio.h"
#include "task/task.h" #include "task/task.h"
//#define WIFI_DEBUG
//#define EVENT_DEBUG
void wifi_add_sprintf_field(lua_State* L, char* name, char* string, ...); void wifi_add_sprintf_field(lua_State* L, char* name, char* string, ...);
void wifi_add_int_field(lua_State* L, char* name, lua_Integer integer); void wifi_add_int_field(lua_State* L, char* name, lua_Integer integer);
...@@ -37,7 +40,13 @@ static inline void unregister_lua_cb(lua_State* L, int* cb_ref) ...@@ -37,7 +40,13 @@ static inline void unregister_lua_cb(lua_State* L, int* cb_ref)
void wifi_change_default_host_name(void); void wifi_change_default_host_name(void);
#ifdef NODE_DEBUG #if defined(WIFI_DEBUG) || defined(NODE_DEBUG)
#define WIFI_DBG(...) c_printf(__VA_ARGS__)
#else
#define WIFI_DBG(...) //c_printf(__VA_ARGS__)
#endif
#if defined(EVENT_DEBUG) || defined(NODE_DEBUG)
#define EVENT_DBG(...) c_printf(__VA_ARGS__) #define EVENT_DBG(...) c_printf(__VA_ARGS__)
#else #else
#define EVENT_DBG(...) //c_printf(__VA_ARGS__) #define EVENT_DBG(...) //c_printf(__VA_ARGS__)
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
typedef struct { typedef struct {
int canary;
int size; int size;
uint8_t colorsPerLed; uint8_t colorsPerLed;
uint8_t values[0]; uint8_t values[0];
...@@ -132,8 +131,7 @@ static int ws2812_write(lua_State* L) { ...@@ -132,8 +131,7 @@ static int ws2812_write(lua_State* L) {
} }
else if (type == LUA_TUSERDATA) else if (type == LUA_TUSERDATA)
{ {
ws2812_buffer * buffer = (ws2812_buffer*)lua_touserdata(L, 1); ws2812_buffer * buffer = (ws2812_buffer*)luaL_checkudata(L, 1, "ws2812.buffer");
luaL_argcheck(L, buffer && buffer->canary == CANARY_VALUE, 1, "ws2812.buffer expected");
buffer1 = buffer->values; buffer1 = buffer->values;
length1 = buffer->colorsPerLed*buffer->size; length1 = buffer->colorsPerLed*buffer->size;
...@@ -156,8 +154,7 @@ static int ws2812_write(lua_State* L) { ...@@ -156,8 +154,7 @@ static int ws2812_write(lua_State* L) {
} }
else if (type == LUA_TUSERDATA) else if (type == LUA_TUSERDATA)
{ {
ws2812_buffer * buffer = (ws2812_buffer*)lua_touserdata(L, 2); ws2812_buffer * buffer = (ws2812_buffer*)luaL_checkudata(L, 2, "ws2812.buffer");
luaL_argcheck(L, buffer && buffer->canary == CANARY_VALUE, 2, "ws2812.buffer expected");
buffer2 = buffer->values; buffer2 = buffer->values;
length2 = buffer->colorsPerLed*buffer->size; length2 = buffer->colorsPerLed*buffer->size;
...@@ -173,14 +170,13 @@ static int ws2812_write(lua_State* L) { ...@@ -173,14 +170,13 @@ static int ws2812_write(lua_State* L) {
return 0; return 0;
} }
// Handle a buffer where we can store led values static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) {
static int ws2812_new_buffer(lua_State *L) { /* relative string position: negative means back from end */
const int leds = luaL_checkint(L, 1); if (pos < 0) pos += (ptrdiff_t)len + 1;
const int colorsPerLed = luaL_checkint(L, 2); return (pos >= 0) ? pos : 0;
}
luaL_argcheck(L, leds > 0, 1, "should be a positive integer");
luaL_argcheck(L, colorsPerLed > 0, 2, "should be a positive integer");
static ws2812_buffer *allocate_buffer(lua_State *L, int leds, int colorsPerLed) {
// Allocate memory // Allocate memory
size_t size = sizeof(ws2812_buffer) + colorsPerLed*leds*sizeof(uint8_t); size_t size = sizeof(ws2812_buffer) + colorsPerLed*leds*sizeof(uint8_t);
ws2812_buffer * buffer = (ws2812_buffer*)lua_newuserdata(L, size); ws2812_buffer * buffer = (ws2812_buffer*)lua_newuserdata(L, size);
...@@ -193,16 +189,26 @@ static int ws2812_new_buffer(lua_State *L) { ...@@ -193,16 +189,26 @@ static int ws2812_new_buffer(lua_State *L) {
buffer->size = leds; buffer->size = leds;
buffer->colorsPerLed = colorsPerLed; buffer->colorsPerLed = colorsPerLed;
// Store canary for future type checks return buffer;
buffer->canary = CANARY_VALUE; }
// Handle a buffer where we can store led values
static int ws2812_new_buffer(lua_State *L) {
const int leds = luaL_checkint(L, 1);
const int colorsPerLed = luaL_checkint(L, 2);
luaL_argcheck(L, leds > 0, 1, "should be a positive integer");
luaL_argcheck(L, colorsPerLed > 0, 2, "should be a positive integer");
ws2812_buffer * buffer = allocate_buffer(L, leds, colorsPerLed);
c_memset(buffer->values, 0, colorsPerLed * leds);
return 1; return 1;
} }
static int ws2812_buffer_fill(lua_State* L) { static int ws2812_buffer_fill(lua_State* L) {
ws2812_buffer * buffer = (ws2812_buffer*)lua_touserdata(L, 1); ws2812_buffer * buffer = (ws2812_buffer*)luaL_checkudata(L, 1, "ws2812.buffer");
luaL_argcheck(L, buffer && buffer->canary == CANARY_VALUE, 1, "ws2812.buffer expected");
// Grab colors // Grab colors
int i, j; int i, j;
...@@ -230,11 +236,10 @@ static int ws2812_buffer_fill(lua_State* L) { ...@@ -230,11 +236,10 @@ static int ws2812_buffer_fill(lua_State* L) {
} }
static int ws2812_buffer_fade(lua_State* L) { static int ws2812_buffer_fade(lua_State* L) {
ws2812_buffer * buffer = (ws2812_buffer*)lua_touserdata(L, 1); ws2812_buffer * buffer = (ws2812_buffer*)luaL_checkudata(L, 1, "ws2812.buffer");
const int fade = luaL_checkinteger(L, 2); const int fade = luaL_checkinteger(L, 2);
unsigned direction = luaL_optinteger( L, 3, FADE_OUT ); unsigned direction = luaL_optinteger( L, 3, FADE_OUT );
luaL_argcheck(L, buffer && buffer->canary == CANARY_VALUE, 1, "ws2812.buffer expected");
luaL_argcheck(L, fade > 0, 2, "fade value should be a strict positive number"); luaL_argcheck(L, fade > 0, 2, "fade value should be a strict positive number");
uint8_t * p = &buffer->values[0]; uint8_t * p = &buffer->values[0];
...@@ -260,17 +265,25 @@ static int ws2812_buffer_fade(lua_State* L) { ...@@ -260,17 +265,25 @@ static int ws2812_buffer_fade(lua_State* L) {
static int ws2812_buffer_shift(lua_State* L) { static int ws2812_buffer_shift(lua_State* L) {
ws2812_buffer * buffer = (ws2812_buffer*)lua_touserdata(L, 1); ws2812_buffer * buffer = (ws2812_buffer*)luaL_checkudata(L, 1, "ws2812.buffer");
const int shiftValue = luaL_checkinteger(L, 2); const int shiftValue = luaL_checkinteger(L, 2);
const unsigned shift_type = luaL_optinteger( L, 3, SHIFT_LOGICAL ); const unsigned shift_type = luaL_optinteger( L, 3, SHIFT_LOGICAL );
luaL_argcheck(L, buffer && buffer->canary == CANARY_VALUE, 1, "ws2812.buffer expected"); ptrdiff_t start = posrelat(luaL_optinteger(L, 4, 1), buffer->size);
luaL_argcheck(L, shiftValue > 0-buffer->size && shiftValue < buffer->size, 2, "shifting more elements than buffer size"); ptrdiff_t end = posrelat(luaL_optinteger(L, 5, -1), buffer->size);
if (start < 1) start = 1;
if (end > (ptrdiff_t)buffer->size) end = (ptrdiff_t)buffer->size;
start--;
int size = end - start;
size_t offset = start * buffer->colorsPerLed;
luaL_argcheck(L, shiftValue > 0-size && shiftValue < size, 2, "shifting more elements than buffer size");
int shift = shiftValue >= 0 ? shiftValue : -shiftValue; int shift = shiftValue >= 0 ? shiftValue : -shiftValue;
// check if we want to shift at all // check if we want to shift at all
if (shift == 0) if (shift == 0 || size <= 0)
{ {
return 0; return 0;
} }
...@@ -280,38 +293,38 @@ static int ws2812_buffer_shift(lua_State* L) { ...@@ -280,38 +293,38 @@ static int ws2812_buffer_shift(lua_State* L) {
size_t shift_len, remaining_len; size_t shift_len, remaining_len;
// calculate length of shift section and remaining section // calculate length of shift section and remaining section
shift_len = shift*buffer->colorsPerLed; shift_len = shift*buffer->colorsPerLed;
remaining_len = (buffer->size-shift)*buffer->colorsPerLed; remaining_len = (size-shift)*buffer->colorsPerLed;
if (shiftValue > 0) if (shiftValue > 0)
{ {
// Store the values which are moved out of the array (last n pixels) // Store the values which are moved out of the array (last n pixels)
c_memcpy(tmp_pixels, &buffer->values[(buffer->size-shift)*buffer->colorsPerLed], shift_len); c_memcpy(tmp_pixels, &buffer->values[offset + (size-shift)*buffer->colorsPerLed], shift_len);
// Move pixels to end // Move pixels to end
os_memmove(&buffer->values[shift*buffer->colorsPerLed], &buffer->values[0], remaining_len); os_memmove(&buffer->values[offset + shift*buffer->colorsPerLed], &buffer->values[offset], remaining_len);
// Fill beginning with temp data // Fill beginning with temp data
if (shift_type == SHIFT_LOGICAL) if (shift_type == SHIFT_LOGICAL)
{ {
c_memset(&buffer->values[0], 0, shift_len); c_memset(&buffer->values[offset], 0, shift_len);
} }
else else
{ {
c_memcpy(&buffer->values[0], tmp_pixels, shift_len); c_memcpy(&buffer->values[offset], tmp_pixels, shift_len);
} }
} }
else else
{ {
// Store the values which are moved out of the array (last n pixels) // Store the values which are moved out of the array (last n pixels)
c_memcpy(tmp_pixels, &buffer->values[0], shift_len); c_memcpy(tmp_pixels, &buffer->values[offset], shift_len);
// Move pixels to end // Move pixels to end
os_memmove(&buffer->values[0], &buffer->values[shift*buffer->colorsPerLed], remaining_len); os_memmove(&buffer->values[offset], &buffer->values[offset + shift*buffer->colorsPerLed], remaining_len);
// Fill beginning with temp data // Fill beginning with temp data
if (shift_type == SHIFT_LOGICAL) if (shift_type == SHIFT_LOGICAL)
{ {
c_memset(&buffer->values[(buffer->size-shift)*buffer->colorsPerLed], 0, shift_len); c_memset(&buffer->values[offset + (size-shift)*buffer->colorsPerLed], 0, shift_len);
} }
else else
{ {
c_memcpy(&buffer->values[(buffer->size-shift)*buffer->colorsPerLed], tmp_pixels, shift_len); c_memcpy(&buffer->values[offset + (size-shift)*buffer->colorsPerLed], tmp_pixels, shift_len);
} }
} }
// Free memory // Free memory
...@@ -320,13 +333,107 @@ static int ws2812_buffer_shift(lua_State* L) { ...@@ -320,13 +333,107 @@ static int ws2812_buffer_shift(lua_State* L) {
return 0; return 0;
} }
static int ws2812_buffer_dump(lua_State* L) {
ws2812_buffer * buffer = (ws2812_buffer*)luaL_checkudata(L, 1, "ws2812.buffer");
lua_pushlstring(L, buffer->values, buffer->size * buffer->colorsPerLed);
return 1;
}
static int ws2812_buffer_replace(lua_State* L) {
ws2812_buffer * buffer = (ws2812_buffer*)luaL_checkudata(L, 1, "ws2812.buffer");
size_t l = buffer->size;
ptrdiff_t start = posrelat(luaL_optinteger(L, 3, 1), l);
uint8_t *src;
size_t srcLen;
if (lua_type(L, 2) == LUA_TSTRING) {
size_t length;
src = (uint8_t *) lua_tolstring(L, 2, &length);
srcLen = length / buffer->colorsPerLed;
} else {
ws2812_buffer * rhs = (ws2812_buffer*)luaL_checkudata(L, 2, "ws2812.buffer");
src = rhs->values;
srcLen = rhs->size;
luaL_argcheck(L, rhs->colorsPerLed == buffer->colorsPerLed, 2, "Buffers have different colors");
}
luaL_argcheck(L, srcLen + start - 1 <= buffer->size, 2, "Does not fit into destination");
c_memcpy(buffer->values + (start - 1) * buffer->colorsPerLed, src, srcLen * buffer->colorsPerLed);
return 0;
}
// buffer:mix(factor1, buffer1, ..)
// factor is 256 for 100%
// uses saturating arithmetic (one buffer at a time)
static int ws2812_buffer_mix(lua_State* L) {
ws2812_buffer * buffer = (ws2812_buffer*)luaL_checkudata(L, 1, "ws2812.buffer");
int pos = 2;
size_t cells = buffer->size * buffer->colorsPerLed;
int n_sources = (lua_gettop(L) - 1) / 2;
struct {
int factor;
const uint8_t *values;
} source[n_sources];
int src;
for (src = 0; src < n_sources; src++, pos += 2) {
int factor = luaL_checkinteger(L, pos);
ws2812_buffer *src_buffer = (ws2812_buffer*) luaL_checkudata(L, pos + 1, "ws2812.buffer");
luaL_argcheck(L, src_buffer->size == buffer->size && src_buffer->colorsPerLed == buffer->colorsPerLed, pos + 1, "Buffer not same shape");
source[src].factor = factor;
source[src].values = src_buffer->values;
}
size_t i;
for (i = 0; i < cells; i++) {
int val = 0;
for (src = 0; src < n_sources; src++) {
val += ((int)(source[src].values[i] * source[src].factor) >> 8);
}
if (val < 0) {
val = 0;
} else if (val > 255) {
val = 255;
}
buffer->values[i] = val;
}
return 0;
}
// Returns the total of all channels
static int ws2812_buffer_power(lua_State* L) {
ws2812_buffer * buffer = (ws2812_buffer*)luaL_checkudata(L, 1, "ws2812.buffer");
size_t cells = buffer->size * buffer->colorsPerLed;
size_t i;
int total = 0;
for (i = 0; i < cells; i++) {
total += buffer->values[i];
}
lua_pushnumber(L, total);
return 1;
}
static int ws2812_buffer_get(lua_State* L) { static int ws2812_buffer_get(lua_State* L) {
ws2812_buffer * buffer = (ws2812_buffer*)lua_touserdata(L, 1); ws2812_buffer * buffer = (ws2812_buffer*)luaL_checkudata(L, 1, "ws2812.buffer");
const int led = luaL_checkinteger(L, 2) - 1; const int led = luaL_checkinteger(L, 2) - 1;
luaL_argcheck(L, buffer && buffer->canary == CANARY_VALUE, 1, "ws2812.buffer expected");
luaL_argcheck(L, led >= 0 && led < buffer->size, 2, "index out of range"); luaL_argcheck(L, led >= 0 && led < buffer->size, 2, "index out of range");
int i; int i;
...@@ -339,10 +446,9 @@ static int ws2812_buffer_get(lua_State* L) { ...@@ -339,10 +446,9 @@ static int ws2812_buffer_get(lua_State* L) {
} }
static int ws2812_buffer_set(lua_State* L) { static int ws2812_buffer_set(lua_State* L) {
ws2812_buffer * buffer = (ws2812_buffer*)lua_touserdata(L, 1); ws2812_buffer * buffer = (ws2812_buffer*)luaL_checkudata(L, 1, "ws2812.buffer");
const int led = luaL_checkinteger(L, 2) - 1; const int led = luaL_checkinteger(L, 2) - 1;
luaL_argcheck(L, buffer && buffer->canary == CANARY_VALUE, 1, "ws2812.buffer expected");
luaL_argcheck(L, led >= 0 && led < buffer->size, 2, "index out of range"); luaL_argcheck(L, led >= 0 && led < buffer->size, 2, "index out of range");
int type = lua_type(L, 3); int type = lua_type(L, 3);
...@@ -387,24 +493,94 @@ static int ws2812_buffer_set(lua_State* L) { ...@@ -387,24 +493,94 @@ static int ws2812_buffer_set(lua_State* L) {
} }
static int ws2812_buffer_size(lua_State* L) { static int ws2812_buffer_size(lua_State* L) {
ws2812_buffer * buffer = (ws2812_buffer*)lua_touserdata(L, 1); ws2812_buffer * buffer = (ws2812_buffer*)luaL_checkudata(L, 1, "ws2812.buffer");
luaL_argcheck(L, buffer && buffer->canary == CANARY_VALUE, 1, "ws2812.buffer expected");
lua_pushnumber(L, buffer->size); lua_pushnumber(L, buffer->size);
return 1; return 1;
} }
static int ws2812_buffer_sub(lua_State* L) {
ws2812_buffer * lhs = (ws2812_buffer*)luaL_checkudata(L, 1, "ws2812.buffer");
size_t l = lhs->size;
ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l);
ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l);
if (start < 1) start = 1;
if (end > (ptrdiff_t)l) end = (ptrdiff_t)l;
if (start <= end) {
ws2812_buffer *result = allocate_buffer(L, end - start + 1, lhs->colorsPerLed);
c_memcpy(result->values, lhs->values + lhs->colorsPerLed * (start - 1), lhs->colorsPerLed * (end - start + 1));
} else {
ws2812_buffer *result = allocate_buffer(L, 0, lhs->colorsPerLed);
}
return 1;
}
static int ws2812_buffer_concat(lua_State* L) {
ws2812_buffer * lhs = (ws2812_buffer*)luaL_checkudata(L, 1, "ws2812.buffer");
ws2812_buffer * rhs = (ws2812_buffer*)luaL_checkudata(L, 2, "ws2812.buffer");
luaL_argcheck(L, lhs->colorsPerLed == rhs->colorsPerLed, 1, "Can only concatenate buffers with same colors");
int colorsPerLed = lhs->colorsPerLed;
int leds = lhs->size + rhs->size;
ws2812_buffer * buffer = allocate_buffer(L, leds, colorsPerLed);
c_memcpy(buffer->values, lhs->values, lhs->colorsPerLed * lhs->size);
c_memcpy(buffer->values + lhs->colorsPerLed * lhs->size, rhs->values, rhs->colorsPerLed * rhs->size);
return 1;
}
static int ws2812_buffer_tostring(lua_State* L) {
ws2812_buffer * buffer = (ws2812_buffer*)luaL_checkudata(L, 1, "ws2812.buffer");
luaL_Buffer result;
luaL_buffinit(L, &result);
luaL_addchar(&result, '[');
int i;
int p = 0;
for (i = 0; i < buffer->size; i++) {
int j;
if (i > 0) {
luaL_addchar(&result, ',');
}
luaL_addchar(&result, '(');
for (j = 0; j < buffer->colorsPerLed; j++, p++) {
if (j > 0) {
luaL_addchar(&result, ',');
}
char numbuf[5];
c_sprintf(numbuf, "%d", buffer->values[p]);
luaL_addstring(&result, numbuf);
}
luaL_addchar(&result, ')');
}
luaL_addchar(&result, ']');
luaL_pushresult(&result);
return 1;
}
static const LUA_REG_TYPE ws2812_buffer_map[] = static const LUA_REG_TYPE ws2812_buffer_map[] =
{ {
{ LSTRKEY( "dump" ), LFUNCVAL( ws2812_buffer_dump )},
{ LSTRKEY( "fade" ), LFUNCVAL( ws2812_buffer_fade )}, { LSTRKEY( "fade" ), LFUNCVAL( ws2812_buffer_fade )},
{ LSTRKEY( "fill" ), LFUNCVAL( ws2812_buffer_fill )}, { LSTRKEY( "fill" ), LFUNCVAL( ws2812_buffer_fill )},
{ LSTRKEY( "get" ), LFUNCVAL( ws2812_buffer_get )}, { LSTRKEY( "get" ), LFUNCVAL( ws2812_buffer_get )},
{ LSTRKEY( "replace" ), LFUNCVAL( ws2812_buffer_replace )},
{ LSTRKEY( "mix" ), LFUNCVAL( ws2812_buffer_mix )},
{ LSTRKEY( "power" ), LFUNCVAL( ws2812_buffer_power )},
{ LSTRKEY( "set" ), LFUNCVAL( ws2812_buffer_set )}, { LSTRKEY( "set" ), LFUNCVAL( ws2812_buffer_set )},
{ LSTRKEY( "size" ), LFUNCVAL( ws2812_buffer_size )},
{ LSTRKEY( "shift" ), LFUNCVAL( ws2812_buffer_shift )}, { LSTRKEY( "shift" ), LFUNCVAL( ws2812_buffer_shift )},
{ LSTRKEY( "size" ), LFUNCVAL( ws2812_buffer_size )},
{ LSTRKEY( "sub" ), LFUNCVAL( ws2812_buffer_sub )},
{ LSTRKEY( "__concat" ),LFUNCVAL( ws2812_buffer_concat )},
{ LSTRKEY( "__index" ), LROVAL( ws2812_buffer_map )}, { LSTRKEY( "__index" ), LROVAL( ws2812_buffer_map )},
{ LSTRKEY( "__tostring" ), LFUNCVAL( ws2812_buffer_tostring )},
{ LNILKEY, LNILVAL} { LNILKEY, LNILVAL}
}; };
......
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
#include "nodemcu_mdns.h" #include "nodemcu_mdns.h"
#if 0 #if 0
#define MDNS_DBG(...) os_printf(...) #define MDNS_DBG(...) dbg_printf(...)
#else #else
#define MDNS_DBG(...) do {} while (0) #define MDNS_DBG(...) do {} while (0)
#endif #endif
......
...@@ -355,11 +355,12 @@ sint32_t vfs_chdir( const char *path ) ...@@ -355,11 +355,12 @@ sint32_t vfs_chdir( const char *path )
sint32_t vfs_errno( const char *name ) sint32_t vfs_errno( const char *name )
{ {
vfs_fs_fns *fs_fns; vfs_fs_fns *fs_fns;
const char *normname = normalize_path( name );
char *outname; char *outname;
if (!name) name = ""; // current drive if (!name) name = ""; // current drive
const char *normname = normalize_path( name );
#ifdef BUILD_SPIFFS #ifdef BUILD_SPIFFS
if (fs_fns = myspiffs_realm( normname, &outname, FALSE )) { if (fs_fns = myspiffs_realm( normname, &outname, FALSE )) {
return fs_fns->ferrno( ); return fs_fns->ferrno( );
......
...@@ -85,7 +85,7 @@ inline sint32_t vfs_flush( int fd ) { ...@@ -85,7 +85,7 @@ inline sint32_t vfs_flush( int fd ) {
// Returns: File size // Returns: File size
inline uint32_t vfs_size( int fd ) { inline uint32_t vfs_size( int fd ) {
vfs_file *f = (vfs_file *)fd; vfs_file *f = (vfs_file *)fd;
return f && f->fns->size ? f->fns->size( f ) : 0; return f ? f->fns->size( f ) : 0;
} }
// vfs_ferrno - get file system specific errno // vfs_ferrno - get file system specific errno
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
#include "platform.h" #include "platform.h"
#include "spiffs.h" #include "spiffs.h"
#include "spiffs_nucleus.h"
spiffs fs; spiffs fs;
#define LOG_PAGE_SIZE 256 #define LOG_PAGE_SIZE 256
...@@ -10,9 +12,9 @@ spiffs fs; ...@@ -10,9 +12,9 @@ spiffs fs;
#define MIN_BLOCKS_FS 4 #define MIN_BLOCKS_FS 4
static u8_t spiffs_work_buf[LOG_PAGE_SIZE*2]; static u8_t spiffs_work_buf[LOG_PAGE_SIZE*2];
static u8_t spiffs_fds[32*4]; static u8_t spiffs_fds[sizeof(spiffs_fd) * SPIFFS_MAX_OPEN_FILES];
#if SPIFFS_CACHE #if SPIFFS_CACHE
static u8_t spiffs_cache[(LOG_PAGE_SIZE+32)*2]; static u8_t myspiffs_cache[(LOG_PAGE_SIZE+32)*2];
#endif #endif
static s32_t my_spiffs_read(u32_t addr, u32_t size, u8_t *dst) { static s32_t my_spiffs_read(u32_t addr, u32_t size, u8_t *dst) {
...@@ -168,8 +170,8 @@ static bool myspiffs_mount_internal(bool force_mount) { ...@@ -168,8 +170,8 @@ static bool myspiffs_mount_internal(bool force_mount) {
spiffs_fds, spiffs_fds,
sizeof(spiffs_fds), sizeof(spiffs_fds),
#if SPIFFS_CACHE #if SPIFFS_CACHE
spiffs_cache, myspiffs_cache,
sizeof(spiffs_cache), sizeof(myspiffs_cache),
#else #else
0, 0, 0, 0,
#endif #endif
...@@ -243,6 +245,7 @@ static sint32_t myspiffs_vfs_lseek( const struct vfs_file *fd, sint32_t off, int ...@@ -243,6 +245,7 @@ static sint32_t myspiffs_vfs_lseek( const struct vfs_file *fd, sint32_t off, int
static sint32_t myspiffs_vfs_eof( const struct vfs_file *fd ); static sint32_t myspiffs_vfs_eof( const struct vfs_file *fd );
static sint32_t myspiffs_vfs_tell( const struct vfs_file *fd ); static sint32_t myspiffs_vfs_tell( const struct vfs_file *fd );
static sint32_t myspiffs_vfs_flush( const struct vfs_file *fd ); static sint32_t myspiffs_vfs_flush( const struct vfs_file *fd );
static uint32_t myspiffs_vfs_size( const struct vfs_file *fd );
static sint32_t myspiffs_vfs_ferrno( const struct vfs_file *fd ); static sint32_t myspiffs_vfs_ferrno( const struct vfs_file *fd );
static sint32_t myspiffs_vfs_closedir( const struct vfs_dir *dd ); static sint32_t myspiffs_vfs_closedir( const struct vfs_dir *dd );
...@@ -295,7 +298,7 @@ static vfs_file_fns myspiffs_file_fns = { ...@@ -295,7 +298,7 @@ static vfs_file_fns myspiffs_file_fns = {
.eof = myspiffs_vfs_eof, .eof = myspiffs_vfs_eof,
.tell = myspiffs_vfs_tell, .tell = myspiffs_vfs_tell,
.flush = myspiffs_vfs_flush, .flush = myspiffs_vfs_flush,
.size = NULL, .size = myspiffs_vfs_size,
.ferrno = myspiffs_vfs_ferrno .ferrno = myspiffs_vfs_ferrno
}; };
...@@ -430,13 +433,17 @@ static sint32_t myspiffs_vfs_close( const struct vfs_file *fd ) { ...@@ -430,13 +433,17 @@ static sint32_t myspiffs_vfs_close( const struct vfs_file *fd ) {
static sint32_t myspiffs_vfs_read( const struct vfs_file *fd, void *ptr, size_t len ) { static sint32_t myspiffs_vfs_read( const struct vfs_file *fd, void *ptr, size_t len ) {
GET_FILE_FH(fd); GET_FILE_FH(fd);
return SPIFFS_read( &fs, fh, ptr, len ); sint32_t n = SPIFFS_read( &fs, fh, ptr, len );
return n >= 0 ? n : VFS_RES_ERR;
} }
static sint32_t myspiffs_vfs_write( const struct vfs_file *fd, const void *ptr, size_t len ) { static sint32_t myspiffs_vfs_write( const struct vfs_file *fd, const void *ptr, size_t len ) {
GET_FILE_FH(fd); GET_FILE_FH(fd);
return SPIFFS_write( &fs, fh, (void *)ptr, len ); sint32_t n = SPIFFS_write( &fs, fh, (void *)ptr, len );
return n >= 0 ? n : VFS_RES_ERR;
} }
static sint32_t myspiffs_vfs_lseek( const struct vfs_file *fd, sint32_t off, int whence ) { static sint32_t myspiffs_vfs_lseek( const struct vfs_file *fd, sint32_t off, int whence ) {
...@@ -456,7 +463,8 @@ static sint32_t myspiffs_vfs_lseek( const struct vfs_file *fd, sint32_t off, int ...@@ -456,7 +463,8 @@ static sint32_t myspiffs_vfs_lseek( const struct vfs_file *fd, sint32_t off, int
break; break;
} }
return SPIFFS_lseek( &fs, fh, off, spiffs_whence ); sint32_t res = SPIFFS_lseek( &fs, fh, off, spiffs_whence );
return res >= 0 ? res : VFS_RES_ERR;
} }
static sint32_t myspiffs_vfs_eof( const struct vfs_file *fd ) { static sint32_t myspiffs_vfs_eof( const struct vfs_file *fd ) {
...@@ -477,6 +485,16 @@ static sint32_t myspiffs_vfs_flush( const struct vfs_file *fd ) { ...@@ -477,6 +485,16 @@ static sint32_t myspiffs_vfs_flush( const struct vfs_file *fd ) {
return SPIFFS_fflush( &fs, fh ) >= 0 ? VFS_RES_OK : VFS_RES_ERR; return SPIFFS_fflush( &fs, fh ) >= 0 ? VFS_RES_OK : VFS_RES_ERR;
} }
static uint32_t myspiffs_vfs_size( const struct vfs_file *fd ) {
GET_FILE_FH(fd);
int32_t curpos = SPIFFS_tell( &fs, fh );
int32_t size = SPIFFS_lseek( &fs, fh, 0, SPIFFS_SEEK_END );
(void) SPIFFS_lseek( &fs, fh, curpos, SPIFFS_SEEK_SET );
return size;
}
static sint32_t myspiffs_vfs_ferrno( const struct vfs_file *fd ) { static sint32_t myspiffs_vfs_ferrno( const struct vfs_file *fd ) {
return SPIFFS_errno( &fs ); return SPIFFS_errno( &fs );
} }
......
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