Porównaj commity

...

253 Commity

Autor SHA1 Wiadomość Data
martin-ger 7d94092849 bigger buffers (for tasmota) 2023-04-15 09:45:27 +02:00
martin-ger 9af8b48b17 latest uMQTTBroker lib 2023-04-15 09:12:29 +02:00
martin-ger 7bd705bc0b new binary 2020-02-20 15:19:15 +01:00
martin-ger 07bcd5f00c disconnect on too long message 2020-02-20 11:19:23 +01:00
martin-ger 3e1e72f763 Added AP channel config 2019-01-27 17:37:33 +01:00
martin-ger 2d613c3f90 longer mqtt_id 2019-01-02 09:21:22 +01:00
martin-ger 325923773f
Update README.md 2018-11-08 12:00:46 +01:00
Martin Ger a0f6c505bb uMQTTBroker lastets submodul 2018-11-07 10:16:54 +01:00
Martin Ger 8093558f68 compiled with SDK 2.2 - much more RAM 2018-11-07 10:07:17 +01:00
Martin Ger 358672e085 reset wait 2018-07-18 20:04:31 +02:00
martin-ger ac9041d2d1
Update README.md 2018-07-04 22:06:38 +02:00
Martin Ger bcdf67d648 added 'while do' in scripts 2018-07-04 20:42:13 +02:00
Martin Ger f8f57ecaf7 Update Readme.md with DNS 2018-06-24 11:56:20 +02:00
Martin Ger a07969e954 added basic DNS support 2018-06-24 11:19:06 +02:00
Martin Ger c71a6d1f07 Initial tests DNS 2018-06-22 12:51:04 +02:00
martin-ger b9f3656c09
Update script.timeclock 2018-06-12 16:52:56 +02:00
Martin Ger f1050e5b27 Fix in init_data 2018-06-07 08:40:48 +02:00
Martin Ger 3a3bf92a12 Updated Readme 2018-06-06 22:43:35 +02:00
Martin Ger 6cef1b9b1a added Cicero's esp_init_data init 2018-06-06 22:42:08 +02:00
Martin Ger 6964c0eb50 fixed issue #36 2018-05-20 23:15:27 +02:00
martin-ger b39cbe8b14
Update script.pir 2018-05-15 16:36:10 +02:00
Martin Ger 32e59b48dd save time to RTC mem 2018-03-21 16:00:13 +01:00
Martin Ger f99e3adec6 local time 2018-03-20 12:15:15 +01:00
Martin Ger 89ee5f4c99 More RAM with string consts in flash 2018-03-03 09:52:40 +01:00
Martin Ger 81a009de8a added wifidisconnect 2018-02-22 09:36:42 +01:00
Martin Ger 76b14adb37 Add user level connection timeouts 2018-02-20 12:03:57 +01:00
martin-ger d9bf233108
Update script.no_serial 2018-02-19 20:35:32 +01:00
martin-ger e80656bfa9
Update README.md 2018-02-13 11:27:51 +01:00
Martin Ger 35ba82bd07 added broker_port 2018-02-11 10:09:03 +01:00
Martin Ger b7740123d9 latest compile 2018-02-09 23:40:40 +01:00
martin-ger 21481c6c77
Update cli.c 2018-02-09 23:32:01 +01:00
Martin Ger c64651dd4f fixed GPIO interrupt handling 2018-02-08 15:27:44 +01:00
Martin Ger 129476f2d7 Fixes to serial handling in scripts 2018-02-01 09:34:42 +01:00
Martin Ger b00189ecb5 added serial demo script 2018-01-30 13:04:33 +01:00
Martin Ger b9d9e91924 fixed http script download 2018-01-29 22:29:27 +01:00
Martin Ger f652c46388 latest version of uMQTTBroker 2018-01-25 00:12:04 +01:00
Martin Ger ca4d648e33 Bug in delete_client_by_id 2018-01-20 14:31:53 +01:00
Martin Ger f02f2b3185 new version of uMQTTBroker 2018-01-13 17:07:28 +01:00
Martin Ger 1d624d4bc4 race condition in disconnect resolved 2018-01-13 16:55:04 +01:00
Martin Ger 0ff1ae847b added bridge script 2017-12-31 13:24:45 +01:00
Martin Ger 2afa1d93b4 added bridge script 2017-12-31 13:12:06 +01:00
martin-ger cac546bfe6
Update README.md 2017-12-16 17:09:15 +01:00
Martin Ger 1e617f3c87 added command backlog 2017-12-16 13:49:42 +01:00
Martin Ger f7af07080a added and 2017-12-16 10:11:42 +01:00
Martin Ger acfcac6843 added byte_val() and binary() 2017-12-01 01:17:18 +01:00
Martin Ger ffab86c7e8 added serial in scripting 2017-11-30 21:54:38 +01:00
Martin Ger d0bb72c67d cli.c new and csvstr() 2017-11-30 15:28:48 +01:00
Martin Ger f1f3389bbc added serial config 2017-11-30 08:54:59 +01:00
Martin Ger cf4eb6b718 substr, '$' handling 2017-11-24 20:14:32 +01:00
Martin Ger ffceccf9c3 substr added 2017-11-17 16:48:11 +01:00
Martin Ger bdfa7b0825 deleted clock events 2017-11-17 00:16:14 +01:00
Martin Ger 2f49d98f0a alarm instead of clock events 2017-11-17 00:11:13 +01:00
martin-ger 290f29dc5b
Update README.md 2017-11-14 19:56:27 +01:00
Martin Ger ff2cb24f51 new uMQTTBroker 2017-11-14 19:39:36 +01:00
martin-ger c15bde4f2a
Update README.md 2017-11-14 19:27:58 +01:00
martin-ger 5f57df5bb6
Update README.md 2017-11-14 19:22:00 +01:00
Martin Ger 373fdca6a2 moved uMQTTBroker lib to a separate repository 2017-11-14 18:54:49 +01:00
Martin Ger 15945718fb handle of empty passwords issue #15 2017-11-14 10:27:14 +01:00
Martin Ger e3b494b70f moved cleanup into the libmqtt 2017-11-08 22:53:36 +01:00
Martin Ger bc5bfbd2d4 do not activate closed connections 2017-11-08 21:50:04 +01:00
Martin Ger 9250e3b533 automatic mem limit; cleanup after STA disconnect 2017-11-08 21:34:36 +01:00
Martin Ger 23c54e7cd7 max number of clients added 2017-11-05 15:36:06 +01:00
Martin Ger ce86663aed added http_post 2017-10-31 15:05:36 +01:00
Martin Ger dbcb7ca6b8 cleaned up disconnect 2017-10-31 14:43:16 +01:00
Martin Ger db51f64528 lib patch 2017-10-26 19:23:06 +02:00
Martin Ger 868c8d6a24 lock retained and publish commands 2017-10-21 15:21:39 +02:00
Martin Ger f480661f9b Autosave of retained topics and script acces 2017-10-21 14:51:01 +02:00
Martin Ger b081def24b Enabled SSL for HTTP and MQTT client 2017-10-20 14:50:51 +02:00
Martin Ger 969329fedb persistence for retained topics 2017-10-20 12:45:56 +02:00
martin-ger ecd5d72ffa Note on Arduino in the abstract 2017-10-20 10:08:28 +02:00
martin-ger 0b254647f7 Added Windows flash instructions 2017-10-20 10:04:28 +02:00
Martin Ger c217ae16cb Initially auto_connect off 2017-10-19 14:33:16 +02:00
Martin Ger 5f6e7545b2 Applied WPA2 KRACK pathes, build with SDK 2.1.0 2017-10-17 09:23:13 +02:00
Martin Ger a797c49715 Update of Readme 2017-10-16 18:18:30 +02:00
Martin Ger 6629df90f0 Add HTTP script upload 2017-10-16 18:11:06 +02:00
Martin Ger f89c74a715 ADC support and shared output buffer 2017-10-12 21:17:41 +02:00
Martin Ger ed3a3b621e Fix for issue 'wdt reset' #5 - reset of script on first boot 2017-10-08 17:02:53 +02:00
Martin Ger cb563d13fd Added Arduino sample code 2017-10-04 22:36:23 +02:00
Martin Ger a71414f77e Added JSON parsing 2017-10-03 23:09:07 +02:00
Martin Ger 4ace989d53 added http client support 2017-10-02 10:34:59 +02:00
martin-ger 493d22e53f Update SCRIPTING.md 2017-09-29 21:37:18 +02:00
Martin Ger 521fcf92ff Added doc on the scripting language 2017-09-29 21:22:55 +02:00
Martin Ger 2b6f223903 Added PWM example 2017-09-29 11:32:25 +02:00
martin-ger 1bb6f445f0 Update README.md 2017-09-29 08:46:17 +02:00
Martin Ger 2d7c43145e Added PWM 2017-09-29 01:46:42 +02:00
Martin Ger a365bf8278 Notes on flash vars 2017-09-26 21:25:02 +02:00
Martin Ger c2f2fbd421 some more code intructions 2017-09-22 15:30:52 +02:00
Martin Ger dd4cf9c2da added Arduino include file 2017-09-22 15:22:22 +02:00
martin-ger e0689dcfbc Update README.md
Some more on Arduino
2017-09-22 09:03:49 +02:00
Martin Ger 43bfae15ed Typos in README 2017-09-17 10:41:03 +02:00
Martin Ger 284d553234 Library build, Arduino instructions 2017-09-17 10:34:08 +02:00
martin-ger 6908a299d4 Update README.md 2017-08-28 14:56:39 +02:00
Martin Ger e446385bc8 fixes in output 2017-08-28 10:42:04 +02:00
Martin Ger 5e2889924b added and print vars 2017-08-24 21:48:58 +02:00
Martin Ger 12c937c9d4 added @vars in flash 2017-08-23 20:57:38 +02:00
Martin Ger 671a543ce3 demo scripts and publish command 2017-08-22 21:46:45 +02:00
Martin Ger 34b225620f faster delete of re-established connections 2017-08-21 22:03:44 +02:00
Martin Ger 3ab2cad6e6 broker access mode added 2017-08-21 14:27:07 +02:00
Martin Ger d262d21b21 'if then else' added 2017-08-21 12:00:54 +02:00
Martin Ger 42b3d0e20a mDNS added 2017-08-21 09:37:28 +02:00
Martin Ger ec02aba72a added logging and broker config 2017-08-19 15:01:53 +02:00
Martin Ger a6078d3caa some cleanup 2017-08-19 12:08:48 +02:00
Martin Ger f45d8fdb09 unlock during 'system' command 2017-08-19 08:34:34 +02:00
Martin Ger 743cbb40c5 system command added 2017-08-18 08:44:01 +02:00
Martin Ger 82d940d873 fix in signal handling 2017-08-17 14:07:20 +02:00
Martin Ger 30260a110d added var ids 2017-08-17 10:23:13 +02:00
Martin Ger 4d941993f5 added vars as topics 2017-08-17 08:46:19 +02:00
Martin Ger 3117ba6b53 added config access modes 2017-08-16 14:00:51 +02:00
Martin Ger 171b75c65c user/password auth added 2017-08-16 11:04:31 +02:00
Martin Ger 10700b7b94 queuing of 'on topic' events 2017-08-15 22:42:41 +02:00
Martin Ger aef3f73e03 No remote reset on locked device 2017-08-14 15:55:19 +02:00
Martin Ger 8205b1cf04 added gpio_pinmode, gpio_in, and brackets 2017-07-26 11:59:11 +02:00
Martin Ger 9d8f70aeae some stats added 2017-07-23 11:26:21 +02:00
Martin Ger 8507c45823 mqttconnect added, mem issues 2017-07-22 22:23:35 +02:00
Martin Ger fcfd1985e5 strcat added, operators added 2017-07-22 19:26:16 +02:00
Martin Ger 1fc6ae24c6 added scripting to the master branch 2017-07-21 16:35:45 +02:00
Martin Ger 7c15a93399 Bug in event queues 2017-07-16 20:27:29 +02:00
Martin Ger de37f8c3d7 /broker/time added 2017-07-13 10:41:58 +02:00
Martin Ger 0b7be38fb1 added NTP time 2 2017-07-12 22:57:08 +02:00
Martin Ger f8715595da added NTP time 2017-07-12 22:04:02 +02:00
Martin Ger 717c6c7653 fix in local publish2 2017-06-23 18:06:55 +02:00
Martin Ger 9c3097198e fix in local publish 2017-06-23 18:05:39 +02:00
Martin Ger 13f58ddfad fixed remote publish 2017-06-22 16:25:24 +02:00
Martin Ger 10f292f27e Added basic sample at user_basic/ 2017-06-07 22:21:26 +02:00
Martin Ger ede97ea37b remote client and MQTT bridging functionality 2017-06-03 15:44:03 +02:00
Martin Ger 0d735c8024 Mem error in retained topics 2017-06-02 14:45:01 +02:00
Martin Ger d519cbb076 Merge branch 'master' of https://github.com/martin-ger/esp_mqtt 2017-06-02 12:04:51 +02:00
Martin Ger 779c7cf26c fix when sending retained topics 2017-06-02 12:03:18 +02:00
martin-ger 4485007978 Update README.md 2017-06-02 02:04:59 +02:00
Martin Ger 8b68abcbcd added precompiled firmware 2017-06-02 01:32:18 +02:00
martin-ger 42939a8bc2 Update README.md 2017-06-02 01:24:31 +02:00
Martin Ger ebfb3e897a added user sample program 2017-06-02 01:04:48 +02:00
Martin Ger 7b3905ae16 Initial commit of uMQTT Broker 2017-06-01 23:38:03 +02:00
Tuan PM cf87bc521e Merge pull request #126 from st0ff3r/master
PROTO_AddRb(): rollback inserts into ringbuffer done by RINGBUF_Put()…
2017-05-25 10:14:47 +07:00
Tuan PM 7ec2ef8e1d Merge pull request #127 from someburner/master
Extend init method to allow 0-length client IDs if MQTTv311 is set
2016-11-20 20:47:08 +07:00
Jeff H 885bde3af9 Extend init method to allow 0-length client IDs if MQTTv311 is set 2016-11-20 01:12:37 -08:00
st0ff3r 80abcbf3a9 PROTO_AddRb(): rollback inserts into ringbuffer done by RINGBUF_Put() when there was not eneough space free 2016-11-18 05:32:06 +01:00
Tuan PM 9249c2a055 Merge pull request #125 from ToSa27/master
Compile to Library
2016-10-26 09:18:56 +07:00
Tobias Hoff 8cf1063d80 Compile to Library
use "make lib" to compile as library
2016-10-26 03:54:33 +02:00
Tobias Hoff adfa2c1833 ignore implicit function declaration
to successfully build without adding declarations missing from the SDK
2016-10-26 03:40:41 +02:00
Tuan PM ccdf6a6213 Merge pull request #124 from ToSa27/master
explicitely set SSL size
2016-10-26 08:36:59 +07:00
Tobias Hoff 0f4113cea4 explicitely set SSL size 2016-10-26 03:33:53 +02:00
Tuan PM d5dcfbaf47 update sdk link 2016-09-18 18:04:48 +07:00
Tuan PM 69710db095 Merge pull request #121 from someburner/patch-1
Use proper type for keepalive
2016-09-18 17:41:49 +07:00
Jeff Hufford 149091e167 Use proper type for keepalive
Minor, but keepalive member in struct mqtt_connect_info is signed and gets compared with unsigned.
2016-09-17 10:22:57 -07:00
Tuan PM 5162b941a8 test travis 4 2016-09-09 23:10:33 +07:00
Tuan PM b19d7822e2 test travis 3 2016-09-09 23:05:51 +07:00
Tuan PM c7e70396ba test travis 2 2016-09-09 23:03:28 +07:00
Tuan PM 676513735a test travis 1 2016-09-09 22:58:05 +07:00
Tuan PM 3f55b6ce7b test travis 2016-09-09 22:52:12 +07:00
Tuan PM 4e303d1674 update travis method to build new esp_mqtt 2016-09-09 22:39:06 +07:00
Tuan PM 30523fbe90 -reformat code using space 2
- fix bug connect callback when connection refuse
- change INFO to MQTT_INFO to resolve conflic with global INFO define
2016-09-09 22:37:03 +07:00
Tuan PM 4acdfe0a5d update link travis to README and fixed opensdk link 2016-09-09 21:18:31 +07:00
Tuan PM bcf0ce4c59 update link travis to README and fixed opensdk link 2016-09-09 21:04:19 +07:00
Tuan PM dbd3324a0a update link travis to README and fixed opensdk link 2016-09-09 21:02:00 +07:00
Tuan PM f5a4f0a7ed update open sdk link for travis 2016-09-09 20:57:29 +07:00
Tuan PM cc989eaa95 update travis to build with sdk 2.0 2016-09-09 20:53:30 +07:00
Tuan PM 91b7ef9b81 Update readme 2016-09-09 20:49:00 +07:00
Tuan PM 7fde706b8e remove all submodule 2016-09-09 20:37:37 +07:00
Tuan PM f7ccc86709 -update to sdk 2.0
- cleanup and make Makefile simple
- add define to get local_config
- remove esptool
2016-09-09 20:36:52 +07:00
Tuan PM a5e5f97cca Merge pull request #118 from vowstar/master
Some fix about stability of mqtt connection about keepalive
2016-09-06 19:35:03 +07:00
Huang Rui 65bf3adc2a Fix keepalive time error.Made keepalive interval half of keepalive time.
This can prevent abnormal disconnect.
2016-09-06 18:32:34 +08:00
Huang Rui c1ac44a083 Clear callback functions to avoid abnormal callback 2016-08-23 17:35:31 +08:00
Tuan PM 8ceb84eb5b Merge pull request #116 from vowstar/master
Fix memory leak when call mqtt_client_delete, and add rfinit.c
2016-08-18 08:13:44 +07:00
Huang Rui e93ccc8f28 Fix memory leak when delete mqtt clientadd modules/rfinit.c, add __attribute__((weak)) to make it works on both sdk 2.0.0 and esp_open_sdk 2016-08-18 02:57:36 +08:00
Huang Rui 1e1d336414 Merge https://github.com/vowstar/esp_mqtt 2016-08-17 21:41:53 +08:00
Tuan PM c082fcbd7c Merge pull request #100 from jensh/mqtt_get_publish_data
mqtt_get_publish_data() should always return len=0 if data=NULL.
2016-06-30 07:49:00 +07:00
Tuan PM d4fd20005c Merge pull request #110 from sreeisalso/master
Corrected mqtt keep alive send
2016-06-30 07:46:51 +07:00
Tuan PM 8933adb4d6 Merge pull request #112 from someburner/master
add wrapper for un-subscribe, check user/pass for NULL
2016-06-30 07:44:44 +07:00
Jeff Hufford 6044edb078 Forgot ICACHE_FLASH_ATTR in header 2016-06-29 07:06:27 -07:00
Jeff H 88bb406fb4 add null checks for client user/pass 2016-06-13 01:09:48 -07:00
Jeff H 53c913256d add wrapper for un-subscribe 2016-06-13 01:05:36 -07:00
Sreekanth 0c806ec0f1 Merge pull request #2 from tuanpmt/master
latest
2016-06-07 14:13:20 +05:30
Sreekanth 280b5c3ce8 updated client->keepAliveTick when packet is sent/received 2016-06-07 12:30:35 +05:30
Tuan PM 368c1aad63 Merge pull request #109 from StefanBruens/sanitize_config_strings
Sanitize config strings
2016-06-01 16:32:23 +07:00
Stefan Brüns 764cc125c1 Extend device_id config field to 32 characters, including trailing null 2016-05-31 19:06:51 +02:00
Stefan Brüns b458ea49c1 make sure SSID is not overwritten by mqtt client id, always null-terminate
Each os_sprintf potentially overwrites any later field if the configured
value is to long.
2016-05-31 19:06:45 +02:00
Rui Huang 679c42a062 Merge pull request #5 from tuanpmt/master
Update code from upstream
2016-04-20 16:54:01 +08:00
Sreekanth c91dcf89df Merge pull request #1 from tuanpmt/master
updating latest
2016-04-06 11:03:28 +05:30
Tuan PM c431787276 Merge pull request #101 from lorenzph/fix-reconnection
Delete existing connection before connecting
2016-04-04 08:20:01 +07:00
Philip Lorenz 0f980bf7eb Delete existing connection before connecting
If the current connection is terminated unexpectedly (e.g. because the
WiFi connection is dropped) the disconnect callback is not called. This
means that reestablishing the existing connection is not possible any
more.

Avoid this issue by forcefully removing the existing connection before
initiating the reconnection. Calling MQTT_Disconnect and waiting for
the disconnection callback should still be performed for intentional
disconnections.

Fixes #96
2016-04-03 19:38:50 +02:00
Jens Hauke 24cda90286 mqtt_get_publish_data() should always return len=0 if data=NULL.
In case of qos>0 mqtt_get_publish_data might return data=NULL but
leave len=buffer_len (!= 0). Doing a memcpy(user_buffer, data, len)
with such a len cause a segfault. This patch always set len=0 when
data=NULL.
2016-04-01 16:53:59 +02:00
Tuan PM 670cfd7171 Merge pull request #99 from sreeisalso/master
Corrected secure TCP_DISCONNECTING
2016-03-31 18:07:08 +07:00
Sreekanth 90e316cc1e Corrected secure TCP_DISCONNECTING 2016-03-31 10:19:16 +05:30
Rui Huang fb0a26b3ba Merge pull request #4 from tuanpmt/master
Merge lorenzph‘s fix
2016-03-05 22:26:17 +08:00
Tuan PM 1843a1efb4 Merge pull request #94 from lorenzph/improve-reliability
Improve reliability
2016-02-17 10:54:01 +07:00
Philip Lorenz ecffa17bac Disconnect before reconnecting
If a reconnect is triggered on a built-up connection the current
espconn instance is replaced without waiting for the invocation of
its disconnection callback.
As a result the disconnection callback gets invoked when the new
espconn instance has already been set, falsely terminating the newly
created connection.

Fix this by disconnecting the current connection cleanly before trying
to reestablish the connection. This change also prevents reconnections
via MQTT_Connect. Instead users should disconnect the current
connection via MQTT_Disconnect before invoking MQTT_Connect for an
existing client.
2016-02-14 22:29:57 +01:00
Philip Lorenz 3e2c77deb5 Do not send keep-alive before pending send has finished
According to the SDK documentation espconn_send should not be called
before espconn_sent_callback has been invoked for the previous
call.

Fixes #67
2016-02-14 22:29:57 +01:00
Tuan PM a5f072bcb1 Merge pull request #92 from vowstar/master
Adjust disconnect add timeout callback in MQTT module.
2016-02-02 13:09:12 +07:00
Rui Huang b71b014b25 Merge pull request #3 from Deadolus/sdk_1.5.0
Merge Sdk 1.5.0 travis file
2016-01-25 02:12:38 +08:00
Rui Huang 1d88deab09 Merge pull request #2 from Deadolus/master
Adding crypto modul for esp_mqtt to work with SDK 1.5.0
2016-01-25 02:07:56 +08:00
Simon Egli 011022510b Adding apt-get update as suggested by manual
Manual at: https://docs.travis-ci.com/user/installing-dependencies/

Signed-off-by: Simon Egli <simon.egli@bbv.ch>
2016-01-21 10:04:57 +01:00
Simon Egli 7bfeb6db16 Downloading newest version of SDK
Signed-off-by: Simon Egli <simon.egli@bbv.ch>
2016-01-21 10:00:34 +01:00
Simon Egli 249c425bac Adding crypto modul for esp_mqtt to work with SDK 1.5.0
Signed-off-by: Simon Egli <simon.egli@bbv.ch>
2016-01-15 15:21:28 +01:00
Huang Rui d2ee709744 Handle keep-alive and add make timeout working. 2016-01-01 02:30:12 +08:00
Huang Rui ee50b6232c Add timeout callback in MQTT module. 2016-01-01 01:25:33 +08:00
Huang Rui 1d07213b4d Rename MQTT_ping to MQTT_Ping 2015-12-31 21:48:20 +08:00
Huang Rui 2be4be43e5 Add MQTT_DeleteClient method.
You can use it to safe delete MQTT connection, and free all memory.
2015-12-31 21:43:37 +08:00
Huang Rui 23635a710f Disconnect in a more safe way.
Using os_post to trig the task to safe call disconnect.
Disconnect the TCP connection when execute MQTT disconnect.
2015-12-31 20:55:37 +08:00
Huang Rui a08749fdf7 qos is not used in MQTT_Subscribe(MQTT_Client client, char topic, uint8_t qos)
Fix https://github.com/tuanpmt/esp_mqtt/issues/82
2015-12-31 14:47:08 +08:00
Huang Rui 3a6a6ac77a Enable SSL 2015-12-31 14:31:33 +08:00
Huang Rui c3d744ae94 Add debug info if platform don't support SSL due to some reason.
Add MQTT_ping.
2015-12-31 14:31:18 +08:00
Huang Rui d9e6e715d5 Add mqtt_config.h to some headers need use.
Add default user_config.h
2015-12-31 14:25:07 +08:00
Huang Rui 83daf971d6 Rename user_config.h to mqtt_config.h 2015-12-31 14:21:59 +08:00
Huang Rui 39277ca0f5 Update MQTT config file 2015-12-31 14:21:22 +08:00
Rui Huang 29a1bd9cbd Merge pull request #1 from frolswe/master
Clear whole mqtt_connection_t.
2015-12-31 14:05:00 +08:00
TuanPM 70d19cbb4d update README for clone --recursive 2015-09-03 13:19:15 +07:00
TuanPM 2786b6f68b change method save wifi infomation to flash 2015-09-03 13:15:02 +07:00
Tuan PM 55937fb701 update support sdk 1.3, not fully tested 2015-08-31 12:10:45 +07:00
Fredrik Olofsson 246e051ed0 Clear whole mqtt_connection_t. 2015-07-23 14:43:55 +02:00
Tuan PM 28c63ffa13 Merge pull request #61 from AxelLin/master
Revert "Add user_rf_pre_init() function to fix build error with SDK-1…
2015-05-30 10:47:10 +07:00
Axel Lin 9f8b8ee117 Revert "Add user_rf_pre_init() function to fix build error with SDK-1.1.0"
This reverts commit 5ff9766908.

The esp-onen-sdk adds the fix for force-requiring user_rf_pre_init() [1].
So we need to drop the user_rf_pre_init function in user_main.c to prevent
multiple definition of `user_rf_pre_init' error.

[1] 4e4590de89
2015-05-29 10:55:25 +08:00
Tuan PM 42798bcba5 Merge pull request #59 from AxelLin/master
Add user_rf_pre_init() function to fix build error with SDK-1.1.0
2015-05-26 15:52:14 +07:00
Axel Lin 5ff9766908 Add user_rf_pre_init() function to fix build error with SDK-1.1.0
This patch fixes below build error with SDK-1.1.0:
esp-open-sdk/sdk/lib/libmain.a(app_main.o): In function `user_uart_wait_tx_fifo_empty':
(.irom0.text+0x34c): undefined reference to `user_rf_pre_init'

According to esp_iot_sdk_v1.1.0_15_05_26 Release Note:
user_rf_pre_init has to be added in user_main.c, user can call
system_phy_set_rfoption to set configuration of RF in it.
2015-05-26 14:55:52 +08:00
Tuan PM 9f4d1508a8 Merge pull request #56 from AxelLin/master
Fix unsubscribe message type
2015-05-07 09:43:22 +07:00
Axel Lin 6556476624 Fix unsubscribe message type
Use MQTT_MSG_TYPE_UNSUBSCRIBE for unsubscribe.
2015-05-07 09:27:25 +08:00
Tuan PM 7247e3f9ff update readme 2015-03-05 17:43:13 +07:00
Tuan PM 24a6caeb22 add travis build 2015-03-05 17:39:27 +07:00
Tuan PM e03d539fa5 add travis build 2015-03-05 17:27:44 +07:00
Tuan PM dbec377d1f NULL to 0 2015-03-02 16:22:56 +07:00
Tuan PM 10851cd97d return when os_event_t == NULL 2015-03-02 16:21:24 +07:00
Tuan PM e6e4e3d914 add user_data to mqtt structure 2015-02-28 19:32:51 +07:00
Tuan PM 261a21db71 move config.* and wifi.* to modules folder 2015-02-16 17:22:10 +07:00
Tuan PM 10d13ed5dc Update README.md, resolve #43 2015-02-16 11:53:12 +07:00
Tuan PM d579c08765 cleanup makefile 2015-02-15 21:44:39 +07:00
Tuan PM da4e128ddc Add compilation instructions 2015-02-15 21:19:21 +07:00
TuanPM 597e078a64 change executeable attr for tools/esptool.py 2015-02-15 19:37:51 +07:00
Tuan PM cacc260e9d change file structure, easy to intergrated with other apps 2015-02-15 19:04:01 +07:00
Tuan PM 454f2d8bd5 Merge pull request #38 from eliabieri/master
Added note
2015-02-06 21:14:42 +07:00
Elia Bieri 10026b16ff Added note
I added a note where you can find the BLANKER (blank.bin) file.
Maybe this helps someone!
2015-02-06 11:54:08 +01:00
Tuan PM c5d81c0fe4 update readme 2015-02-06 09:47:01 +07:00
Tuan PM 774f5a99d4 add protocol name selection(3.11 or 3.1), defaut is v3.1, resolve #36 2015-02-06 09:41:37 +07:00
TuanPM f3cd69d5bb fixes some typo 2015-02-06 08:41:35 +07:00
TuanPM ba9381c06d remove local settings file 2015-02-02 23:24:11 +07:00
TuanPM 4c7c1fc642 correct some typo 2015-02-02 22:52:15 +07:00
Tuan PM 466e6dcf4b remove old queue to get more space if the queue is full 2015-02-02 19:46:46 +07:00
Tuan PM 2b7be3cc8e fixes error reconnect when lost wifi signal 2015-02-02 11:27:52 +07:00
Tuan PM 73e9c30f5c add ICACHE_FLASH_ATTR on functions, resolve #31 2015-01-31 13:21:29 +07:00
Tuan PM a4f112dc35 fixed error bad lwt qos and retain 2015-01-31 12:23:09 +07:00
Tuan PM d810138858 fixes error reconnect, thank @scragill reported 2015-01-29 09:57:15 +07:00
TuanPM d490bb15c6 Add Makefile for Mac OS Yosemite 2015-01-24 23:53:26 +07:00
Tuan PM 567543b05e update debug.h 2015-01-19 10:44:50 +07:00
Tuan PM d08a7844c0 Add project exampel from @eadf, close #28 2015-01-19 09:20:47 +07:00
Tuan PM e41ac71ccb Merge branch 'eadf-master' 2015-01-19 08:59:15 +07:00
Tuan PM f07f5b5024 Merge branch 'master' of https://github.com/eadf/esp_mqtt into eadf-master 2015-01-19 08:58:20 +07:00
EAD Fritz 362820086a driver/uart.h is *not* needed in wifi.c 2015-01-18 14:14:00 +01:00
EAD Fritz 9251afebd0 driver/uart.h is *not* needed in mqtt.c 2015-01-18 14:06:35 +01:00
EAD Fritz 65f907cf9c fixed a copy&paste bug 2015-01-18 12:40:57 +01:00
EAD Fritz d69d24da4a moved CLIENT_SSL_ENABLE away from the 'default configurations' section 2015-01-18 12:24:39 +01:00
EAD Fritz 4ca96e1424 removed .cproject and .project. These .gitgnored files are messing up subtree tests 2015-01-18 11:47:23 +01:00
Tuan PM 7621c66c96 fixes error when receive multiple publish msg same time 2015-01-18 17:47:07 +07:00
EAD Fritz 793a98b147 Moved all of the mqtt specific files to a separate build directory. The intention is to be able to use it as a git subtree module in other projects 2015-01-18 10:43:10 +01:00
Tuan PM f2c16b87f3 prerelease 2015-01-18 14:58:19 +07:00
83 zmienionych plików z 11000 dodań i 3349 usunięć

Wyświetl plik

@ -1,98 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
<storageModule moduleId="org.eclipse.cdt.core.settings">
<cconfiguration id="cdt.managedbuild.toolchain.gnu.mingw.base.1187134800">
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.toolchain.gnu.mingw.base.1187134800" moduleId="org.eclipse.cdt.core.settings" name="Default">
<externalSettings/>
<extensions>
<extension id="org.eclipse.cdt.core.PE" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
</extensions>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<configuration buildProperties="" description="" id="cdt.managedbuild.toolchain.gnu.mingw.base.1187134800" name="Default" parent="org.eclipse.cdt.build.core.emptycfg">
<folderInfo id="cdt.managedbuild.toolchain.gnu.mingw.base.1187134800.1389533387" name="/" resourcePath="">
<toolChain id="cdt.managedbuild.toolchain.gnu.mingw.base.1439189001" name="MinGW GCC" superClass="cdt.managedbuild.toolchain.gnu.mingw.base">
<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.PE" id="cdt.managedbuild.target.gnu.platform.mingw.base.1397325870" name="Debug Platform" osList="win32" superClass="cdt.managedbuild.target.gnu.platform.mingw.base"/>
<builder arguments="-f ${ProjDirPath}/Makefile" command="mingw32-make.exe" id="cdt.managedbuild.builder.gnu.cross.1675187259" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="cdt.managedbuild.builder.gnu.cross"/>
<tool id="cdt.managedbuild.tool.gnu.assembler.mingw.base.1317942365" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.mingw.base">
<inputType id="cdt.managedbuild.tool.gnu.assembler.input.811380737" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
</tool>
<tool id="cdt.managedbuild.tool.gnu.archiver.mingw.base.1098370265" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.mingw.base"/>
<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.mingw.base.1774344183" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.mingw.base">
<option id="gnu.cpp.compiler.option.include.paths.1171001356" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath">
<listOptionValue builtIn="false" value="&quot;C:\Espressif\ESP8266_SDK\include\&quot;"/>
</option>
<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1783416175" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
</tool>
<tool id="cdt.managedbuild.tool.gnu.c.compiler.mingw.base.270886552" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.mingw.base">
<option id="gnu.c.compiler.option.include.paths.452661071" superClass="gnu.c.compiler.option.include.paths" valueType="includePath">
<listOptionValue builtIn="false" value="&quot;C:\Espressif\ESP8266_SDK\include\&quot;"/>
</option>
<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1963428165" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
</tool>
<tool id="cdt.managedbuild.tool.gnu.c.linker.mingw.base.466053609" name="MinGW C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.mingw.base"/>
<tool id="cdt.managedbuild.tool.gnu.cpp.linker.mingw.base.748040064" name="MinGW C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.mingw.base">
<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.581028506" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
<additionalInput kind="additionalinput" paths="$(LIBS)"/>
</inputType>
</tool>
</toolChain>
</folderInfo>
</configuration>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
</cconfiguration>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<project id="at_v0.19_on_SDKv0.9.2.null.2072922048" name="at_v0.19_on_SDKv0.9.2"/>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
<storageModule moduleId="refreshScope" versionNumber="2">
<configuration configurationName="Default">
<resource resourceType="PROJECT" workspacePath="/at_v0.19_on_SDKv0.9.2"/>
</configuration>
</storageModule>
<storageModule moduleId="scannerConfiguration">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
<scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.mingw.base.1187134800;cdt.managedbuild.toolchain.gnu.mingw.base.1187134800.1389533387;cdt.managedbuild.tool.gnu.cpp.compiler.mingw.base.1774344183;cdt.managedbuild.tool.gnu.cpp.compiler.input.1783416175">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
</scannerConfigBuildInfo>
<scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.mingw.base.1187134800;cdt.managedbuild.toolchain.gnu.mingw.base.1187134800.1389533387;cdt.managedbuild.tool.gnu.c.compiler.mingw.base.270886552;cdt.managedbuild.tool.gnu.c.compiler.input.1963428165">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
</scannerConfigBuildInfo>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets">
<buildTargets>
<target name="all" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>mingw32-make.exe</buildCommand>
<buildArguments>-f ${ProjDirPath}/Makefile</buildArguments>
<buildTarget>all</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="clean" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>mingw32-make.exe</buildCommand>
<buildArguments>-f ${ProjDirPath}/Makefile clean</buildArguments>
<buildTarget>clean</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>false</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="flash" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>mingw32-make.exe</buildCommand>
<buildArguments>-f ${ProjDirPath}/Makefile</buildArguments>
<buildTarget>flash</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
</buildTargets>
</storageModule>
</cproject>

20
.editorconfig 100644
Wyświetl plik

@ -0,0 +1,20 @@
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[*Makefile*]
indent_style = tab
indent_size = 2

7
.gitignore vendored
Wyświetl plik

@ -1,5 +1,8 @@
.cproject
.project
build/
firmware/
.settings/
.DS_Store
include/user_config.local.h
scripts/script.demo
scripts/script.timers

3
.gitmodules vendored 100644
Wyświetl plik

@ -0,0 +1,3 @@
[submodule "uMQTTBroker"]
path = uMQTTBroker
url = https://github.com/martin-ger/uMQTTBroker

Wyświetl plik

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>mqtt_pub</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
<triggers>clean,full,incremental,</triggers>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
<triggers>full,incremental,</triggers>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.cdt.core.cnature</nature>
<nature>org.eclipse.cdt.core.ccnature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
</natures>
</projectDescription>

30
.travis.yml 100644
Wyświetl plik

@ -0,0 +1,30 @@
language: cpp
before_install:
- sudo apt-get -qq update
- sudo apt-get install -y python-serial srecord
install:
- mkdir tools && cd tools
- git clone https://github.com/themadinventor/esptool.git
- wget https://github.com/nodemcu/nodemcu-firmware/raw/master/tools/esp-open-sdk.tar.gz
- tar -zxvf esp-open-sdk.tar.gz
- export PATH=$PATH:$PWD/esp-open-sdk/xtensa-lx106-elf/bin
- chmod +x $PWD/esptool/esptool.py
- export ESPTOOL=$PWD/esptool/esptool.py
- wget http://bbs.espressif.com/download/file.php?id=1690 -O ESP8266_NONOS_SDK_V2.0.0_16_08_10.zip
- unzip ESP8266_NONOS_SDK_V2.0.0_16_08_10.zip
- export SDK_BASE=$PWD/ESP8266_NONOS_SDK
- cd ..
script:
- ls
- cp include/user_config.sample.h include/user_config.local.h
- make
- cd firmware/
- srec_cat -output ${file_name} -binary esp_mqtt0x00000.bin -binary -fill 0xff 0x00000 0x10000 esp_mqtt0x10000.bin -binary -offset 0x10000
deploy:
provider: releases
api_key:
file: "$TRAVIS_BUILD_DIR/firmware/${file_name}"
skip_cleanup: true
on:
tags: true
repo: tuanpmt/esp_mqtt

16
.vscode/c_cpp_properties.json vendored 100644
Wyświetl plik

@ -0,0 +1,16 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [],
"compilerPath": "/usr/bin/gcc",
"cStandard": "c11",
"cppStandard": "c++17",
"intelliSenseMode": "clang-x64"
}
],
"version": 4
}

22
LICENSE 100644
Wyświetl plik

@ -0,0 +1,22 @@
The MIT License
Copyright (c) 2010-2016 Tuan PM - https://twitter.com/tuanpmt
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

107
Makefile
Wyświetl plik

@ -1,53 +1,53 @@
# Changelog
# Changed the variables to include the header file directory
# Added global var for the XTENSA tool root
#
# This make file still needs some work.
# Makefile for ESP8266 projects
#
# Thanks to:
# - zarya
# - Jeroen Domburg (Sprite_tm)
# - Christian Klippel (mamalala)
# - Tommie Gannert (tommie)
#
# Changelog:
# - 2014-10-06: Changed the variables to include the header file directory
# - 2014-10-06: Added global var for the Xtensa tool root
# - 2014-11-23: Updated for SDK 0.9.3
# - 2014-12-25: Replaced esptool by esptool.py
BUILD_AREA = $(CURDIR)/..
# Output directors to store intermediate compiled files
# relative to the project directory
BUILD_BASE = build
FW_BASE = firmware
FLAVOR = release
#FLAVOR = debug
# Base directory for the compiler
XTENSA_TOOLS_ROOT ?= c:/Espressif/xtensa-lx106-elf/bin
# base directory for the compiler
XTENSA_TOOLS_ROOT ?= $(BUILD_AREA)/esp-open-sdk/xtensa-lx106-elf/bin
# base directory of the ESP8266 SDK package, absolute
SDK_BASE ?= c:/Espressif/ESP8266_SDK
# # base directory of the ESP8266 SDK package, absolute
SDK_BASE ?= $(BUILD_AREA)/esp-open-sdk/sdk
#Esptool.py path and port
PYTHON ?= C:\Python27\python.exe
ESPTOOL ?= c:\Espressif\utils\esptool.py
ESPPORT ?= COM3
# # esptool.py path and port
ESPTOOL ?= $(BUILD_AREA)/esp-open-sdk/esptool/esptool.py
ESPPORT ?= /dev/ttyUSB0
# name for the target project
TARGET = app
# which modules (subdirectories) of the project to include in compiling
MODULES = driver user
EXTRA_INCDIR = include $(SDK_BASE)/../include
MODULES = driver user uMQTTBroker/src ntp easygpio pwm httpclient adc
#EXTRA_INCDIR = $(BUILD_AREA)/esp-open-sdk/esp-open-lwip/include include
EXTRA_INCDIR = include
LIB_MODULES = mqtt
# libraries used in this project, mainly provided by the SDK
LIBS = c gcc hal phy pp net80211 lwip wpa upgrade main ssl
LIBS = c gcc hal pp phy net80211 lwip wpa main ssl json
# compiler flags using during compilation of source files
CFLAGS = -Os -Wpointer-arith -Wundef -Werror -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -D__ets__ -DICACHE_FLASH
CFLAGS = -Os -ffunction-sections -fdata-sections -g -O2 -Wpointer-arith -Wundef -Werror -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -D__ets__ -DICACHE_FLASH -DUSE_OPTIMIZE_PRINTF -Desp8266
#-DMQTT_DEBUG_ON
# linker flags used to generate the main object file
LDFLAGS = -nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static
ifeq ($(FLAVOR),debug)
CFLAGS += -g -O0
LDFLAGS += -g -O0
endif
ifeq ($(FLAVOR),release)
CFLAGS += -g -O2
LDFLAGS += -g -O2
endif
LDFLAGS = -ffunction-sections -fdata-sections -Wl,-gc-sections -nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static
# linker script used for the above linkier step
LD_SCRIPT = eagle.app.v6.ld
@ -59,20 +59,19 @@ SDK_INCDIR = include include/json
# we create two different files for uploading into the flash
# these are the names and options to generate them
FW_FILE_1 = 0x00000
FW_FILE_1_ARGS = -bo $@ -bs .text -bs .data -bs .rodata -bc -ec
FW_FILE_2 = 0x40000
FW_FILE_2_ARGS = -es .irom0.text $@ -ec
FW_FILE_1_ADDR = 0x00000
FW_FILE_2_ADDR = 0x10000
# select which tools to use as compiler, librarian and linker
CC := $(XTENSA_TOOLS_ROOT)/xtensa-lx106-elf-gcc
AR := $(XTENSA_TOOLS_ROOT)/xtensa-lx106-elf-ar
LD := $(XTENSA_TOOLS_ROOT)/xtensa-lx106-elf-gcc
####
#### no user configurable options below here
####
FW_TOOL ?= $(XTENSA_TOOLS_ROOT)/esptool
SRC_DIR := $(MODULES)
BUILD_DIR := $(addprefix $(BUILD_BASE)/,$(MODULES))
@ -91,9 +90,8 @@ INCDIR := $(addprefix -I,$(SRC_DIR))
EXTRA_INCDIR := $(addprefix -I,$(EXTRA_INCDIR))
MODULE_INCDIR := $(addsuffix /include,$(INCDIR))
FW_FILE_1 := $(addprefix $(FW_BASE)/,$(FW_FILE_1).bin)
FW_FILE_2 := $(addprefix $(FW_BASE)/,$(FW_FILE_2).bin)
BLANKER := $(addprefix $(SDK_BASE)/,bin/blank.bin)
FW_FILE_1 := $(addprefix $(FW_BASE)/,$(FW_FILE_1_ADDR).bin)
FW_FILE_2 := $(addprefix $(FW_BASE)/,$(FW_FILE_2_ADDR).bin)
V ?= $(VERBOSE)
ifeq ("$(V)","1")
@ -109,20 +107,16 @@ vpath %.c $(SRC_DIR)
define compile-objects
$1/%.o: %.c
$(vecho) "CC $$<"
$(Q) $(CC) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CFLAGS) -c $$< -o $$@
$(Q) $(CC) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CFLAGS) -c $$< -o $$@
endef
.PHONY: all checkdirs clean
.PHONY: all checkdirs flash clean
all: checkdirs $(TARGET_OUT) $(FW_FILE_1) $(FW_FILE_2)
$(FW_FILE_1): $(TARGET_OUT)
$(vecho) "FW $@"
$(Q) $(FW_TOOL) -eo $(TARGET_OUT) $(FW_FILE_1_ARGS)
$(FW_FILE_2): $(TARGET_OUT)
$(vecho) "FW $@"
$(Q) $(FW_TOOL) -eo $(TARGET_OUT) $(FW_FILE_2_ARGS)
$(FW_BASE)/%.bin: $(TARGET_OUT) | $(FW_BASE)
$(vecho) "FW $(FW_BASE)/"
$(Q) $(ESPTOOL) elf2image -o $(FW_BASE)/ $(TARGET_OUT)
$(TARGET_OUT): $(APP_AR)
$(vecho) "LD $@"
@ -137,24 +131,13 @@ checkdirs: $(BUILD_DIR) $(FW_BASE)
$(BUILD_DIR):
$(Q) mkdir -p $@
firmware:
$(FW_BASE):
$(Q) mkdir -p $@
flash: firmware/0x00000.bin firmware/0x40000.bin
$(PYTHON) $(ESPTOOL) -p $(ESPPORT) write_flash 0x00000 firmware/0x00000.bin 0x3C000 $(BLANKER) 0x40000 firmware/0x40000.bin
test: flash
screen $(ESPPORT) 115200
rebuild: clean all
flash: $(FW_FILE_1) $(FW_FILE_2)
sudo $(ESPTOOL) --port $(ESPPORT) write_flash $(FW_FILE_1_ADDR) $(FW_FILE_1) $(FW_FILE_2_ADDR) $(FW_FILE_2)
clean:
$(Q) rm -f $(APP_AR)
$(Q) rm -f $(TARGET_OUT)
$(Q) rm -rf $(BUILD_DIR)
$(Q) rm -rf $(BUILD_BASE)
$(Q) rm -f $(FW_FILE_1)
$(Q) rm -f $(FW_FILE_2)
$(Q) rm -rf $(FW_BASE)
$(Q) rm -rf $(FW_BASE) $(BUILD_BASE)
$(foreach bdir,$(BUILD_DIR),$(eval $(call compile-objects,$(bdir))))

Wyświetl plik

@ -1,145 +0,0 @@
# Changelog
# Changed the variables to include the header file directory
# Added global var for the XTENSA tool root
#
# This make file still needs some work.
#
#
# Output directors to store intermediate compiled files
# relative to the project directory
BUILD_BASE = build
FW_BASE = firmware
# Base directory for the compiler
XTENSA_TOOLS_ROOT ?= /opt/Espressif/crosstool-NG/builds/xtensa-lx106-elf/bin
# base directory of the ESP8266 SDK package, absolute
SDK_BASE ?= /opt/Espressif/ESP8266_SDK
#Esptool.py path and port
ESPTOOL ?= esptool.py
ESPPORT ?= /dev/ttyUSB0
# name for the target project
TARGET = app
# which modules (subdirectories) of the project to include in compiling
MODULES = driver user
EXTRA_INCDIR = include $(SDK_BASE)/../include
# libraries used in this project, mainly provided by the SDK
LIBS = c gcc hal phy pp net80211 lwip wpa upgrade main ssl
# compiler flags using during compilation of source files
CFLAGS = -Os -g -O2 -Wpointer-arith -Wundef -Werror -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -D__ets__ -DICACHE_FLASH
# linker flags used to generate the main object file
LDFLAGS = -nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static
# linker script used for the above linkier step
LD_SCRIPT = eagle.app.v6.ld
# various paths from the SDK used in this project
SDK_LIBDIR = lib
SDK_LDDIR = ld
SDK_INCDIR = include include/json
# we create two different files for uploading into the flash
# these are the names and options to generate them
FW_FILE_1 = 0x00000
FW_FILE_1_ARGS = -bo $@ -bs .text -bs .data -bs .rodata -bc -ec
FW_FILE_2 = 0x40000
FW_FILE_2_ARGS = -es .irom0.text $@ -ec
# select which tools to use as compiler, librarian and linker
CC := $(XTENSA_TOOLS_ROOT)/xtensa-lx106-elf-gcc
AR := $(XTENSA_TOOLS_ROOT)/xtensa-lx106-elf-ar
LD := $(XTENSA_TOOLS_ROOT)/xtensa-lx106-elf-gcc
####
#### no user configurable options below here
####
FW_TOOL ?= /usr/bin/esptool
SRC_DIR := $(MODULES)
BUILD_DIR := $(addprefix $(BUILD_BASE)/,$(MODULES))
SDK_LIBDIR := $(addprefix $(SDK_BASE)/,$(SDK_LIBDIR))
SDK_INCDIR := $(addprefix -I$(SDK_BASE)/,$(SDK_INCDIR))
SRC := $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.c))
OBJ := $(patsubst %.c,$(BUILD_BASE)/%.o,$(SRC))
LIBS := $(addprefix -l,$(LIBS))
APP_AR := $(addprefix $(BUILD_BASE)/,$(TARGET)_app.a)
TARGET_OUT := $(addprefix $(BUILD_BASE)/,$(TARGET).out)
LD_SCRIPT := $(addprefix -T$(SDK_BASE)/$(SDK_LDDIR)/,$(LD_SCRIPT))
INCDIR := $(addprefix -I,$(SRC_DIR))
EXTRA_INCDIR := $(addprefix -I,$(EXTRA_INCDIR))
MODULE_INCDIR := $(addsuffix /include,$(INCDIR))
FW_FILE_1 := $(addprefix $(FW_BASE)/,$(FW_FILE_1).bin)
FW_FILE_2 := $(addprefix $(FW_BASE)/,$(FW_FILE_2).bin)
BLANKER := $(addprefix $(SDK_BASE)/,bin/blank.bin)
V ?= $(VERBOSE)
ifeq ("$(V)","1")
Q :=
vecho := @true
else
Q := @
vecho := @echo
endif
vpath %.c $(SRC_DIR)
define compile-objects
$1/%.o: %.c
$(vecho) "CC $$<"
$(Q) $(CC) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CFLAGS) -c $$< -o $$@
endef
.PHONY: all checkdirs clean
all: checkdirs $(TARGET_OUT) $(FW_FILE_1) $(FW_FILE_2)
$(FW_FILE_1): $(TARGET_OUT)
$(vecho) "FW $@"
$(Q) $(FW_TOOL) -eo $(TARGET_OUT) $(FW_FILE_1_ARGS)
$(FW_FILE_2): $(TARGET_OUT)
$(vecho) "FW $@"
$(Q) $(FW_TOOL) -eo $(TARGET_OUT) $(FW_FILE_2_ARGS)
$(TARGET_OUT): $(APP_AR)
$(vecho) "LD $@"
$(Q) $(LD) -L$(SDK_LIBDIR) $(LD_SCRIPT) $(LDFLAGS) -Wl,--start-group $(LIBS) $(APP_AR) -Wl,--end-group -o $@
$(APP_AR): $(OBJ)
$(vecho) "AR $@"
$(Q) $(AR) cru $@ $^
checkdirs: $(BUILD_DIR) $(FW_BASE)
$(BUILD_DIR):
$(Q) mkdir -p $@
firmware:
$(Q) mkdir -p $@
flash: firmware/0x00000.bin firmware/0x40000.bin
$(PYTHON) $(ESPTOOL) -p $(ESPPORT) write_flash 0x00000 firmware/0x00000.bin 0x3C000 $(BLANKER) 0x40000 firmware/0x40000.bin
test: flash
screen $(ESPPORT) 115200
clean:
$(Q) rm -f $(APP_AR)
$(Q) rm -f $(TARGET_OUT)
$(Q) rm -rf $(BUILD_DIR)
$(Q) rm -rf $(BUILD_BASE)
$(Q) rm -f $(FW_FILE_1)
$(Q) rm -f $(FW_FILE_2)
$(Q) rm -rf $(FW_BASE)
$(foreach bdir,$(BUILD_DIR),$(eval $(call compile-objects,$(bdir))))

246
Makefile.orig 100644
Wyświetl plik

@ -0,0 +1,246 @@
# none sdkota espboot rboot
OTA ?= none
OTA_APP_ADDR = 0x2000
OTA_BOOTLOADER_PATH = ../esp-bootloader/firmware/espboot.bin
THISDIR:=$(dir $(abspath $(lastword $(MAKEFILE_LIST))))
# Base directory for the compiler. Needs a / at the end; if not set it'll use the tools that are in
# the PATH.
XTENSA_TOOLS_ROOT ?=
# base directory of the ESP8266 SDK package, absolute
SDK_BASE ?= /home/martin/github/esp-open-sdk/sdk/
#Esptool.py path and port
ESPTOOL ?= /home/martin/github/esp-open-sdk/esptool/esptool.py
ESPPORT ?= /dev/ttyUSB0
#ESPPORT ?= /dev/tty.wchusbserial1410
#ESPDELAY indicates seconds to wait between flashing the two binary images
ESPDELAY ?= 3
#ESPBAUD ?= 115200
ESPBAUD ?= 460800
# 40m 26m 20m 80m
ESP_FREQ = 40m
# qio qout dio dout
ESP_MODE = dio
#4m 2m 8m 16m 32m
ESP_SIZE = 32m
VERBOSE = yes
FLAVOR = debug
# name for the target project
TARGET ?= esp_mqtt
# name for the target when compiling as library
TARGET_LIB ?= libmqtt.a
# which modules (subdirectories) of the project to include in compiling
USER_MODULES = user driver uMQTTBroker/src modules
USER_INC = include
USER_LIB =
# which modules (subdirectories) of the project to include when compiling as library
LIB_MODULES = uMQTTBroker/src
SDK_LIBDIR = lib
SDK_LIBS = c gcc phy pp net80211 wpa main lwip
# crypto ssl json driver
SDK_INC = include include/json
# Output directors to store intermediate compiled files
# relative to the project directory
BUILD_BASE = build
FIRMWARE_BASE = firmware
# Opensdk patches stdint.h when compiled with an internal SDK. If you run into compile problems pertaining to
# redefinition of int types, try setting this to 'yes'.
USE_OPENSDK ?= yes
DATETIME := $(shell date "+%Y-%b-%d_%H:%M:%S_%Z")
# select which tools to use as compiler, librarian and linker
CC := $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-gcc
AR := $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-ar
LD := $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-gcc
OBJCOPY := $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-objcopy
####
#### no user configurable options below here
####
SRC_DIR := $(USER_MODULES)
SRC_DIR_LIB := $(LIB_MODULES)
BUILD_DIR := $(addprefix $(BUILD_BASE)/,$(USER_MODULES))
INCDIR := $(addprefix -I,$(SRC_DIR))
EXTRA_INCDIR := $(addprefix -I,$(USER_INC))
MODULE_INCDIR := $(addsuffix /include,$(INCDIR))
SDK_LIBDIR := $(addprefix $(SDK_BASE)/,$(SDK_LIBDIR))
SDK_LIBS := $(addprefix -l,$(SDK_LIBS))
SDK_INCDIR := $(addprefix -I$(SDK_BASE)/,$(SDK_INC))
SRC := $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.c))
SRC_LIB := $(foreach sdir,$(SRC_DIR_LIB),$(wildcard $(sdir)/*.c))
ASMSRC = $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.S))
ASMSRC_LIB = $(foreach sdir,$(SRC_DIR_LIB),$(wildcard $(sdir)/*.S))
OBJ = $(patsubst %.c,$(BUILD_BASE)/%.o,$(SRC))
OBJ_LIB = $(patsubst %.c,$(BUILD_BASE)/%.o,$(SRC_LIB))
OBJ += $(patsubst %.S,$(BUILD_BASE)/%.o,$(ASMSRC))
OBJ_LIB += $(patsubst %.c,$(BUILD_BASE)/%.o,$(ASMSRC_LIB))
APP_AR := $(addprefix $(BUILD_BASE)/,$(TARGET).a)
TARGET_OUT := $(addprefix $(BUILD_BASE)/,$(TARGET).out)
# compiler flags using during compilation of source files
CFLAGS = -g \
-Wpointer-arith \
-Wundef \
-Wl,-EL \
-Wno-implicit-function-declaration \
-fno-inline-functions \
-nostdlib \
-mlongcalls \
-mtext-section-literals \
-ffunction-sections \
-fdata-sections \
-fno-builtin-printf\
-DICACHE_FLASH \
-DBUID_TIME=\"$(DATETIME)\"
# linker flags used to generate the main object file
LDFLAGS = -nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static
ifeq ($(FLAVOR),debug)
LDFLAGS += -g -O2
CFLAGS += -DMQTT_DEBUG_ON -DDEBUG_ON
endif
ifeq ($(FLAVOR),release)
LDFLAGS += -g -O0
endif
V ?= $(VERBOSE)
ifeq ("$(V)","yes")
Q :=
vecho := @true
else
Q := @
vecho := @echo
endif
ifeq ("$(USE_OPENSDK)","yes")
CFLAGS += -DUSE_OPENSDK
else
CFLAGS += -D_STDINT_H
endif
ifneq ("$(wildcard $(THISDIR)/include/user_config.local.h)","")
CFLAGS += -DLOCAL_CONFIG_AVAILABLE
endif
ESPTOOL_OPTS=--port $(ESPPORT) --baud $(ESPBAUD)
#32m
ESP_INIT_DATA_DEFAULT_ADDR = 0xfc000
ifeq ("$(ESP_SIZE)","16m")
ESP_INIT_DATA_DEFAULT_ADDR = 0x1fc000
else ifeq ("$(ESP_SIZE)","32m")
ESP_INIT_DATA_DEFAULT_ADDR = 0x3fc000
endif
ifeq ("$(OTA)","espboot")
OUTPUT := $(addprefix $(FIRMWARE_BASE)/,$(TARGET)-0x2000.bin)
ESPTOOL_WRITE = write_flash --flash_freq $(ESP_FREQ) --flash_mode $(ESP_MODE) --flash_size $(ESP_SIZE) \
0x00000 $(OTA_BOOTLOADER_PATH) \
$(OTA_APP_ADDR) $(OUTPUT) \
$(ESP_INIT_DATA_DEFAULT_ADDR) $(SDK_BASE)/bin/esp_init_data_default.bin
ESPTOOL_FLASHDEF=--version=2
LD_SCRIPT = -Tld/with-espboot-flash-at-0x2000-size-1M.ld
else
OUTPUT := $(addprefix $(FIRMWARE_BASE)/,$(TARGET))
ESPTOOL_WRITE = write_flash --flash_freq $(ESP_FREQ) --flash_mode $(ESP_MODE) --flash_size $(ESP_SIZE) \
0x00000 $(OUTPUT)0x00000.bin \
0x10000 $(OUTPUT)0x10000.bin \
$(ESP_INIT_DATA_DEFAULT_ADDR) $(SDK_BASE)/bin/esp_init_data_default.bin
ESPTOOL_FLASHDEF=
LD_SCRIPT = -T$(SDK_BASE)/ld/eagle.app.v6.ld
endif
OUTPUT_LIB := $(addprefix $(FIRMWARE_BASE)/,$(TARGET_LIB))
vpath %.c $(SRC_DIR)
define compile-objects
$1/%.o: %.c
$(vecho) "CC $$<"
$(Q) $(CC) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CFLAGS) -c $$< -o $$@
endef
.PHONY: all lib checkdirs clean
all: touch checkdirs $(OUTPUT)
lib: checkdirs $(OUTPUT_LIB)
touch:
$(vecho) "-------------------------------------------\n"
$(vecho) "BUID TIME $(DATETIME)"
$(vecho) "-------------------------------------------\n"
$(Q) touch user/user_main.c
checkdirs: $(BUILD_DIR) $(FIRMWARE_BASE)
$(OUTPUT): $(TARGET_OUT)
$(vecho) "FW $@"
$(Q) $(ESPTOOL) elf2image $(ESPTOOL_FLASHDEF) $< -o $(OUTPUT)
$(OUTPUT_LIB): $(OBJ_LIB)
$(vecho) "AR $@"
$(Q) $(AR) cru $@ $^
$(BUILD_DIR):
$(Q) mkdir -p $@
$(FIRMWARE_BASE):
$(Q) mkdir -p $@
$(TARGET_OUT): $(APP_AR)
$(vecho) "LD $@"
$(Q) $(LD) -L$(SDK_LIBDIR) $(LD_SCRIPT) $(LDFLAGS) -Wl,--start-group $(SDK_LIBS) $(APP_AR) -Wl,--end-group -o $@
$(APP_AR): $(OBJ)
$(vecho) "AR $@"
$(Q) $(AR) cru $@ $^
flash:
$(ESPTOOL) $(ESPTOOL_OPTS) $(ESPTOOL_WRITE)
fast: all flash openport
openport:
$(vecho) "After flash, terminal will enter serial port screen"
$(vecho) "Please exit with command:"
$(vecho) "\033[0;31m" "Ctrl + A + k" "\033[0m"
#@read -p "Press any key to continue... " -n1 -s
@screen $(ESPPORT) 115200
clean:
$(Q) rm -rf $(BUILD_DIR)
$(Q) rm -rf $(FIRMWARE_BASE)
$(foreach bdir,$(BUILD_DIR),$(eval $(call compile-objects,$(bdir))))

Wyświetl plik

@ -1,160 +0,0 @@
# Changelog
# Changed the variables to include the header file directory
# Added global var for the XTENSA tool root
#
# This make file still needs some work.
#
#
# Output directors to store intermediate compiled files
# relative to the project directory
BUILD_BASE = build
FW_BASE = firmware
FLAVOR = release
#FLAVOR = debug
# Base directory for the compiler
XTENSA_TOOLS_ROOT ?= c:/Espressif/xtensa-lx106-elf/bin
# base directory of the ESP8266 SDK package, absolute
SDK_BASE ?= c:/Espressif/ESP8266_SDK
#Esptool.py path and port
PYTHON ?= C:\Python27\python.exe
ESPTOOL ?= c:\Espressif\utils\esptool.py
ESPPORT ?= COM3
# name for the target project
TARGET = app
# which modules (subdirectories) of the project to include in compiling
MODULES = driver user
EXTRA_INCDIR = include $(SDK_BASE)/../include
# libraries used in this project, mainly provided by the SDK
LIBS = c gcc hal phy pp net80211 lwip wpa upgrade main ssl
# compiler flags using during compilation of source files
CFLAGS = -Os -Wpointer-arith -Wundef -Werror -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -D__ets__ -DICACHE_FLASH
# linker flags used to generate the main object file
LDFLAGS = -nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static
ifeq ($(FLAVOR),debug)
CFLAGS += -g -O0
LDFLAGS += -g -O0
endif
ifeq ($(FLAVOR),release)
CFLAGS += -g -O2
LDFLAGS += -g -O2
endif
# linker script used for the above linkier step
LD_SCRIPT = eagle.app.v6.ld
# various paths from the SDK used in this project
SDK_LIBDIR = lib
SDK_LDDIR = ld
SDK_INCDIR = include include/json
# we create two different files for uploading into the flash
# these are the names and options to generate them
FW_FILE_1 = 0x00000
FW_FILE_1_ARGS = -bo $@ -bs .text -bs .data -bs .rodata -bc -ec
FW_FILE_2 = 0x40000
FW_FILE_2_ARGS = -es .irom0.text $@ -ec
# select which tools to use as compiler, librarian and linker
CC := $(XTENSA_TOOLS_ROOT)/xtensa-lx106-elf-gcc
AR := $(XTENSA_TOOLS_ROOT)/xtensa-lx106-elf-ar
LD := $(XTENSA_TOOLS_ROOT)/xtensa-lx106-elf-gcc
####
#### no user configurable options below here
####
FW_TOOL ?= $(XTENSA_TOOLS_ROOT)/esptool
SRC_DIR := $(MODULES)
BUILD_DIR := $(addprefix $(BUILD_BASE)/,$(MODULES))
SDK_LIBDIR := $(addprefix $(SDK_BASE)/,$(SDK_LIBDIR))
SDK_INCDIR := $(addprefix -I$(SDK_BASE)/,$(SDK_INCDIR))
SRC := $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.c))
OBJ := $(patsubst %.c,$(BUILD_BASE)/%.o,$(SRC))
LIBS := $(addprefix -l,$(LIBS))
APP_AR := $(addprefix $(BUILD_BASE)/,$(TARGET)_app.a)
TARGET_OUT := $(addprefix $(BUILD_BASE)/,$(TARGET).out)
LD_SCRIPT := $(addprefix -T$(SDK_BASE)/$(SDK_LDDIR)/,$(LD_SCRIPT))
INCDIR := $(addprefix -I,$(SRC_DIR))
EXTRA_INCDIR := $(addprefix -I,$(EXTRA_INCDIR))
MODULE_INCDIR := $(addsuffix /include,$(INCDIR))
FW_FILE_1 := $(addprefix $(FW_BASE)/,$(FW_FILE_1).bin)
FW_FILE_2 := $(addprefix $(FW_BASE)/,$(FW_FILE_2).bin)
BLANKER := $(addprefix $(SDK_BASE)/,bin/blank.bin)
V ?= $(VERBOSE)
ifeq ("$(V)","1")
Q :=
vecho := @true
else
Q := @
vecho := @echo
endif
vpath %.c $(SRC_DIR)
define compile-objects
$1/%.o: %.c
$(vecho) "CC $$<"
$(Q) $(CC) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CFLAGS) -c $$< -o $$@
endef
.PHONY: all checkdirs clean
all: checkdirs $(TARGET_OUT) $(FW_FILE_1) $(FW_FILE_2)
$(FW_FILE_1): $(TARGET_OUT)
$(vecho) "FW $@"
$(Q) $(FW_TOOL) -eo $(TARGET_OUT) $(FW_FILE_1_ARGS)
$(FW_FILE_2): $(TARGET_OUT)
$(vecho) "FW $@"
$(Q) $(FW_TOOL) -eo $(TARGET_OUT) $(FW_FILE_2_ARGS)
$(TARGET_OUT): $(APP_AR)
$(vecho) "LD $@"
$(Q) $(LD) -L$(SDK_LIBDIR) $(LD_SCRIPT) $(LDFLAGS) -Wl,--start-group $(LIBS) $(APP_AR) -Wl,--end-group -o $@
$(APP_AR): $(OBJ)
$(vecho) "AR $@"
$(Q) $(AR) cru $@ $^
checkdirs: $(BUILD_DIR) $(FW_BASE)
$(BUILD_DIR):
$(Q) mkdir -p $@
firmware:
$(Q) mkdir -p $@
flash: firmware/0x00000.bin firmware/0x40000.bin
$(PYTHON) $(ESPTOOL) -p $(ESPPORT) write_flash 0x00000 firmware/0x00000.bin 0x3C000 $(BLANKER) 0x40000 firmware/0x40000.bin
test: flash
screen $(ESPPORT) 115200
rebuild: clean all
clean:
$(Q) rm -f $(APP_AR)
$(Q) rm -f $(TARGET_OUT)
$(Q) rm -rf $(BUILD_DIR)
$(Q) rm -rf $(BUILD_BASE)
$(Q) rm -f $(FW_FILE_1)
$(Q) rm -f $(FW_FILE_2)
$(Q) rm -rf $(FW_BASE)
$(foreach bdir,$(BUILD_DIR),$(eval $(call compile-objects,$(bdir))))

388
README.md
Wyświetl plik

@ -1,222 +1,250 @@
**esp_mqtt**
==========
This is MQTT client library for ESP8266, port from: [MQTT client library for Contiki](https://github.com/esar/contiki-mqtt) (thanks)
# esp_uMQTT_broker
An MQTT Broker/Client with scripting support on the ESP8266
**Features:**
This program enables the ESP8266 to become the central node in a small distributed IoT system. It implements an MQTT Broker and a simple scripted rule engine with event/action statements that links together the MQTT sensors and actors. It can act as STA, as AP, or as both and it can connect to another MQTT broker (i.e. in the cloud). Here it can also be bridge that forwards and rewrites topics in both directions. Also it can parse JSON structures, send basic HTTP GET requests and do basic I/O: i.e. read and write to local GPIO pins, react on timers and GPIO interrupts, drive GPIO pins with PWM, and read the ADC.
* Support subscribing, publishing, authentication, will messages, keep alive pings and all 3 QoS levels (it should be a fully functional client).
* Support multiple connection (to multiple hosts).
* Support SSL connection (max 1024 bit key size)
* Easy to setup and use
Find a video that explains the ideas and the architecture of the project at: https://www.youtube.com/watch?v=0K9q4IuB_oA
You can use the pure broker functionality (not the CLI and the scripting) in any ESP *Arduino* project as a libary by going to https://github.com/martin-ger/uMQTTBroker . Just clone (or download the zip-file and extract it) into the libraries directory of your Arduino ESP8266 installation.
# Usage
In the user directory there is the main program that serves as a stand-alone MQTT broker, client and bridge. The program starts with the following default configuration:
**Usage**
```c
#include "ets_sys.h"
#include "driver/uart.h"
#include "osapi.h"
#include "mqtt.h"
#include "wifi.h"
#include "config.h"
#include "debug.h"
#include "gpio.h"
#include "user_interface.h"
#include "mem.h"
- ap_ssid: MyAP, ap_password: none, ap_on: 1, ap_open: 1
- network: 192.168.4.0/24
MQTT_Client mqttClient;
This means it starts an open AP with ap_ssid MyAP. This default can be changed in the file user_config.h. The default can be overwritten and persistenly saved to flash by using a console interface. This console is available either via the serial port at 115200 baud or via tcp port 7777 (e.g. "telnet 192.168.4.1 7777" from a connected STA). It does not yet try to automatically re-connect to an uplink AP (as it does not know a valid ssid or password).
void wifiConnectCb(uint8_t status)
{
if(status == STATION_GOT_IP){
MQTT_Connect(&mqttClient);
}
}
void mqttConnectedCb(uint32_t *args)
{
MQTT_Client* client = (MQTT_Client*)args;
INFO("MQTT: Connected\r\n");
MQTT_Subscribe(client, "/mqtt/topic/0", 0);
MQTT_Subscribe(client, "/mqtt/topic/1", 1);
MQTT_Subscribe(client, "/mqtt/topic/2", 2);
Use the following commands for an initial setup:
MQTT_Publish(client, "/mqtt/topic/0", "hello0", 6, 0, 0);
MQTT_Publish(client, "/mqtt/topic/1", "hello1", 6, 1, 0);
MQTT_Publish(client, "/mqtt/topic/2", "hello2", 6, 2, 0);
- set ssid your_home_router's_SSID
- set password your_home_router's_password
- set ap_ssid ESP's_ssid
- set ap_password ESP's_password
- show (to check the parameters)
- save
- reset
}
After reboot it will try to automatically connect to your home router and itself as AP is ready for stations to connect.
void mqttDisconnectedCb(uint32_t *args)
{
MQTT_Client* client = (MQTT_Client*)args;
INFO("MQTT: Disconnected\r\n");
}
The console understands the following commands:
void mqttPublishedCb(uint32_t *args)
{
MQTT_Client* client = (MQTT_Client*)args;
INFO("MQTT: Published\r\n");
}
General commands:
void mqttDataCb(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t data_len)
{
char *topicBuf = (char*)os_zalloc(topic_len+1),
*dataBuf = (char*)os_zalloc(data_len+1);
- help: prints a short help message
- show [config|stats]: prints the current config or some status information and statistics
- save: saves the current config parameters to flash
- lock [_password_]: saves and locks the current config, changes are not allowed. Password can be left open if already set before
- unlock _password_: unlocks the config, requires password from the lock command
- reset [factory]: resets the esp, 'factory' optionally resets WiFi params to default values (works on a locked device only from serial console)
- set speed [80|160]: sets the CPU clock frequency (default 80 Mhz)
- set config_port _portno_: sets the port number of the console login (default is 7777, 0 disables remote console config)
- set config_access [0|1|2|3]: controls the networks that allow config access (0: no access, 1: only internal, 2: only external, 3: both (default))
- set bitrate [bps]: sets the serial bitrate (default 115200 bps)
- set system_output [0|1|2]: configures systems handling of the serial port (0: none/script, 1: cli commands/responses, 2: cli and info/warnings (default)). Mode 0 means, that any serial input is forwarded to the scripting engine if enabled
- quit: terminates a remote session
MQTT_Client* client = (MQTT_Client*)args;
WiFi and network related commands:
os_memcpy(topicBuf, topic, topic_len);
topicBuf[topic_len] = 0;
- set [ssid|password] _value_: changes the settings for the uplink AP (WiFi config of your home-router)
- set [ap_ssid|ap_password] _value_: changes the settings for the soft-AP of the ESP (for your stations)
- set ap_channel [1-13]: sets the channel of the SoftAP (default 1)
- set ap_on [0|1]: selects, whether the soft-AP is disabled (ap_on=0) or enabled (ap_on=1, default)
- set ap_open [0|1]: selects, whether the soft-AP uses WPA2 security (ap_open=0, automatic, if an ap_password is set) or open (ap_open=1)
- set auto_connect [0|1]: selects, whether the WiFi client should automatically retry to connect to the uplink AP (default: on=1)
- set network _ip-addr_: sets the IP address of the SoftAP's network, network is always /24, esp_uMQTT_broker is always x.x.x.1
- set dns _dns-addr_: sets a static DNS address
- set dns dhcp: configures use of the dynamic DNS address from DHCP, default
- set ip _ip-addr_: sets a static IP address for the ESP in the uplink network
- set ip dhcp: configures dynamic IP address for the ESP in the uplink network, default
- set netmask _netmask_: sets a static netmask for the uplink network
- set gw _gw-addr_: sets a static gateway address in the uplink network
- set dns_name _dnsname_: sets the DNS name of the uMQTTBroker (only for clients connected to the softAP) ("none" = disabled, default)
- set mdns_mode [0|1|2]: selects, which interface should be announced via mDNS (0: none (default), 1: STA, 2: SoftAP)
- scan: does a scan for APs
os_memcpy(dataBuf, data, data_len);
dataBuf[data_len] = 0;
While the user interface looks similar to my esp_wifi_repeater at https://github.com/martin-ger/esp_wifi_repeater this does NO NAT routing. AP and STA network are stricly separated and there is no routing in between. The only possible connection via both networks is the uMQTT broker that listens on both interfaces.
INFO("Receive topic: %s, data: %s \r\n", topicBuf, dataBuf);
os_free(topicBuf);
os_free(dataBuf);
}
MQTT broker related command:
- show [mqtt]: prints the current config or status information of the MQTT broker
- set broker_user _unsername_: sets the username for authentication of MQTT clients ("none" if no auth, default)
- set broker_password _password_: sets the password for authentication of MQTT clients ("none" if empty, default)
- set broker_port _portno_: sets the port number where the broker listens (default: 1883)
- set broker_access _mode_: controls the networks that allow MQTT broker access (0: no access, 1: only internal, 2: only external, 3: both (default))
- set broker_subscriptions _max_: sets the max number of subscription the broker can store (default: 30)
- set broker_retained_messages _max_: sets the max number of retained messages the broker can store (default: 30)
- set broker_clients _clients_max_: sets the max number of concurrent client connections (default: 0 = mem is the only limit)
- save_retained: saves the current state of all retained topics (max. 4096 Bytes in sum) to flash, so they will persist a reboot
- delete_retained: deletes the state of all retained topics in RAM and flash
- set broker_autoretain [0|1]: selects, whether the broker should do a "save_retained" automatically each time it receives a new retained message (default off). With this option on the broker can be resetted at any time without loosing state. However, this is slow and too many writes may damage flash mem.
void user_init(void)
{
uart_init(BIT_RATE_115200, BIT_RATE_115200);
os_delay_us(1000000);
# MQTT client/bridging functionality
The broker comes with a "local" and a "remote" client, which means, the broker itself can publish and subscribe topics. The "local" client is a client to the own broker (without the need of an additional TCP connection).
CFG_Load();
By default the "remote" MQTT client is disabled. It can be enabled by setting the config parameter "mqtt_host" to a hostname different from "none". To configure the "remote" MQTT client you can set the following parameters:
MQTT_InitConnection(&mqttClient, sysCfg.mqtt_host, sysCfg.mqtt_port, sysCfg.security);
//MQTT_InitConnection(&mqttClient, "192.168.11.122", 1880, 0);
- set mqtt_host _IP_or_hostname_: IP or hostname of the MQTT broker ("none" disables the MQTT client)
- set mqtt_user _username_: Username for authentication ("none" if no authentication is required at the broker)
- set mqtt_user _password_: Password for authentication
- set mqtt_ssl [0|1]: Use SSL for connection to the remote broker (default: 0 = off)
- set mqtt_id _clientId_: Id of the client at the broker (default: "ESPRouter_xxxxxx" derived from the MAC address)
- publish [local|remote] _topic_ _data_ [retained]: this publishes a topic (mainly for testing)
MQTT_InitClient(&mqttClient, sysCfg.device_id, sysCfg.mqtt_user, sysCfg.mqtt_pass, sysCfg.mqtt_keepalive, 1);
//MQTT_InitClient(&mqttClient, "client_id", "user", "pass", 120, 1);
The remote MQTT server can be accessed via SSL, e.g. a secure test connection to test.mosquitto.org can be configured as following:
```
CMD>set mqtt_host test.mosquitto.org
CMD>set mqtt_port 8883
CMD>set mqtt_ssl 1
CMD>save
CMD>reset
```
Certificate checks are not yet implemented.
MQTT_InitLWT(&mqttClient, "/lwt", "offline", 0, 0);
MQTT_OnConnected(&mqttClient, mqttConnectedCb);
MQTT_OnDisconnected(&mqttClient, mqttDisconnectedCb);
MQTT_OnPublished(&mqttClient, mqttPublishedCb);
MQTT_OnData(&mqttClient, mqttDataCb);
# Scripting
The esp_uMQTT_broker comes with a build-in scripting engine. A script enables the ESP not just to act as a passive broker but to react on events (publications and timing events), to send out its own items and handle local I/O. Details on syntax and semantics of the scripting language can be found here: https://github.com/martin-ger/esp_mqtt/blob/master/SCRIPTING.md . Examples of scripts are in the "scripts" directory.
WIFI_Connect(sysCfg.sta_ssid, sysCfg.sta_pwd, wifiConnectCb);
The script specific CLI commands are:
INFO("\r\nSystem started ...\r\n");
}
- script [_portno_|url|delete]: opens port for upload of scripts, downloads a script from an URL, or just deletes the current one
- show script [_line_no_]: dumps the currently active script starting with the given line (dumpy only about 1 KB, repeat command for more lines)
- set @[num] _value_: sets the flash variable "num" (for use in scripts) to the given inital value (must be shorter than 63 chars)
- set pwm_period _period_: sets the PWM period in terms of 200ns slots (default: 5000, = 0.1ms ^= 1KHz)
- show vars: dumps all variables of the current program incl. the persistent flash variables
Debug commands:
- set script_logging [0|1]: switches logging of script execution on or off (not permanently stored in the configuration)
- set backlog _buffersize_: sets the size of the backlog buffer (0 = backlog off, default, not permanently stored in the configuration)
- show backlog: dumps the backlog to the remote console
The backlog buffer stores the most recent console outputs of the running script and the CLI. If you detect an error situation you can log into the remote console and dump the recent output with "show backlog".
Scripts with size up to 4KB are uploaded to the esp_uMQTT_broker using a network interface.
There are two options to upload a script:
## Script Pull (http)
For this, you first have to make the scripts available via a web server. A quite simple way to do that is to start a minimal web server in the "scripts" directory, i.g. on Linux you can start a server on port 8080 on the delevopment machine with:
```
$ cd scripts
python -m SimpleHTTPServer 8080
```
Another way of course is to upload the script to a real server somewhere on the web.
Then start the download with the command "script <url>" on the concole of the ESP, e.g. like this with the correct hostname and port:
```
CMD>script http://myserver:8080/scripts/script.new
HTTP request to myserver:8080/scripts/script.new started
HTTP script download completed (330 Bytes)
Syntax okay
CMD>
```
You can also download over the internet, e.g. directly from github:
```
CMD>script https://raw.githubusercontent.com/martin-ger/esp_mqtt/master/scripts/script.pwm
HTTP request to https://raw.githubusercontent.com/martin-ger/esp_mqtt/master/scripts/script.pwm started
HTTP script download completed (749 Bytes)
Syntax okay
CMD>
```
The ESP tries to download the script from the given URL and prints upon success or failure a report on the console.
## Script Push (netcat)
Another option is to upload the script as plain TCP stream. Start the upload with "script <portno>" on the console of the ESP, e.g.:
```
CMD>script 2000
Waiting for script upload on port 2000
CMD>
```
**Publish message and Subscribe**
```c
/* TRUE if success */
BOOL MQTT_Subscribe(MQTT_Client *client, char* topic, uint8_t qos);
BOOL MQTT_Publish(MQTT_Client *client, const char* topic, const char* data, int data_length, int qos, int retain);
Now the ESP listens on the given port for an incoming connection and stores anything it receives as new script. Upload a file using netcat, e.g.:
```bash
$ netcat 192.168.178.29 2000 < user/demo_script2
```
The ESP will store the file and immediatly checks the syntax of the script:
```
CMD>script 2000
Waiting for script upload on port 2000
Script upload completed (451 Bytes)
Syntax okay
CMD>
```
**Already support LWT: (Last Will and Testament)***
You can examine the currently loaded script using the "show script" command. It only displays about 1KB of a script. If you need to see more, use "show script <line_no>" with a higher starting line. Newly loaded scripts are stored persistently in flash and will be executed after next reset if they contain no syntax errors. "script delete" stops script execution and deleted a script from flash.
```c
# NTP Support
NTP time is supported and accurate timestamps are available if the sync with an NTP server is done. By default the NTP client is enabled and set to "1.pool.ntp.org". It can be changed by setting the config parameter "ntp_server" to a hostname or an IP address. An ntp_server of "none" will disable the NTP client. Also you can set the "ntp_timezone" to an offset from GMT in hours. The system time will be synced with the NTP server every "ntp_interval" seconds. Here it uses NOT the full NTP calculation and clock drift compensation. Instead it will just set the local time to the latest received time.
/* Broker will publish a message with qos = 0, retain = 0, data = "offline" to topic "/lwt" if client don't send keepalive packet */
MQTT_InitLWT(&mqttClient, "/lwt", "offline", 0, 0);
After NTP sync has been completed successfully once, the local time will be published every second under the topic "$SYS/broker/time" in the format "hh:mm:ss". You can also query the NTP time using the "time" command from the commandline.
- set ntp_server _IP_or_hostname_: sets the name or IP of an NTP server (default "1.pool.ntp.org", "none" disables NTP)
- set ntp_interval _interval_: sets the NTP sync interval in seconds (default 300)
- set ntp_timezone _tz_: sets the timezone in hours offset (default 0)
- time: prints the current time as ddd hh:mm:ss
If you don't have internet access but still need a time base e.g. for your script, you can set the time manually (be aware that the local timer of the ESP has a significant drift):
- set ntp_time _hh:mm:ss_: sets the NTP time manually
- set ntp_weekday _ddd_: sets the current day of week ("Mon"-"Sun")
# DNS
A simple DNS responder is included, so an MQTT client connected to the AP interface might also use a name instead of the IP. Any valid domain name can be configured (shorter than 31 chars).
- set dns_name _dnsname_: sets the DNS name of the uMQTTBroker (only for clients connected to the softAP) ("none" = disabled, default)
# mDNS
mDNS is supported and depending on "mdns_mode" the broker responds on the name "mqtt.local" with one of its two addresses:
- set mdns_mode [0|1|2]: selects, which interface address should be announced via mDNS (0=none (default), 1 = STA, 2 = SoftAP)
# Building and Flashing
The code can be used in any project that is compiled using the NONOS_SDK or the esp-open-sdk. Also the complete broker in the user directory can be build using the standard SDKs after adapting the variables in the Makefile.
Download the repository using
```bash
$ git clone --recursive https://github.com/martin-ger/esp_mqtt.git
```
**Default configuration**
See: *include/user_config.h* and *include/config.c*
If you want to load new default configurations, just change the value of CFG_HOLDER in ***include/user_config.h***
Now in the Makefile, it will erase section hold the user configuration at 0x3C000
Configure the build options in "user_config.h", then build the esp_uMQTT_broker firmware with "make". "make flash" flashes it onto an esp8266.
If you want to use the precompiled binaries from the firmware directory you can flash them directly on an ESP8266, e.g. with
```bash
flash: firmware/0x00000.bin firmware/0x40000.bin
$(PYTHON) $(ESPTOOL) -p $(ESPPORT) write_flash 0x00000 firmware/0x00000.bin 0x3C000 $(BLANKER) 0x40000 firmware/0x40000.bin
$ esptool.py --port /dev/ttyUSB0 write_flash -fs 32m 0x00000 firmware/0x00000.bin 0x10000 firmware/0x10000.bin
```
On Windows you can flash it using the "ESP8266 Download Tool" available at https://espressif.com/en/support/download/other-tools. Download the two files 0x00000.bin and 0x10000.bin from the firmware directory. For a generic ESP12, a NodeMCU or a Wemos D1 use the following settings (for an ESP-01 change FLASH SIZE to "8Mbit"):
**Create SSL Self sign**
<img src="https://raw.githubusercontent.com/martin-ger/esp_wifi_repeater/5127c917cea012d2d9575d617fd7cecfa16375e5/FlashRepeaterWindows.jpg">
## Known Issues
If "QIO" mode fails on your device, try "DIO" instead. Also have a look at the "Detected Info" to check size and mode of the flash chip. If your downloaded firmware still doesn't start properly, please check with the enclosed checksums whether the binary files are possibly corrupted.
# The MQTT broker library
The library code has been moved to a separate repository at https://github.com/martin-ger/uMQTTBroker and is included recursivly.
It can be integrated into any NONOS SDK (or esp-open-sdk) program ("make -f Makefile.orig lib" will build the mqtt code as a C library). You can find a minimal NONOS SDK sample in the directory "user_basic" in this repository. Rename it to "user", adapt "user_config.h", and do the "make" to build a small demo that just starts an MQTT broker without any additional logic.
The broker is started by simply including:
```c
#include "mqtt/mqtt_server.h"
```
openssl req -x509 -newkey rsa:1024 -keyout key.pem -out cert.pem -days XXX
and then calling
```c
bool MQTT_server_start(uint16_t portno, uint16_t max_subscriptions, uint16_t max_retained_topics);
```
in the "user_init()" (or Arduino "setup()") function. Now it is ready for MQTT connections on all activated interfaces (STA and/or AP). Please note, that the lib uses two tasks (with prio 1 and 2) for client and broker. Thus, only task with prio 0 is left for a user application.
**SSL Mqtt broker for test**
```javascript
var mosca = require('mosca')
var SECURE_KEY = __dirname + '/key.pem';
var SECURE_CERT = __dirname + '/cert.pem';
var ascoltatore = {
//using ascoltatore
type: 'mongo',
url: 'mongodb://localhost:27017/mqtt',
pubsubCollection: 'ascoltatori',
mongo: {}
};
# Limitations on the number of clients
To adjust memory consumption of one MQTT connection and thus the max number of concurrent connections you can redefine MQTT_BUF_SIZE and QUEUE_BUFFER_SIZE in "user_config.h". MQTT_BUF_SIZE is the max. size of pending inbound messages for one connection (and thus also the max. size of a single MQTT message) and QUEUE_BUFFER_SIZE is the max. size of all pending outbound messages for one connection. Currently these parameters are set to 1024 resp. 2048 bytes, resulting in a memory consumption of about 4 KB per connection and a max number of connections of about 8-9 (depending on the memory usage of the rest of the program). When you reduce buffer sizes, e.g. to 512 and 1024 bytes, a single connection requires only about 2.5 KB resulting in up to 13 possible concurrent MQTT connections. In any case you have to increase the number of TCP connections (default 5) first by calling "espconn_tcp_set_max_con(n)" with n, the max. number of concurrent TCP connections, less or equal to 15.
var moscaSettings = {
port: 1880,
stats: false,
backend: ascoltatore,
persistence: {
factory: mosca.persistence.Mongo,
url: 'mongodb://localhost:27017/mqtt'
},
secure : {
keyPath: SECURE_KEY,
certPath: SECURE_CERT,
port: 1883
}
};
Also there is a hard limitation on the number of STAs connected to the SoftAP, which is 8. I.e. when using the esp_uMQTT_broker only with clients via the SoftAP interface, even with reduced memory consumtion, the limit of different client nodes is still 8, as it is imposed by the binary WiFi driver. Only when used via the STA interface and an external AP you can connect more than 8 MQTT clients.
var server = new mosca.Server(moscaSettings);
server.on('ready', setup);
server.on('clientConnected', function(client) {
console.log('client connected', client.id);
});
// fired when a message is received
server.on('published', function(packet, client) {
console.log('Published', packet.payload);
});
// fired when the mqtt server is ready
function setup() {
console.log('Mosca server is up and running')
}
```
**Be careful:** This library is not fully supported for too long messages.
**Status:** *Alpha release.*
[MQTT Broker for test](https://github.com/mcollina/mosca)
[MQTT Client for test](https://chrome.google.com/webstore/detail/mqttlens/hemojaaeigabkbcookmlgmdigohjobjm?hl=en)
**Contributing:**
***Feel free to contribute to the project in any way you like!***
**Requried:**
esp_iot_sdk_v0.9.4_14_12_19
**Authors:**
[Tuan PM](https://twitter.com/TuanPMT)
**Donations**
Invite me to a coffee
[![Donate](https://www.paypalobjects.com/en_US/GB/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=JR9RVLFC4GE6J)
**LICENSE - "MIT License"**
Copyright (c) 2014-2015 Tuan PM, https://twitter.com/TuanPMT
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# Thanks
- pfalcon for esp_open_sdk (best with NONOS SDK V2.2 patches - https://github.com/xxxajk/esp-open-lwip)
- tuanpmt for esp_mqtt (https://github.com/tuanpmt/esp_mqtt )
- eadf for esp8266_easygpio (https://github.com/eadf/esp8266_easygpio )
- Stefan Brüns for ESP8266_new_pwm (https://github.com/StefanBruens/ESP8266_new_pwm )
- Martin d'Allens for esphttpclient (https://github.com/Caerbannog/esphttpclient )
- Moritz Warning for SimpleDNS (https://github.com/mwarning/SimpleDNS )
- Ian Craggs for mqtt_topic
- many others contributing to open software (for the ESP8266)

435
SCRIPTING.md 100644
Wyświetl plik

@ -0,0 +1,435 @@
Scripting Language
==================
The scripting language of the esp_uMQTT_broker is stricly event based. It mainly consists of "on _event_ do _action_" clauses. An event can be:
- the reception of an MQTT item,
- the sucessful connection to an external MQTT broker,
- the sucessful connect to the WiFi network
- an expiring timer,
- a predefined time-of-day,
- a GPIO interrupt,
- an HTTP response, and
- the initialization of the system.
An action can be a sequence of:
- subscriptions on MQTT topics,
- publication of MQTT topics,
- timer settings,
- I/O on the GPIOs,
- manipulation of variables, and
- output on the command line.
The scripting language assumes that there *can* be two MQTT brokers: the _local_ one on the ESP8266 and/or a _remote_ one another node. The connection to the local broker is always present, the connection to the remote broker must be established via the configuration of the esp_uMQTT_broker. Neither one must be used, scripts can also work without MQTT, but the real intention of the language is to provide an easy way to react on received topics and, if required, to forward or rewrite topics from one broker to the other.
## Syntax
In general, scripts conform to the following BNF:
```
<statement> ::= on <event> do <action> |
config <param> ([any ASCII]* | @<num>) |
<statement> <statement>
<event> ::= init |
wificonnect | wifidisconnect |
mqttconnect |
timer <num> |
alarm <num> |
topic (local|remote) <topic-id> |
gpio_interrupt <num> (pullup|nopullup) |
serial |
http_response
<action> ::= publish (local|remote) <topic-id> <expr> [retained] |
subscribe (local|remote) <topic-id> |
unsubscribe (local|remote) <topic-id> |
settimer <num> <expr> |
setalarm <num> <expr> |
setvar ($[any ASCII]* | @<num>) = <expr> |
http_get <expr> |
http_post <expr> <expr> |
gpio_pinmode <num> (input|output) [pullup] |
gpio_out <num> <expr> |
gpio_pwm <num> <num> |
serial_out <expr> |
if <expr> then <action> [else <action>] endif |
while <expr> do <action> done |
print <expr> | println <expr> |
system <expr> |
<action> <action>
<expr> ::= <val> | <val> <op> <expr> | (<expr>) | not (<expr>) |
retained_topic(<expr>) | substr(<expr>,<num>,<num>) |
binary (<expr>) | byte_val(<expr>,<num>) |
csvstr(<expr>,<num>,<char>) | eatwhite (<expr>) |
json_parse (<expr>,<expr>)
<op> := '=' | '>' | gte | str_ge | str_gte | '+' | '-' | '*' | '|' | div
<val> := <string> | <const> | #<hex-string> | $[any ASCII]* | @<num> |
gpio_in(<num>) | $adc | $this_item | $this_data | $this_serial |
$this_gpio | $timestamp | $weekday |
$this_http_code | $this_http_host | $this_http_path | $this_http_body
<string> := "[any ASCII]*" | [any ASCII]*
<num> := [0-9]*
```
## Statements
```
on <event> do <action>
```
Whenever the _event_ occurs, the _action_ is executed. This is the basic form for all activities defined in a script.
```
config <param> ([any ASCII]* | @<num>)
```
These aditional statements are executed once right after startup. Typically, they should be located at the beginning of a script, but this is not required. The _param_ is any configuration parameter that can be set via the CLI of the esp_uMQTT_broker, e.g. the _ssid_ or the _password_ of the uplink WiFi AP. Basically, "config _x_ _y_" means the same as "set _x_ _y_" on the CLI. But all parameters defined in _config_ statements override the manually configured values in the CLI. Thus a script can contain its own network, MQTT, and security configuration. Instead of constant values also flash variables are allowed (see below). This can be used to configure node specific values, like an id or an address.
## Events
```
init
```
This event happens once after restart of the script. All "config" parameters are applied, but typically WiFi is not yet up and no external nodes are connected. This is typically the clause where the initalization of variables and timers as well as subscriptions to topics on the local broker take place.
```
wificonnect | wifidisconnect
```
This event happens each time, the esp_uMQTT_broker (re-)connects as client to the WiFi and has received an IP address, resp. if it disconnects (tyically due to link loss).
```
mqttconnect
```
This event happens each time, the MQTT *client* module (re-)connects to an external broker. This is typically the clause where subscriptions to topics on this broker are done (must be re-done after a connection loss anyway).
```
topic (local|remote) <topic-id>
```
This event happens when a matching topic has been received from one broker, either from the local or the remote one. The _topic-id_ may contain the usual MQTT wildcards '+' or '#'. The actual topic-id of the message can be accessed in the actions via the special variable _$this_topic_, the content of the message via the special variable _$this_data_. These variables are only defined inside the "on topic" clause. If the script needs these values elsewhere, they have to be saved in other variables.
```
timer <num>
```
This event happens when the timer with the given number expires. Timers are set in millisecond units, but their expiration might be delayed by other interrupts and events, e.g. network traffic. Thus their accuracy is limited. Timers are not reloading automatically. I.e. if you need a permanently running timer, reload the expired timer in the "on timer" clause.
```
alarm <num>
```
This event happens when the time-of-day stored in the alarm with the given number is reached. It happens once per day. Alarm times are given as "hh:mm:ss" and are only available if NTP is enabled. Make sure to set the correct "ntp_timezone" to adjust UTC to your location.
```
serial
```
This event happens when the "system_output" mode is set to 0 and a newline (NL)-terminated string has been received from the serial input. Instead of interpreting it as cli command it is forwarded to the scripting engine. The input value witout the trailing newline char is availabe via the special variable _$this_serial_.
```
gpio_interrupt <num> (pullup|nopullup)
```
This event happens when the GPIO pin with the given number generates an interrupt. An interrupt happens on each state change, i.e. a 0-1-0 sequence will cause two events. Use the special variable _$this_gpio_ to access the actual state of the pin. This variable is only defined inside the "on topic" clause. The interrupt mechanism uses a 50ms delay for debouncing the input. This means this event is suitable for switches, not for high-frequency signals. The "pullup" or "nopullup" defines whether the input pin is free floating or internally pulled to high level.
```
http_response
```
This event happens when an HTTP-request has been sent with "http_get" or "http_post" and a response arrives. The actual body of the response can be accessed in the actions via the special variable _$this_http_body_, the HTTP return code via the special variable _$this_http_code_. To identify responses from multiple requests the special variables _$this_http_host_ and _$this_http_path_ can be tested. They contain the host and the path of the request. All these variables are only defined inside the "on http_response" clause.
## Actions
```
publish (local|remote) <topic-id> <expr> [retained]
```
Publishs an MQTT topic to either the local or the remote broker. The "topic-id" must be a valid MQTT topic without wildcards, the "expr" can be any value. A string will be published without null-termination. If the optional "retained" is given, the topic will be published with the retained-flag, i.e. the broker will permanently store this topic/value until it is overwritten by a new value.
```
subscribe (local|remote) <topic-id> |
unsubscribe (local|remote) <topic-id>
```
Subscribes or unsubscribes a topic either at the local or at the remote broker. The _topic-id_ may contain the usual MQTT wildcards '+' or '#'. Without prior subscription no "on topic" events can happen.
```
settimer <num> <expr>
```
(Re-)initializes the timer "num" with a value given in milliseconds. Timers are not reloading automatically. I.e. if you need a permanently running timer, reload the expired timer in the "on timer" clause.
```
setalarm <num> <expr>
```
(Re-)initializes the alarm "num" with a value given as "hh:mm:ss" (it can also be just "hh:mm" or even "hh"). Alarm values are compared lexicographically with the current clock time.
```
setvar ($[any ASCII]* | @<num>) = <expr>
```
Sets a variable to a given value. All variable names start with a '$'. Variables are not typed and a handled like strings. Whenever a numerical value is need, the contents of a variable is interpreted as an integer number. If a boolean value is required, it tested, whether the string evaluates to zero (= false) or any other value (= true).
Currently the interpreter is configured for a maximum of 10 variables, with a significant id length of 15. In addition, there are currently 8 flash variables (up to 63 chars long) that do preserve their state even after reset or power down. These variables are named @1 to @8. Writing these variables is very slow as this includes a flash sector clear and rewrite cycle. Thus, these variables should be written only when relevant state should be saved. Reading these vars is faster.
Flash variables can also be used for storing config parameters or handing them over from the CLI to a script. They can be set with the "set @[num] _value_" on the CLI and the written values can then be picked up by a script to read e.g. config parameters like DNS names, IPs, node IDs or username/password.
```
http_get <expr>
```
Sends an HTTP GET request to the URL given in the expression.
```
http_post <expr> <expr>
```
Sends an HTTP POST request to the URL given in the first expression with the post data from the second expression.
```
gpio_pinmode <num> (input|output) [pullup]
```
Defines the status of a GPIO pin. This is only required for input pins, that are not used in "gpio_interrupt" events. The status of these pins can be accessed via the "gpio_in()" expression. It is optional for output and PWM pins as these are configured automatically as soon as an output command is given. The optional "pullup" defines whether the input pin is free floating or internally pulled to high level.
```
gpio_out <num> <expr>
```
Sets GPIO pin num to the given boolean value.
```
gpio_pwm <num> <num>
```
Defines the GPIO pin num as PWM output and sets the PWM duty cycle to the given value. The value should be in the range from 0-1000 (0 = off, 1000 = full duty). By default the PWM frequency is 1000Hz. It can be changed with the _pwm_period_ config parameter.
```
serial_out <expr>
```
Sends the given expression to serial port.
```
system <expr>
```
Executes the given expression as if it has been issued on the CLI. Useful e.g. for "save", "lock" or "reset" commands.
```
print <expr> |
println <expr>
```
Prints the given expression to serial or a connected remote console (either with or without trailing line break).
```
if <expr> then <action> [else <action>] endif
```
Classic "if then else" expression. Sequences of actions must be terminated with the (optional) "else" and the "endif". Can be nested.
```
while <expr> do <action> done
```
Classic "while" loop. Can be nested. Make sure that loops terminate quickly (about a second) to avoid a watchdog timeout reset.
## Expressions
Expressions evaluate to a (string) value. A single constant, a string, or a variable are the basic expressions. Expressions can be combined by operators. If more than one operator is used in an expression, all expressions are stricly evaluated from left to right. CAUTION: arithmetical preceedence does not (yet) apply automatically like in other programming languages. However, the preceedence can be fully controlled by brackets.
```
not(<expr>)
```
Interpretes the argument expression as boolean and inverts the result.
```
retained_topic(<expr>)
```
Interpretes the argument as topic name (incl. wildcards) and searches the first local retained topic that matches this name. The stored value of this topic is returned (empty, if nothing found). Can be used to check the status of the system synchronously without the need to subscribe for that retained topic, wait for status changes and store them in a variable.
```
binary(<expr>)
```
Converts the numerical value of the given expression into a single character string, e.g. binary(65) is "A".
```
byte_val(<expr>,<num>)
```
Converts the byte at the given position of a string (first is postion 0) into a numerical value, e.g. byte_val("ABC", 0) is "65".
```
substr(<expr>,<num>,<num>)
```
Extracts characters from a string. The two constant numbers give the starting position (first is postion 0) and the length. If the starting position is negative (write it with colons as e.g. "-2"), it counts backwards from the end of the string.
```
csvstr(<expr>,<num>,<char>)
```
Extracts strings from a CSV-list (correctly a string with a delimiter character). The constant number gives the position (first is postion 0) and the char is the delimiter. Examples: csvstr("one,two,three", 1, ",") is "two", csvstr("system/test/1", 0, "/") is "system".
```
eatwhite(<expr>)
```
Eliminates all whitespaces from a string.
```
json_parse (<expr>,<expr>)
```
Parses a JSON structure. The first argument expression is interpreted as JSON path, i.g. a string with names or numbers separated by "." characters. The second argument expression is interpreted as a JSON structure and the result of the expression is the data field of the JSON structure that is identified by the path (or an empty string if not found).
Example - give in the variable $json the following JSON structure:
```
{
"name":
{ "first":"John",
"last":"Snow" }
"age":30,
"cars":[ "Ford", "BMW", "Fiat" ]
}
```
"json_parse("name.first", $json)" results in "John", "json_parse("cars.1", $json)" results in "BMW".
## Values
A constant, a string, or a variable are values. Optionally, strings and constans can be put in quotes, like e.g. "A String" or "-10". This is especially useful for strings containing a whitespace or an operator. Any single character can be quotet using the '\\' escape character, like e.g. A\ String (equals "A String").
Other value terms are:
```
#<hex-string>
```
A value given as hex value in multiples of two hex-digit value, e.g. "#fffeff1a". With this notation binary and even NULL characters can be defined e.g. for MQTT publication data.
Some (additional) vars contain special status: $this_topic and $this_data are only defined in 'on topic' clauses and contain the current topic and its data. $this_gpio contains the state of the GPIO in an 'on gpio_interrupt' clause and $timestamp contains the current time of day in 'hh:mm:ss' format. If no NTP sync happened the time will be reported as "99:99:99". The variable "$weekday" returns the day of week as three letters ("Mon","Tue",...).
```
gpio_in(<num>)
```
Reads the current boolean input value of the given GPIO pin. This pin has to be defined as input before using the "gpio_pinmode" action.
```
$adc | $this_item | $this_data | $this_serial | $this_gpio | $timestamp | $weekday |
$this_http_host | $this_http_path | $this_http_code | $this_http_body
```
Special variables:
- $adc gives you the current value of the ADC (analog to digital input pin)
- $this_topic and $this_data are only defined in "on topic" clauses and contain the current topic and its data.
- $this_serial contains the serial input string in an "on serial" clause.
- $this_gpio contains the state of the GPIO in an "on gpio_interrupt" clause.
- $timestamp contains the current time of day in "hh:mm:ss" format. If no NTP sync happened the time will be reported as "99:99:99". $weekday returns the day of week as three letters ("Mon","Tue",...).
- $this_http_code, $this_http_host, $this_http_path, and $this_http_body are only defined inside the "on http_response" clause and contain the HTTP return code, the URL host and path of the request, and the body of an HTTP response.
## Operators
Operators are used to combine values and expressions.
```
'=' | '>' | gte | str_ge | str_gte
```
These operators result in boolean values and are typically used in comparisons in "if" clauses. "gte" means "greater or equal". The smaller operators are not required, as they can be replaced by the greater operators and swapping the values. "str_ge" and "str_gte" also do a greater comparison, but as the former operators compare numerical values, these do a lexicographical comparison, i.e. "11" is lexicographically greater than "012".
```
'+' | '-' | '*' | div
```
These operators are the arithmetical operations. CAUTION: arithmetical preceedence does not (yet) apply automatically, all expressions are evaluated from left to right. I.e. "2+3\*4" evaluates to 20 instead of 14. However, the preceedence can be fully controlled by brackets. Write "2+(3\*4)" instead.
```
'|'
```
This operator concatenates the left and the right operator as strings. Useful e.g. in "print" actions or when putting together MQTT topics.
## Comments
Comments start with a %' anywhere in a line and reach until the end of this line.
## Sample
Here is a demo of a script to give you an idea of the power of the scripting feature. This script controls a Sonoff switch module. It connects to a remote MQTT broker and in parallel offers locally its own. The device has a number stored in the variable $device_number. On both brokers it subscribes to a topic named '/martinshome/switch/($device_number)/command', where it receives commands, and it publishes the topic '/martinshome/switch/($device_number)/status' with the current state of the switch relay. It understands the commands 'on','off', 'toggle', and 'blink'. Blinking is realized via a timer event. Local status is stored in the two variables $relay_status and $blink (blinking on/off). The 'on gpio_interrupt' clause reacts on pressing the pushbutton of the Sonoff and simply toggles the switch (and stops blinking):
```
% Config params, overwrite any previous settings from the commandline
config ap_ssid MyAP
config ap_password stupidPassword
config ntp_server 1.de.pool.ntp.org
config broker_user Martin
config broker_password secret
config mqtt_host martinshome.fritz.box
config speed 160
% Now the initialization, this is done once after booting
on init
do
% Device number
setvar $device_number = 1
% @<num> vars are stored in flash and are persistent even after reboot
setvar $run = @1 + 1
setvar @1 = $run
println "This is boot no "|$run
% Status of the relay
setvar $relay_status=0
gpio_out 12 $relay_status
gpio_out 13 not ($relay_status)
% Blink flag
setvar $blink=0
% Command topic
setvar $command_topic="/martinshome/switch/" | $device_number | "/command"
% Status topic
setvar $status_topic="/martinshome/switch/" | $device_number | "/status"
publish local $status_topic $relay_status retained
% local subscriptions once in 'init'
subscribe local $command_topic
% Now the MQTT client init, this is done each time the client connects
on mqttconnect
do
% remote subscriptions for each connection in 'mqttconnect'
subscribe remote $command_topic
publish remote $status_topic $relay_status retained
% Now the events, checked whenever something happens
% Is there a remote command?
on topic remote $command_topic
do
println "Received remote command: " | $this_data
% republish this locally - this does the action
publish local $command_topic $this_data
% Is there a local command?
on topic local $command_topic
do
println "Received local command: " | $this_data
if $this_data = "on" then
setvar $relay_status = 1
setvar $blink = 0
gpio_out 12 $relay_status
gpio_out 13 not ($relay_status)
else
if $this_data = "off" then
setvar $relay_status = 0
setvar $blink = 0
gpio_out 12 $relay_status
gpio_out 13 not ($relay_status)
endif
endif
if $this_data = "toggle" then
setvar $relay_status = not ($relay_status)
gpio_out 12 $relay_status
gpio_out 13 not ($relay_status)
endif
if $this_data = "blink" then
setvar $blink = 1
settimer 1 500
endif
publish local $status_topic $relay_status retained
publish remote $status_topic $relay_status retained
% The local pushbutton
on gpio_interrupt 0 pullup
do
println "New state GPIO 0: " | $this_gpio
if $this_gpio = 0 then
setvar $blink = 0
publish local $command_topic "toggle"
endif
% Blinking
on timer 1
do
if $blink = 1 then
publish local $command_topic "toggle"
settimer 1 500
endif
```

Wyświetl plik

@ -0,0 +1,381 @@
{
// NOTE: You should always edit options in user file, not this file.
// Print debug message
"debug": false,
// Auto format on file save
"autoformat_on_save": false,
// The mapping key is `syntax name`, and the value is `formatting mode`.
// Note that the value for each mapping should be "c", "java" or "cs".
"user_defined_syntax_mode_mapping": {
// For example:
/*
"arduino": "c",
"pde": "java",
"apex": "java"
*/
},
// Please visit http://astyle.sourceforge.net/astyle.html for more information
"options_default": {
// Default bracket style
// Can be one of "allman", "bsd", "break", "java", "attach", "kr", "k&r",
// "k/r" "stroustrup", "whitesmith", "banner", "gnu", "linux", "horstmann",
// "1tbs", "otbs ", "google", "pico", "lisp", "python", "vtk", or null
// for default.
"style": "k&r",
// Tab options
// "indent": Can be one of "spaces", "tab" "force-tab", "force-tab-x", or null
// "indent-spaces": Can be either null or numbers
//
// While both "indent" or "indent-spaces" are null (default), the indentation options
// will be retrieved from Sublime Text view settings: `tab_size`, `translate_tabs_to_spaces`:
// 1. If `translate_tabs_to_spaces` is true, "indent" will be "spaces", otherwise, "tab";
// 2. "indent-spaces" will equal to `tab_size`.
"indent": null,
"indent-spaces": null,
// === Bracket Modify Options ===
// Attach brackets to a namespace statement. This is done regardless of
// the bracket style being used.
"attach-namespaces": false,
// Attach brackets to a class statement. This is done regardless of the
// bracket style being used.
"attach-classes": false,
// Attach brackets to class and struct inline function definitions. This
// is not done for run-in type brackets (Horstmann and Pico styles). This
// option is effective for C++ files only.
"attach-inlines": false,
// Attach brackets to a bracketed extern "C" statement. This is done
// regardless of the bracket style being used. This option is effective
// for C++ files only.
//
// An extern "C" statement that is part of a function definition is
// formatted according to the requested bracket style. Bracketed extern
// "C" statements are unaffected by the bracket style and this option is
// the only way to change them.
"attach-extern-c": false,
// === Indentation Options ===
// Indent 'class' and 'struct' blocks so that the blocks 'public:',
// 'protected:' and 'private:' are indented. The struct blocks are
// indented only if an access modifier is declared somewhere in the
// struct. The entire block is indented. This option is effective for C++ files only.
"indent-classes": false,
// Indent 'class' and 'struct' access modifiers, 'public:', 'protected:'
// and 'private:', one half indent. The rest of the class is not indented.
// This option is effective for C++ files only. If used with indentclasses
// this option will be ignored.
"indent-modifiers": false,
// Indent 'switch' blocks so that the 'case X:' statements are indented
// in the switch block. The entire case block is indented.
"indent-switches": true,
// Indent 'case X:' blocks from the 'case X:' headers. Case statements
// not enclosed in blocks are NOT indented.
"indent-cases": true,
// Add extra indentation to namespace blocks. This option has
// no effect on Java files.
"indent-namespaces": false,
// Add extra indentation to labels so they appear 1 indent less than the
// current indentation, rather than being flushed to the left (the default).
"indent-labels": false,
// Indent preprocessor blocks at bracket level zero, and immediately within
// a namespace. There are restrictions on what will be indented. Blocks
// within methods, classes, arrays, etc, will not be indented. Blocks
// containing brackets or multi-line define statements will not be indented.
// Without this option the preprocessor block is not indented.
"indent-preproc-block": false,
// Indent multi-line preprocessor definitions ending with a backslash.
// Should be used with `convert-tabs` for proper results. Does a pretty
// good job, but cannot perform miracles in obfuscated preprocessor
// definitions. Without this option the preprocessor statements remain unchanged.
"indent-preproc-define": false,
// Indent preprocessor conditional statements to the same level as the
// source code.
"indent-preproc-cond": false,
// Indent C++ comments beginning in column one. By default C++ comments
// beginning in column one are not indented. This option will allow the
// comments to be indented with the code.
"indent-col1-comments": false,
// Set the minimal indent that is added when a header is built of multiple
// lines. This indent helps to easily separate the header from the command
// statements that follow. The value for # indicates a number of indents
// and is a minimum value. The indent may be greater to align with the data
// on the previous line.
// The valid values are:
// 0 - no minimal indent. The lines will be aligned with the paren on the
// preceding line.
// 1 - indent at least one additional indent.
// 2 - indent at least two additional indents.
// 3 - indent at least one-half an additional indent. This is intended for
// large indents (e.g. 8).
// The default value is 2, two additional indents.
"min-conditional-indent": 2,
// Set the maximum spaces to indent a continuation line.
// The maximum spaces indicate a number of columns and
// must not be greater than 120. A maximum of less
// than two indent lengths will be ignored. This option
// will prevent continuation lines from extending too
// far to the right. Setting a larger value will allow
// the code to be extended further to the right.
//
// range: [40, 120]
"max-instatement-indent": 40,
// === Padding Options ===
// null - Do nothing
// "default" - Pad empty lines around header blocks (e.g. 'if',
// 'for', 'while'...).
// "all" - Pad empty lines around header blocks (e.g. 'if',
// 'for', 'while'...). Treat closing header blocks
// (e.g. 'else', 'catch') as stand-alone blocks.
"break-blocks": null,
// Insert space padding around operators. Any end of line comments
// will remain in the original column, if possible. Note that there
// is no option to unpad. Once padded, they stay padded.
"pad-oper": true,
// Insert space padding around parenthesis on both the outside and
// the inside. Any end of line comments will remain in the original
// column, if possible.
"pad-paren": false,
// Insert space padding around parenthesis on the outside only. Any
// end of line comments will remain in the original column, if possible.
// This can be used with `unpad-paren` below to remove unwanted spaces.
"pad-paren-out": false,
// Insert space padding around the first parenthesis in a series on the
// outside only. Any end of line comments will remain in the original
// column, if possible. This can be used with unpad-paren below to remove
// unwanted spaces. If used with pad-paren or pad-paren-out, this
// option will be ignored. If used with pad-paren-in, the result will
// be the same as pad-paren.
"pad-first-paren-out": false,
// Insert space padding around parenthesis on the inside only. Any
// end of line comments will remain in the original column, if possible.
// This can be used with `unpad-paren` below to remove unwanted spaces.
"pad-paren-in": false,
// Insert space padding after paren headers only (e.g. 'if', 'for',
//'while'...). Any end of line comments will remain in the original
// column, if possible. This can be used with unpad-paren to remove
// unwanted spaces.
"pad-header": true,
// Remove extra space padding around parenthesis on the inside and outside.
// Any end of line comments will remain in the original column, if possible.
// This option can be used in combination with the paren padding options
// `pad-paren`, `pad-paren-out`, `pad-paren-in`, and `pad-header` above.
// Only padding that has not been requested by other options will be removed.
// For example, if a source has parens padded on both the inside and outside,
// and you want inside only. You need to use unpad-paren to remove the outside
// padding, and pad-paren-in to retain the inside padding. Using only `pad-paren-in`
// would not remove the outside padding.
"unpad-paren": false,
// Delete empty lines within a function or method. Empty lines outside of functions
// or methods are NOT deleted. If used with break-blocks or break-blocks=all it will
// delete all lines EXCEPT the lines added by the `break-blocks` options.
"delete-empty-lines": false,
// Fill empty lines with the white space of the previous line.
"fill-empty-lines": false,
// Attach a pointer or reference operator (* or &) to either the variable type (left)
// or variable name (right), or place it between the type and name (middle).
// The spacing between the type and name will be preserved, if possible. To format
// references separately use the following `align-reference` option.
// can be one of null, "type", "middle" or "name"
"align-pointer": null,
// This option will align references separate from pointers. Pointers are not changed
// by this option. If pointers and references are to be aligned the same, use the
// previous `align-pointer` option. The option align-reference=none will not change
// the reference alignment. The other options are the same as for `align-pointer`.
// In the case of a reference to a pointer (*&) with conflicting alignments, the
// `align-pointer` value will be used.
// can be one of "none", "type", "middle", "name", or null for default.
"align-reference": null,
// === Formatting Options ===
// When `style` is "attach", "linux" or "stroustrup", this breaks closing headers
// (e.g. 'else', 'catch', ...) from their immediately preceding closing brackets.
// Closing header brackets are always broken with broken brackets, horstmann
// rackets, indented blocks, and indented brackets.
"break-closing-brackets": false,
// Break "else if" header combinations into separate lines. This option has no effect
// if keep-one-line-statements is used, the "else if" statements will remain as they are.
// If this option is NOT used, "else if" header combinations will be placed on a single line.
"break-elseifs": false,
// Add brackets to unbracketed one line conditional statements (e.g. 'if', 'for', 'while'...).
// The statement must be on a single line. The brackets will be added according to the
// currently requested predefined style or bracket type. If no style or bracket type is
// requested the brackets will be attached. If `add-one-line-brackets` is also used the
// result will be one line brackets.
"add-brackets": false,
// Add one line brackets to unbracketed one line conditional statements
// (e.g. 'if', 'for', 'while'...). The statement must be on a single line.
// The option implies `keep-one-line-blocks` and will not break the one line blocks.
"add-one-line-brackets": false,
// Remove brackets from conditional statements (e.g. 'if', 'for', 'while'...).
// The statement must be a single statement on a single line. If
// --add-brackets or --add-one-line-brackets is also used the result will
// be to add brackets. Brackets will not be removed from
// "One True Brace Style", --style=1tbs.
"remove-brackets": false,
// Don't break one-line blocks.
"keep-one-line-blocks": true,
// Don't break complex statements and multiple statements residing on a single line.
"keep-one-line-statements": true,
// Closes whitespace in the angle brackets of template definitions. Closing
// the ending angle brackets is now allowed by the C++11 standard.
// Be sure your compiler supports this before making the changes.
"close-templates": false,
// Remove the preceding '*' in a multi-line comment that begins a line.
// A trailing '*', if present, is also removed. Text that is less than one
// is indent is indented to one indent. Text greater than one indent is
// not changed. Multi-line comments that begin a line but without the
// preceding '*' are indented to one indent for consistency. This can
// slightly modify the indentation of commented out blocks of code.
// Lines containing all '*' are left unchanged. Extra spacing is removed
// from the comment close '*/'.
"remove-comment-prefix": false,
// The option max-code-length will break a line if the code exceeds # characters.
// The valid values are 50 thru 200. Lines without logical conditionals will
// break on a logical conditional (||, &&, ...), comma, paren, semicolon, or space.
//
// Some code will not be broken, such as comments, quotes, and arrays.
// If used with keep-one-line-blocks or add-one-line-brackets the blocks
// will NOT be broken. If used with keep-one-line-statements the statements
// will be broken at a semicolon if the line goes over the maximum length.
// If there is no available break point within the max code length, the
// line will be broken at the first available break point after the max code length.
//
// By default logical conditionals will be placed first on the new line.
// The option break-after-logical will cause the logical conditionals to be
// placed last on the previous line. This option has no effect without max-code-length.
"max-code-length": -1,
"break-after-logical": false,
// == Objective-C Options ==
// Because of the longer indents sometimes needed for Objective-C, the option
// "max-instatement-indent" may need to be increased. If you are not getting
// the paren and square bracket alignment you want, try increasing this value.
// Align the colons in Objective-C method declarations. This option is effective
// for Objective-C files only.
"align-method-colon": false,
// Insert space padding after the '-' or '+' Objective-C method prefix. This will
// add exactly one space. Any additional spaces will be deleted. This option is
// effective for Objective-C files only.
"pad-method-prefix": false,
// Remove all space padding after the '-' or '+' Objective-C method prefix.
// If used with pad-method-prefix, this option will be ignored. This option
// is effective for Objective-C files only.
"unpad-method-prefix": false,
// Add or remove space padding before or after the colons in an Objective-C
// method call. These options will pad exactly one space. Any additional
// spaces will be deleted. Colons immediarely preceeding a paren will not
// be padded. This option is effective for Objective-C files only.
//
// Can be one of "none", "all", "after" or "before", or null for default.
"pad-method-colon": null
},
//
// Language Specific Options
//
// You can override default options in language-specific options here.
// Addtional options are also provided:
//
// "additional_options": Addtional options following astyle options file style
// (http://astyle.sourceforge.net/astyle.html).
// e.g.: "additional_options": ["--indent=spaces=2", "--convert-tabs"]
//
// "additional_options_file": Addtional options file for astyle (aka astylerc), you must specify
// a full path for that file, environment variable may be included.
// e.g.: "additional_options_file": "%USERPROFILE%/astylerc" // (Windows)
// e.g.: "additional_options_file": "$HOME/.astylerc" // (Linux)
// === Additional variables that you may use ===
// $file_path The directory of the current file, e.g., C:\Files.
// $file The full path to the current file, e.g., C:\Files\Chapter1.txt.
// $file_name The name portion of the current file, e.g., Chapter1.txt.
// $file_extension The extension portion of the current file, e.g., txt.
// $file_base_name The name-only portion of the current file, e.g., Document.
// $packages The full path to the Packages folder.
// The following requires "Sublime Text 3"
// $project The full path to the current project file.
// $project_path The directory of the current project file.
// $project_name The name portion of the current project file.
// $project_extension The extension portion of the current project file.
// $project_base_name The name-only portion of the current project file.
//
// "use_only_additional_options": While true, SublimeAStyleFormatter will *only* process
// options in *both* "additional_options" and "additional_options_file".
// Language-specific options for C
"options_c": {
"use_only_additional_options": false,
"additional_options_file": "",
"additional_options": []
},
// Language-specific for C++
"options_c++": {
"use_only_additional_options": false,
"additional_options_file": "",
"additional_options": []
},
// Language-specific for Java
"options_java": {
"style": "java",
"use_only_additional_options": false,
"additional_options_file": "",
"additional_options": []
},
// Language-specific for C#
"options_cs": {
"use_only_additional_options": false,
"additional_options_file": "",
"additional_options": []
}
}

75
adc/adc.c 100644
Wyświetl plik

@ -0,0 +1,75 @@
#include "ets_sys.h"
#include "osapi.h"
#include "adc.h"
#define i2c_bbpll 0x67
#define i2c_bbpll_en_audio_clock_out 4
#define i2c_bbpll_en_audio_clock_out_msb 7
#define i2c_bbpll_en_audio_clock_out_lsb 7
#define i2c_bbpll_hostid 4
#define i2c_saradc 0x6C
#define i2c_saradc_hostid 2
#define i2c_saradc_en_test 0
#define i2c_saradc_en_test_msb 5
#define i2c_saradc_en_test_lsb 5
#define i2c_writeReg_Mask(block, host_id, reg_add, Msb, Lsb, indata) \
rom_i2c_writeReg_Mask(block, host_id, reg_add, Msb, Lsb, indata)
#define i2c_readReg_Mask(block, host_id, reg_add, Msb, Lsb) \
rom_i2c_readReg_Mask_(block, host_id, reg_add, Msb, Lsb)
#define i2c_writeReg_Mask_def(block, reg_add, indata) \
i2c_writeReg_Mask(block, block##_hostid, reg_add, reg_add##_msb, reg_add##_lsb, indata)
#define i2c_readReg_Mask_def(block, reg_add) \
i2c_readReg_Mask(block, block##_hostid, reg_add, reg_add##_msb, reg_add##_lsb)
#ifdef ADC_DEBUG
#define ADC_DBG os_printf
#else
#define ADC_DBG
#endif
uint16 ICACHE_FLASH_ATTR adc_read(void)
{
uint8 i;
uint16 sar_dout, tout, sardata[8];
i2c_writeReg_Mask_def(i2c_saradc, i2c_saradc_en_test, 1); //select test mux
//PWDET_CAL_EN=0, PKDET_CAL_EN=0
SET_PERI_REG_MASK(0x60000D5C, 0x200000);
while (GET_PERI_REG_BITS(0x60000D50, 26, 24) > 0); //wait r_state == 0
sar_dout = 0;
CLEAR_PERI_REG_MASK(0x60000D50, 0x02); //force_en=0
SET_PERI_REG_MASK(0x60000D50, 0x02); //force_en=1
os_delay_us(2);
while (GET_PERI_REG_BITS(0x60000D50, 26, 24) > 0); //wait r_state == 0
read_sar_dout(sardata);
for (i = 0; i < 8; i++) {
sar_dout += sardata[i];
ADC_DBG("%d, ", sardata[i]);
}
tout = (sar_dout + 8) >> 4; //tout is 10 bits fraction
i2c_writeReg_Mask_def(i2c_saradc, i2c_saradc_en_test, 1); //select test mux
while (GET_PERI_REG_BITS(0x60000D50, 26, 24) > 0); //wait r_state == 0
CLEAR_PERI_REG_MASK(0x60000D5C, 0x200000);
SET_PERI_REG_MASK(0x60000D60, 0x1); //force_en=1
CLEAR_PERI_REG_MASK(0x60000D60, 0x1); //force_en=1
return tout; //tout is 10 bits fraction
}

6
adc/adc.h 100644
Wyświetl plik

@ -0,0 +1,6 @@
#ifndef __ADC_H__
#define __ADC_H__
uint16 adc_read(void);
#endif

484
driver/new_uart.c 100644
Wyświetl plik

@ -0,0 +1,484 @@
/*
* File : uart.c
* Copyright (C) 2013 - 2016, Espressif Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of version 3 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ets_sys.h"
#include "osapi.h"
#include "driver/uart.h"
#include "osapi.h"
#include "driver/uart_register.h"
#include "mem.h"
#include "os_type.h"
#ifdef _ENABLE_RING_BUFFER
static ringbuf_t rxBuff;
static ringbuf_t txBuff;
#endif
#ifdef _ENABLE_CONSOLE_INTEGRATION
uint8_t linked_to_console = 0;
uint8_t echo_on = 1;
#endif
extern UartDevice UartDev;
/* Local variables */
static uint8 uart_recvTaskPrio = 0;
/* Internal Functions */
static void ICACHE_FLASH_ATTR uart_config(uint8 uart_no);
static void uart0_rx_intr_handler(void *para);
/* Public APIs */
void ICACHE_FLASH_ATTR UART_init(UartBautRate uart0_br, UartBautRate uart1_br, uint8 recv_task_priority);
#define ENABLE_DEBUG
#ifdef ENABLE_DEBUG
#define DBG
#define DBG1 os_printf
#define DBG2 os_printf
#else
#define DBG
#define DBG1
#define DBG2
#endif
#if _ENABLE_CONSOLE_INTEGRATION == 1
void ICACHE_FLASH_ATTR UART_init_console(UartBautRate uart0_br,
uint8 recv_task_priority,
ringbuf_t rxbuffer,
ringbuf_t txBuffer)
{
/* Set the task which should receive the signals once the data is received */
uart_recvTaskPrio = recv_task_priority;
UartDev.baut_rate = uart0_br;
rxBuff = rxbuffer;
txBuff = txBuffer;
linked_to_console = 1;
echo_on = 1;
uart_config(UART0);
UART_SetPrintPort(UART0);
UartDev.baut_rate = uart0_br;
uart_config(UART1);
ETS_UART_INTR_ENABLE();
}
#endif
void ICACHE_FLASH_ATTR UART_init(UartBautRate uart0_br, UartBautRate uart1_br, uint8 recv_task_priority)
{
/* Set the task which should receive the signals once the data is received */
uart_recvTaskPrio = recv_task_priority;
UartDev.baut_rate = uart0_br;
uart_config(UART0);
UART_SetPrintPort(UART0);
UartDev.baut_rate = uart1_br;
uart_config(UART1);
ETS_UART_INTR_ENABLE();
#if _ENABLE_CONSOLE_INTEGRATION == 0
#if _ENABLE_RING_BUFFER == 1
rxBuff = ringbuf_new(RX_RING_BUFFER_SIZE);
#endif
#endif
}
/******************************************************************************
* FunctionName : uart_config
* Description : Internal used function
* UART0 used for data TX/RX, RX buffer size is 0x100, interrupt enabled
* UART1 just used for debug output
* Parameters : uart_no, use UART0 or UART1 defined ahead
* Returns : NONE
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR uart_config(uint8 uart_no)
{
if (uart_no == UART1)
{
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK);
}
else
{
/* rcv_buff size if 0x100 */
ETS_UART_INTR_ATTACH(uart0_rx_intr_handler, &(UartDev.rcv_buff));
PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD);
#if UART_HW_RTS
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS); //HW FLOW CONTROL RTS PIN
#endif
#if UART_HW_CTS
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_U0CTS); //HW FLOW CONTROL CTS PIN
#endif
}
uart_div_modify(uart_no, UART_CLK_FREQ / (UartDev.baut_rate));//SET BAUDRATE
WRITE_PERI_REG(UART_CONF0(uart_no), ((UartDev.exist_parity & UART_PARITY_EN_M) << UART_PARITY_EN_S) //SET BIT AND PARITY MODE
| ((UartDev.parity & UART_PARITY_M) <<UART_PARITY_S )
| ((UartDev.stop_bits & UART_STOP_BIT_NUM) << UART_STOP_BIT_NUM_S)
| ((UartDev.data_bits & UART_BIT_NUM) << UART_BIT_NUM_S));
//clear rx and tx fifo,not ready
SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST); //RESET FIFO
CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
if (uart_no == UART0)
{
int rx_threshold = 10;
#if _ENABLE_CONSOLE_INTEGRATION == 1
rx_threshold = 1;
#endif
//set rx fifo trigger
WRITE_PERI_REG(UART_CONF1(uart_no),
((rx_threshold & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) |
#if UART_HW_RTS
((110 & UART_RX_FLOW_THRHD) << UART_RX_FLOW_THRHD_S) |
UART_RX_FLOW_EN | //enbale rx flow control
#endif
// (0x02 & UART_RX_TOUT_THRHD) << UART_RX_TOUT_THRHD_S |
// UART_RX_TOUT_EN|
((0x10 & UART_TXFIFO_EMPTY_THRHD)<<UART_TXFIFO_EMPTY_THRHD_S));//wjl
#if UART_HW_CTS
SET_PERI_REG_MASK( UART_CONF0(uart_no),UART_TX_FLOW_EN); //add this sentense to add a tx flow control via MTCK( CTS )
#endif
SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_TOUT_INT_ENA |UART_FRM_ERR_INT_ENA);
}
else
{
WRITE_PERI_REG(UART_CONF1(uart_no),((UartDev.rcv_buff.TrigLvl & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S));//TrigLvl default val == 1
}
//clear all interrupt
WRITE_PERI_REG(UART_INT_CLR(uart_no), 0xffff);
//enable rx_interrupt
SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_OVF_INT_ENA);
}
/******************************************************************************
* FunctionName : UART_Recv
* Description : Public API, unloads the contents of the Rx FIFO for specified
* uart into the buffer specified. Will unload upto buffer size
* only
* Parameters : IN uart number (uart_no)
* IN/OUT char *buffer
* IN int max_buf_len
* Returns : int (number of bytes unloaded ) 0 if FIFO is empty
*******************************************************************************/
int UART_Recv(uint8 uart_no, char *buffer, int max_buf_len)
{
uint8 max_unload, index = -1;
#if _ENABLE_RING_BUFFER == 1
/* If the ring buffer is enabled, then unload from Rx Ring Buffer */
uint8 bytes_ringbuffer = ringbuf_bytes_used(rxBuff);
//ring_buffer_dump(rxBuff);
if (bytes_ringbuffer)
{
max_unload = (bytes_ringbuffer<max_buf_len ? bytes_ringbuffer: max_buf_len);
ringbuf_memcpy_from(buffer, rxBuff, max_unload);
}
#else
/* If the ring buffer is not enabled, then unload from Rx FIFO */
uint8 fifo_len = (READ_PERI_REG(UART_STATUS(uart_no))>>UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT;
if (fifo_len)
{
max_unload = (fifo_len<max_buf_len ? fifo_len : max_buf_len);
DBG1("Rx Fifo contains %d characters have to unload %d\r\n", fifo_len , max_unload);
for (index=0;index<max_unload; index++)
{
*(buffer+index) = READ_PERI_REG(UART_FIFO(UART0)) & 0xFF;
}
//return index;
WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_RXFIFO_FULL_INT_CLR);
uart_rx_intr_enable(uart_no);
}
#endif
return index;
}
int ICACHE_FLASH_ATTR UART_Echo(uint8 echo)
{
echo_on = echo;
return echo_on;
}
int UART_Send(uint8 uart_no, char *buffer, int len)
{
int index = 0;
char ch ;
//DBG1("Sending: %s\n", buffer);
for (index=0; index <len; index ++)
{
ch = *(buffer+index);
uart_tx_one_char(uart_no, ch);
}
return index;
}
/*---------------------------------------------------------------------------*
* Internal Functions
*---------------------------------------------------------------------------*/
/******************************************************************************
* FunctionName : uart_rx_intr_disable
* Description : Internal used function disables the uart interrupts
* Parameters : IN uart number (uart_no)
* Returns : NONE
*******************************************************************************/
void uart_rx_intr_disable(uint8 uart_no)
{
//DBG1("RxIntr Disabled\r\n");
#if 1
CLEAR_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
#else
ETS_UART_INTR_DISABLE();
#endif
}
/******************************************************************************
* FunctionName : uart_rx_intr_enable
* Description : Internal used function enables the uart interrupts
* Parameters : IN uart number (uart_no)
* Returns : NONE
*******************************************************************************/
void uart_rx_intr_enable(uint8 uart_no)
{
//DBG1("RxIntr Enabled\r\n");
#if 1
SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
#else
ETS_UART_INTR_ENABLE();
#endif
}
/******************************************************************************
* FunctionName : uart0_rx_intr_handler
* Description : Internal used function
* UART0 interrupt handler, add self handle code inside
* Parameters : void *para - point to ETS_UART_INTR_ATTACH's arg
* Returns : NONE
*******************************************************************************/
static void uart0_rx_intr_handler(void *para)
{
uint8 uart_no = UART0;//UartDev.buff_uart_no;
/* Is the frame Error interrupt set ? */
if(UART_FRM_ERR_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_FRM_ERR_INT_ST))
{
/* The Frame Error (UART_FRM_ERR_INT_ST) has bee set */
DBG1("Frame Error\r\n");
WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_FRM_ERR_INT_CLR);
goto end_int_handler;
}
if(UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST))
{
/* Rx FIFO is full, hence the interrupt */
#if _ENABLE_RING_BUFFER == 1
uint16_t index;
uint16_t fifo_len = (READ_PERI_REG(UART_STATUS(uart_no))>>UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT;
//DBG1("RX FIFO FULL [%d]\r\n", fifo_len );
if (fifo_len)
{
//DBG1("Rx Fifo contains %d characters have to unload\r\n", fifo_len);
for (index=0;index<fifo_len; index++)
{
uint8_t ch = (READ_PERI_REG(UART_FIFO(UART0)) & 0xFF);
//if (ch == '\r') ch = '\n';
ringbuf_memcpy_into(rxBuff, &ch, 1);
#if _ENABLE_CONSOLE_INTEGRATION == 1
if (echo_on){
uart_tx_one_char(uart_no, ch);
}
if (ch == '\r')
{
system_os_post(0, SIG_CONSOLE_RX, 0);
}
#endif
}
WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_RXFIFO_FULL_INT_CLR);
uart_rx_intr_enable(uart_no);
#if _ENABLE_CONSOLE_INTEGRATION == 0
system_os_post(uart_recvTaskPrio, SIG_UART0, 0);
#endif
}
#else
DBG1("RX FIFO FULL [%d]\r\n", (READ_PERI_REG(UART_STATUS(uart_no))>>UART_RXFIFO_CNT_S)& UART_RXFIFO_CNT);
uart_rx_intr_disable(UART0);
WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_FULL_INT_CLR);
system_os_post(uart_recvTaskPrio, SIG_UART0, 0);
#endif
goto end_int_handler;
}
if(UART_RXFIFO_TOUT_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_TOUT_INT_ST))
{
/* The Time out threshold for Rx/Tx is being execeeded */
DBG1("Rx Timeout Threshold not being met \r\n");
uart_rx_intr_disable(UART0);
WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_TOUT_INT_CLR);
system_os_post(uart_recvTaskPrio, SIG_UART0, 0);
goto end_int_handler;
}
if(UART_TXFIFO_EMPTY_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_TXFIFO_EMPTY_INT_ST))
{
/* The Tx FIFO is empty, the FIFO needs to be fed with new data */
DBG1("Tx FIFO is empty\r\n");
CLEAR_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA);
#if UART_BUFF_EN
tx_start_uart_buffer(UART0);
#endif
//system_os_post(uart_recvTaskPrio, 1, 0);
WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_TXFIFO_EMPTY_INT_CLR);
}
end_int_handler:
return;
}
/******************************************************************************
* FunctionName : uart_tx_one_char_no_wait
* Description : uart tx a single char without waiting for fifo
* Parameters : uint8 uart - uart port
* uint8 TxChar - char to tx
* Returns : STATUS
*******************************************************************************/
STATUS uart_tx_one_char(uint8 uart, uint8 TxChar)
{
while (true)
{
uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT<<UART_TXFIFO_CNT_S);
if ((fifo_cnt >> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) < 126) {
break;
}
}
WRITE_PERI_REG(UART_FIFO(uart) , TxChar);
return OK;
}
/******************************************************************************
* FunctionName : uart_tx_one_char_no_wait
* Description : uart tx a single char without waiting for fifo
* Parameters : uint8 uart - uart port
* uint8 TxChar - char to tx
* Returns : STATUS
*******************************************************************************/
STATUS uart_tx_one_char_no_wait(uint8 uart, uint8 TxChar)
{
uint8 fifo_cnt = (( READ_PERI_REG(UART_STATUS(uart))>>UART_TXFIFO_CNT_S)& UART_TXFIFO_CNT);
if (fifo_cnt < 126)
{
WRITE_PERI_REG(UART_FIFO(uart) , TxChar);
}
return OK;
}
/******************************************************************************
* FunctionName : uart0_write_char_no_wait
* Description : tx a single char without waiting for uart 0.
helper function for os_printf output to fifo or tx buffer
* Parameters : uint8 uart - uart port
* uint8 TxChar - char to tx
* Returns : STATUS
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR uart0_write_char_no_wait(char c)
{
#if UART_BUFF_EN //send to uart0 fifo but do not wait
uint8 chr;
if (c == '\n'){
chr = '\r';
tx_buff_enq(&chr, 1);
chr = '\n';
tx_buff_enq(&chr, 1);
}else if (c == '\r'){
}else{
tx_buff_enq(&c,1);
}
#else //send to uart tx buffer
if (c == '\n')
{
uart_tx_one_char(UART0, '\r');
uart_tx_one_char(UART0, '\n');
//uart_tx_one_char_no_wait(UART0, '\r');
//uart_tx_one_char_no_wait(UART0, '\n');
}
else
if (c == '\r')
{
uart_tx_one_char(UART0, c);
}
else
{
uart_tx_one_char(UART0, c);
//uart_tx_one_char_no_wait(UART0, c);
}
#endif
}
/******************************************************************************
* FunctionName : UART_SetPrintPort
* Description :
*
* Parameters :
* Returns : NONE
*******************************************************************************/
void ICACHE_FLASH_ATTR UART_SetPrintPort(uint8 uart_no)
{
if(uart_no==1)
{
//os_install_putc1(uart1_write_char);
}
else
{
/*option 1: do not wait if uart fifo is full,drop current character*/
//os_install_putc1(uart0_write_char_no_wait);
/*option 2: wait for a while if uart fifo is full*/
//os_install_putc1(uart0_write_char);
}
}

Wyświetl plik

@ -1,307 +0,0 @@
/******************************************************************************
* Copyright 2013-2014 Espressif Systems (Wuxi)
*
* FileName: uart.c
*
* Description: Two UART mode configration and interrupt handler.
* Check your hardware connection while use this mode.
*
* Modification history:
* 2014/3/12, v1.0 create this file.
*******************************************************************************/
#include "ets_sys.h"
#include "osapi.h"
#include "driver/uart.h"
#include "osapi.h"
#include "driver/uart_register.h"
//#include "ssc.h"
// UartDev is defined and initialized in rom code.
extern UartDevice UartDev;
//extern os_event_t at_recvTaskQueue[at_recvTaskQueueLen];
LOCAL void uart0_rx_intr_handler(void *para);
/******************************************************************************
* FunctionName : uart_config
* Description : Internal used function
* UART0 used for data TX/RX, RX buffer size is 0x100, interrupt enabled
* UART1 just used for debug output
* Parameters : uart_no, use UART0 or UART1 defined ahead
* Returns : NONE
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
uart_config(uint8 uart_no)
{
if (uart_no == UART1)
{
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK);
}
else
{
/* rcv_buff size if 0x100 */
ETS_UART_INTR_ATTACH(uart0_rx_intr_handler, &(UartDev.rcv_buff));
PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS);
}
uart_div_modify(uart_no, UART_CLK_FREQ / (UartDev.baut_rate));
WRITE_PERI_REG(UART_CONF0(uart_no), UartDev.exist_parity
| UartDev.parity
| (UartDev.stop_bits << UART_STOP_BIT_NUM_S)
| (UartDev.data_bits << UART_BIT_NUM_S));
//clear rx and tx fifo,not ready
SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
//set rx fifo trigger
// WRITE_PERI_REG(UART_CONF1(uart_no),
// ((UartDev.rcv_buff.TrigLvl & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) |
// ((96 & UART_TXFIFO_EMPTY_THRHD) << UART_TXFIFO_EMPTY_THRHD_S) |
// UART_RX_FLOW_EN);
if (uart_no == UART0)
{
//set rx fifo trigger
WRITE_PERI_REG(UART_CONF1(uart_no),
((0x10 & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) |
((0x10 & UART_RX_FLOW_THRHD) << UART_RX_FLOW_THRHD_S) |
UART_RX_FLOW_EN |
(0x02 & UART_RX_TOUT_THRHD) << UART_RX_TOUT_THRHD_S |
UART_RX_TOUT_EN);
SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_TOUT_INT_ENA |
UART_FRM_ERR_INT_ENA);
}
else
{
WRITE_PERI_REG(UART_CONF1(uart_no),
((UartDev.rcv_buff.TrigLvl & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S));
}
//clear all interrupt
WRITE_PERI_REG(UART_INT_CLR(uart_no), 0xffff);
//enable rx_interrupt
SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA);
}
/******************************************************************************
* FunctionName : uart1_tx_one_char
* Description : Internal used function
* Use uart1 interface to transfer one char
* Parameters : uint8 TxChar - character to tx
* Returns : OK
*******************************************************************************/
LOCAL STATUS
uart_tx_one_char(uint8 uart, uint8 TxChar)
{
while (true)
{
uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT<<UART_TXFIFO_CNT_S);
if ((fifo_cnt >> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) < 126) {
break;
}
}
WRITE_PERI_REG(UART_FIFO(uart) , TxChar);
return OK;
}
/******************************************************************************
* FunctionName : uart1_write_char
* Description : Internal used function
* Do some special deal while tx char is '\r' or '\n'
* Parameters : char c - character to tx
* Returns : NONE
*******************************************************************************/
void ICACHE_FLASH_ATTR
uart1_write_char(char c)
{
if (c == '\n')
{
uart_tx_one_char(UART1, '\r');
uart_tx_one_char(UART1, '\n');
}
else if (c == '\r')
{
}
else
{
uart_tx_one_char(UART1, c);
}
}
void ICACHE_FLASH_ATTR
uart0_write_char(char c)
{
if (c == '\n')
{
uart_tx_one_char(UART0, '\r');
uart_tx_one_char(UART0, '\n');
}
else if (c == '\r')
{
}
else
{
uart_tx_one_char(UART0, c);
}
}
/******************************************************************************
* FunctionName : uart0_tx_buffer
* Description : use uart0 to transfer buffer
* Parameters : uint8 *buf - point to send buffer
* uint16 len - buffer len
* Returns :
*******************************************************************************/
void ICACHE_FLASH_ATTR
uart0_tx_buffer(uint8 *buf, uint16 len)
{
uint16 i;
for (i = 0; i < len; i++)
{
uart_tx_one_char(UART0, buf[i]);
}
}
/******************************************************************************
* FunctionName : uart0_sendStr
* Description : use uart0 to transfer buffer
* Parameters : uint8 *buf - point to send buffer
* uint16 len - buffer len
* Returns :
*******************************************************************************/
void ICACHE_FLASH_ATTR
uart0_sendStr(const char *str)
{
while(*str)
{
uart_tx_one_char(UART0, *str++);
}
}
/******************************************************************************
* FunctionName : uart0_rx_intr_handler
* Description : Internal used function
* UART0 interrupt handler, add self handle code inside
* Parameters : void *para - point to ETS_UART_INTR_ATTACH's arg
* Returns : NONE
*******************************************************************************/
//extern void at_recvTask(void);
LOCAL void
uart0_rx_intr_handler(void *para)
{
/* uart0 and uart1 intr combine togther, when interrupt occur, see reg 0x3ff20020, bit2, bit0 represents
* uart1 and uart0 respectively
*/
// RcvMsgBuff *pRxBuff = (RcvMsgBuff *)para;
uint8 RcvChar;
uint8 uart_no = UART0;//UartDev.buff_uart_no;
// if (UART_RXFIFO_FULL_INT_ST != (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST))
// {
// return;
// }
// if (UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST))
// {
//// at_recvTask();
// RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xFF;
// system_os_post(at_recvTaskPrio, NULL, RcvChar);
// WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_RXFIFO_FULL_INT_CLR);
// }
if(UART_FRM_ERR_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_FRM_ERR_INT_ST))
{
os_printf("FRM_ERR\r\n");
WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_FRM_ERR_INT_CLR);
}
if(UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST))
{
// os_printf("fifo full\r\n");
ETS_UART_INTR_DISABLE();/////////
//system_os_post(at_recvTaskPrio, 0, 0);
// WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_RXFIFO_FULL_INT_CLR);
// while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S))
// {
//// at_recvTask();
// RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xFF;
// system_os_post(at_recvTaskPrio, NULL, RcvChar);
// }
}
else if(UART_RXFIFO_TOUT_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_TOUT_INT_ST))
{
ETS_UART_INTR_DISABLE();/////////
//system_os_post(at_recvTaskPrio, 0, 0);
// WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_RXFIFO_TOUT_INT_CLR);
//// os_printf("rx time over\r\n");
// while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S))
// {
//// os_printf("process recv\r\n");
//// at_recvTask();
// RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xFF;
// system_os_post(at_recvTaskPrio, NULL, RcvChar);
// }
}
// WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_RXFIFO_FULL_INT_CLR);
// if (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S))
// {
// RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xFF;
// at_recvTask();
// *(pRxBuff->pWritePos) = RcvChar;
// system_os_post(at_recvTaskPrio, NULL, RcvChar);
// //insert here for get one command line from uart
// if (RcvChar == '\r')
// {
// pRxBuff->BuffState = WRITE_OVER;
// }
//
// pRxBuff->pWritePos++;
//
// if (pRxBuff->pWritePos == (pRxBuff->pRcvMsgBuff + RX_BUFF_SIZE))
// {
// // overflow ...we may need more error handle here.
// pRxBuff->pWritePos = pRxBuff->pRcvMsgBuff ;
// }
// }
}
/******************************************************************************
* FunctionName : uart_init
* Description : user interface for init uart
* Parameters : UartBautRate uart0_br - uart0 bautrate
* UartBautRate uart1_br - uart1 bautrate
* Returns : NONE
*******************************************************************************/
void ICACHE_FLASH_ATTR
uart_init(UartBautRate uart0_br, UartBautRate uart1_br)
{
// rom use 74880 baut_rate, here reinitialize
UartDev.baut_rate = uart0_br;
uart_config(UART0);
UartDev.baut_rate = uart1_br;
uart_config(UART1);
ETS_UART_INTR_ENABLE();
// install uart1 putc callback
os_install_putc1((void *)uart0_write_char);
}
void ICACHE_FLASH_ATTR
uart_reattach()
{
uart_init(BIT_RATE_74880, BIT_RATE_74880);
// ETS_UART_INTR_ATTACH(uart_rx_intr_handler_ssc, &(UartDev.rcv_buff));
// ETS_UART_INTR_ENABLE();
}

343
easygpio/easygpio.c 100644
Wyświetl plik

@ -0,0 +1,343 @@
/*
* easygpio.c
*
* Copyright (c) 2015, eadf (https://github.com/eadf)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "easygpio.h"
#include "gpio.h"
#include "osapi.h"
#include "ets_sys.h"
#define EASYGPIO_USE_GPIO_INPUT_GET
static void ICACHE_FLASH_ATTR
gpio16_output_conf(void) {
WRITE_PERI_REG(PAD_XPD_DCDC_CONF,
(READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbcUL) | 0x1UL); // mux configuration for XPD_DCDC to output rtc_gpio0
WRITE_PERI_REG(RTC_GPIO_CONF,
(READ_PERI_REG(RTC_GPIO_CONF) & 0xfffffffeUL) | 0x0UL); //mux configuration for out enable
WRITE_PERI_REG(RTC_GPIO_ENABLE,
(READ_PERI_REG(RTC_GPIO_ENABLE) & 0xfffffffeUL) | 0x1UL); //out enable
}
static void ICACHE_FLASH_ATTR
gpio16_input_conf(void) {
WRITE_PERI_REG(PAD_XPD_DCDC_CONF,
(READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbcUL) | 0x1UL); // mux configuration for XPD_DCDC and rtc_gpio0 connection
WRITE_PERI_REG(RTC_GPIO_CONF,
(READ_PERI_REG(RTC_GPIO_CONF) & 0xfffffffeUL) | 0x0UL); //mux configuration for out enable
WRITE_PERI_REG(RTC_GPIO_ENABLE,
READ_PERI_REG(RTC_GPIO_ENABLE) & 0xfffffffeUL); //out disable
}
/**
* Returns the number of active pins in the gpioMask.
*/
uint8_t ICACHE_FLASH_ATTR
easygpio_countBits(uint32_t gpioMask) {
uint8_t i=0;
uint8_t numberOfPins=0;
for (i=0; i<32; i++){
numberOfPins += (gpioMask & BIT(i))?1:0;
}
return numberOfPins;
}
/**
* Returns the gpio name and func for a specific pin.
*/
bool ICACHE_FLASH_ATTR
easygpio_getGPIONameFunc(uint8_t gpio_pin, uint32_t *gpio_name, uint8_t *gpio_func) {
if (gpio_pin == 6 || gpio_pin == 7 || gpio_pin == 8 || gpio_pin == 11 || gpio_pin >= 17) {
os_printf("easygpio_getGPIONameFunc Error: There is no GPIO%d, check your code\n", gpio_pin);
return false;
}
if (gpio_pin == 16) {
os_printf("easygpio_getGPIONameFunc Error: GPIO16 does not have gpio_name and gpio_func\n");
return false;
}
switch ( gpio_pin ) {
case 0:
*gpio_func = FUNC_GPIO0;
*gpio_name = PERIPHS_IO_MUX_GPIO0_U;
return true;
case 1:
*gpio_func = FUNC_GPIO1;
*gpio_name = PERIPHS_IO_MUX_U0TXD_U;
return true;
case 2:
*gpio_func = FUNC_GPIO2;
*gpio_name = PERIPHS_IO_MUX_GPIO2_U;
return true;
case 3:
*gpio_func = FUNC_GPIO3;
*gpio_name = PERIPHS_IO_MUX_U0RXD_U;
return true;
case 4:
*gpio_func = FUNC_GPIO4;
*gpio_name = PERIPHS_IO_MUX_GPIO4_U;
return true;
case 5:
*gpio_func = FUNC_GPIO5;
*gpio_name = PERIPHS_IO_MUX_GPIO5_U;
return true;
case 9:
*gpio_func = FUNC_GPIO9;
*gpio_name = PERIPHS_IO_MUX_SD_DATA2_U;
return true;
case 10:
*gpio_func = FUNC_GPIO10;
*gpio_name = PERIPHS_IO_MUX_SD_DATA3_U;
return true;
case 12:
*gpio_func = FUNC_GPIO12;
*gpio_name = PERIPHS_IO_MUX_MTDI_U;
return true;
case 13:
*gpio_func = FUNC_GPIO13;
*gpio_name = PERIPHS_IO_MUX_MTCK_U;
return true;
case 14:
*gpio_func = FUNC_GPIO14;
*gpio_name = PERIPHS_IO_MUX_MTMS_U;
return true;
case 15:
*gpio_func = FUNC_GPIO15;
*gpio_name = PERIPHS_IO_MUX_MTDO_U;
return true;
default:
return false;
}
return true;
}
/**
* Sets the pull up registers for a pin.
*/
static void ICACHE_FLASH_ATTR
easygpio_setupPullsByName(uint32_t gpio_name, EasyGPIO_PullStatus pullStatus) {
if (EASYGPIO_PULLUP == pullStatus) {
PIN_PULLUP_EN(gpio_name);
} else {
PIN_PULLUP_DIS(gpio_name);
}
}
/**
* Sets the pull registers for a pin.
*/
bool ICACHE_FLASH_ATTR
easygpio_pullMode(uint8_t gpio_pin, EasyGPIO_PullStatus pullStatus) {
uint32_t gpio_name;
uint8_t gpio_func;
if (!easygpio_getGPIONameFunc(gpio_pin, &gpio_name, &gpio_func) ) {
return false;
}
easygpio_setupPullsByName(gpio_name, pullStatus);
return true;
}
/**
* Sets the 'gpio_pin' pin as a GPIO and sets the pull register for that pin.
* 'pullStatus' has no effect on output pins or GPIO16
*/
bool ICACHE_FLASH_ATTR
easygpio_pinMode(uint8_t gpio_pin, EasyGPIO_PullStatus pullStatus, EasyGPIO_PinMode pinMode) {
uint32_t gpio_name;
uint8_t gpio_func;
if (16==gpio_pin) {
// ignoring pull status on GPIO16 for now
if (EASYGPIO_OUTPUT == pinMode) {
gpio16_output_conf();
} else {
gpio16_input_conf();
}
return true;
} else if (!easygpio_getGPIONameFunc(gpio_pin, &gpio_name, &gpio_func) ) {
return false;
}
PIN_FUNC_SELECT(gpio_name, gpio_func);
easygpio_setupPullsByName(gpio_name, pullStatus);
if (EASYGPIO_OUTPUT != pinMode) {
GPIO_DIS_OUTPUT(GPIO_ID_PIN(gpio_pin));
} else {
// must enable the pin or else the WRITE_PERI_REG won't work
gpio_output_set(0, 0, BIT(GPIO_ID_PIN(gpio_pin)),0);
}
return true;
}
/**
* Sets the 'gpio_pin' pin as a GPIO and sets the interrupt to trigger on that pin.
* The 'interruptArg' is the function argument that will be sent to your interruptHandler
*/
bool ICACHE_FLASH_ATTR
easygpio_attachInterrupt(uint8_t gpio_pin, EasyGPIO_PullStatus pullStatus, void (*interruptHandler)(void *arg), void *interruptArg) {
uint32_t gpio_name;
uint8_t gpio_func;
if (gpio_pin == 16) {
os_printf("easygpio_setupInterrupt Error: GPIO16 does not have interrupts\n");
return false;
}
if (!easygpio_getGPIONameFunc(gpio_pin, &gpio_name, &gpio_func) ) {
return false;
}
ETS_GPIO_INTR_ATTACH(interruptHandler, interruptArg);
ETS_GPIO_INTR_DISABLE();
PIN_FUNC_SELECT(gpio_name, gpio_func);
easygpio_setupPullsByName(gpio_name, pullStatus);
// disable output
GPIO_DIS_OUTPUT(gpio_pin);
gpio_register_set(GPIO_PIN_ADDR(gpio_pin), GPIO_PIN_INT_TYPE_SET(GPIO_PIN_INTR_DISABLE)
| GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_DISABLE)
| GPIO_PIN_SOURCE_SET(GPIO_AS_PIN_SOURCE));
//clear gpio14 status
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(gpio_pin));
ETS_GPIO_INTR_ENABLE();
return true;
}
/**
* Detach the interrupt handler from the 'gpio_pin' pin.
*/
bool ICACHE_FLASH_ATTR
easygpio_detachInterrupt(uint8_t gpio_pin) {
if (gpio_pin == 16) {
os_printf("easygpio_setupInterrupt Error: GPIO16 does not have interrupts\n");
return false;
}
// Don't know how to detach interrupt, yet.
// Quick and dirty fix - just disable the interrupt
gpio_pin_intr_state_set(GPIO_ID_PIN(gpio_pin), GPIO_PIN_INTR_DISABLE);
return true;
}
/**
* Uniform way of setting GPIO output value. Handles GPIO 0-16.
*
* You can not rely on that this function will switch the gpio to an output like GPIO_OUTPUT_SET does.
* Use easygpio_outputEnable() to change an input gpio to output mode.
*/
void
easygpio_outputSet(uint8_t gpio_pin, uint8_t value) {
if (16==gpio_pin) {
WRITE_PERI_REG(RTC_GPIO_OUT,
(READ_PERI_REG(RTC_GPIO_OUT) & 0xfffffffeUL) | (0x1UL & value));
} else {
#ifdef EASYGPIO_USE_GPIO_OUTPUT_SET
GPIO_OUTPUT_SET(GPIO_ID_PIN(gpio_pin), value);
#else
if (value&1){
WRITE_PERI_REG( PERIPHS_GPIO_BASEADDR, READ_PERI_REG(PERIPHS_GPIO_BASEADDR) | BIT(gpio_pin));
} else {
WRITE_PERI_REG( PERIPHS_GPIO_BASEADDR, READ_PERI_REG(PERIPHS_GPIO_BASEADDR) & ~BIT(gpio_pin));
}
#endif
}
}
/**
* Uniform way of getting GPIO input value. Handles GPIO 0-16.
* The pin must be initiated with easygpio_pinMode() so that the pin mux is setup as a gpio in the first place.
* If you know that you won't be using GPIO16 then you'd better off by just using GPIO_INPUT_GET().
*/
uint8_t
easygpio_inputGet(uint8_t gpio_pin) {
if (16==gpio_pin) {
return (READ_PERI_REG(RTC_GPIO_IN_DATA) & 1UL);
} else {
#ifdef EASYGPIO_USE_GPIO_INPUT_GET
return GPIO_INPUT_GET(GPIO_ID_PIN(gpio_pin));
#else
// this does *not* work, maybe GPIO_IN_ADDRESS is the wrong address
return ((GPIO_REG_READ(GPIO_IN_ADDRESS) > gpio_pin) & 1UL);
#endif
}
}
/**
* Uniform way of turning an output GPIO pin into input mode. Handles GPIO 0-16.
* The pin must be initiated with easygpio_pinMode() so that the pin mux is setup as a gpio in the first place.
* This function does the same thing as GPIO_DIS_OUTPUT, but works on GPIO16 too.
*/
void easygpio_outputDisable(uint8_t gpio_pin) {
if (16==gpio_pin) {
WRITE_PERI_REG(RTC_GPIO_ENABLE,
READ_PERI_REG(RTC_GPIO_ENABLE) & 0xfffffffeUL); //out disable
} else {
GPIO_DIS_OUTPUT(GPIO_ID_PIN(gpio_pin));
}
}
/**
* Uniform way of turning an input GPIO pin into output mode. Handles GPIO 0-16.
* The pin must be initiated with easygpio_pinMode() so that the pin mux is setup as a gpio in the first place.
*
* This function:
* - should only be used to convert a input pin into an output pin.
* - is a little bit slower than easygpio_outputSet() so you should use that
* function to just change output value.
* - does the same thing as GPIO_OUTPUT_SET, but works on GPIO16 too.
*/
void easygpio_outputEnable(uint8_t gpio_pin, uint8_t value) {
if (16==gpio_pin) {
// write the value before flipping to output
// - so we don't flash previous value for a few ns.
WRITE_PERI_REG(RTC_GPIO_OUT,
(READ_PERI_REG(RTC_GPIO_OUT) & 0xfffffffeUL) | (0x1UL & value));
WRITE_PERI_REG(RTC_GPIO_ENABLE,
(READ_PERI_REG(RTC_GPIO_ENABLE) & 0xfffffffeUL) | 0x1UL); //out enable
} else {
GPIO_OUTPUT_SET(GPIO_ID_PIN(gpio_pin), value);
}
}

114
easygpio/easygpio.h 100644
Wyświetl plik

@ -0,0 +1,114 @@
/*
* easygpio.h
*
* Copyright (c) 2015, eadf (https://github.com/eadf)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef EASYGPIO_INCLUDE_EASYGPIO_EASYGPIO_H_
#define EASYGPIO_INCLUDE_EASYGPIO_EASYGPIO_H_
#include "c_types.h"
typedef enum {
EASYGPIO_INPUT=0,
EASYGPIO_OUTPUT=1
} EasyGPIO_PinMode;
typedef enum {
EASYGPIO_PULLUP=3,
EASYGPIO_NOPULL=4
} EasyGPIO_PullStatus;
/**
* Returns the gpio name and func for a specific pin.
*/
bool easygpio_getGPIONameFunc(uint8_t gpio_pin, uint32_t *gpio_name, uint8_t *gpio_func);
/**
* Sets the 'gpio_pin' pin as a GPIO and sets the interrupt to trigger on that pin.
* The 'interruptArg' is the function argument that will be sent to your interruptHandler
* (this way you can several interrupts with one interruptHandler)
*/
bool easygpio_attachInterrupt(uint8_t gpio_pin, EasyGPIO_PullStatus pullStatus, void (*interruptHandler)(void *arg), void *interruptArg);
/**
* Deatach the interrupt handler from the 'gpio_pin' pin.
*/
bool easygpio_detachInterrupt(uint8_t gpio_pin);
/**
* Returns the number of active pins in the gpioMask.
*/
uint8_t easygpio_countBits(uint32_t gpioMask);
/**
* Sets the 'gpio_pin' pin as a GPIO and enables/disables the pull-up on that pin.
* 'pullStatus' has no effect on output pins or GPIO16
*/
bool easygpio_pinMode(uint8_t gpio_pin, EasyGPIO_PullStatus pullStatus, EasyGPIO_PinMode pinMode);
/**
* Enable or disable the internal pull up for a pin.
*/
bool easygpio_pullMode(uint8_t gpio_pin, EasyGPIO_PullStatus pullStatus);
/**
* Uniform way of getting GPIO input value. Handles GPIO 0-16.
* The pin must be initiated with easygpio_pinMode() so that the pin mux is setup as a gpio in the first place.
* If you know that you won't be using GPIO16 then you'd better off by just using GPIO_INPUT_GET().
*/
uint8_t easygpio_inputGet(uint8_t gpio_pin);
/**
* Uniform way of setting GPIO output value. Handles GPIO 0-16.
*
* You can not rely on that this function will switch the gpio to an output like GPIO_OUTPUT_SET does.
* Use easygpio_outputEnable() to change an input gpio to output mode.
*/
void easygpio_outputSet(uint8_t gpio_pin, uint8_t value);
/**
* Uniform way of turning an output GPIO pin into input mode. Handles GPIO 0-16.
* The pin must be initiated with easygpio_pinMode() so that the pin mux is setup as a gpio in the first place.
* This function does the same thing as GPIO_DIS_OUTPUT, but works on GPIO16 too.
*/
void easygpio_outputDisable(uint8_t gpio_pin);
/**
* Uniform way of turning an input GPIO pin into output mode. Handles GPIO 0-16.
* The pin must be initiated with easygpio_pinMode() so that the pin mux is setup as a gpio in the first place.
*
* This function:
* - should only be used to convert a input pin into an output pin.
* - is a little bit slower than easygpio_outputSet() so you should use that
* function to just change output value.
* - does the same thing as GPIO_OUTPUT_SET, but works on GPIO16 too.
*/
void easygpio_outputEnable(uint8_t gpio_pin, uint8_t value);
#endif /* EASYGPIO_INCLUDE_EASYGPIO_EASYGPIO_H_ */

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -0,0 +1,525 @@
/*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* Martin d'Allens <martin.dallens@gmail.com> wrote this file. As long as you retain
* this notice you can do whatever you want with this stuff. If we meet some day,
* and you think this stuff is worth it, you can buy me a beer in return.
* ----------------------------------------------------------------------------
*/
// FIXME: sprintf->snprintf everywhere.
#include "osapi.h"
#include "user_interface.h"
#include "espconn.h"
#include "mem.h"
#include "limits.h"
#include "httpclient.h"
// Debug output.
#if 0
#define PRINTF(...) os_printf(__VA_ARGS__)
#else
#define PRINTF(...)
#endif
// Internal state.
typedef struct {
char * path;
int port;
char * post_data;
char * headers;
char * hostname;
char * buffer;
int buffer_size;
bool secure;
http_callback user_callback;
} request_args;
static char * ICACHE_FLASH_ATTR esp_strdup(const char * str)
{
if (str == NULL) {
return NULL;
}
char * new_str = (char *)os_malloc(os_strlen(str) + 1); // 1 for null character
if (new_str == NULL) {
os_printf("esp_strdup: malloc error");
return NULL;
}
os_strcpy(new_str, str);
return new_str;
}
static int ICACHE_FLASH_ATTR
esp_isupper(char c)
{
return (c >= 'A' && c <= 'Z');
}
static int ICACHE_FLASH_ATTR
esp_isalpha(char c)
{
return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'));
}
static int ICACHE_FLASH_ATTR
esp_isspace(char c)
{
return (c == ' ' || c == '\t' || c == '\n' || c == '\12');
}
static int ICACHE_FLASH_ATTR
esp_isdigit(char c)
{
return (c >= '0' && c <= '9');
}
/*
* Convert a string to a long integer.
*
* Ignores `locale' stuff. Assumes that the upper and lower case
* alphabets and digits are each contiguous.
*/
static long ICACHE_FLASH_ATTR
esp_strtol(const char *nptr, char **endptr, int base)
{
const char *s = nptr;
unsigned long acc;
int c;
unsigned long cutoff;
int neg = 0, any, cutlim;
/*
* Skip white space and pick up leading +/- sign if any.
* If base is 0, allow 0x for hex and 0 for octal, else
* assume decimal; if base is already 16, allow 0x.
*/
do {
c = *s++;
} while (esp_isspace(c));
if (c == '-') {
neg = 1;
c = *s++;
} else if (c == '+')
c = *s++;
if ((base == 0 || base == 16) &&
c == '0' && (*s == 'x' || *s == 'X')) {
c = s[1];
s += 2;
base = 16;
} else if ((base == 0 || base == 2) &&
c == '0' && (*s == 'b' || *s == 'B')) {
c = s[1];
s += 2;
base = 2;
}
if (base == 0)
base = c == '0' ? 8 : 10;
/*
* Compute the cutoff value between legal numbers and illegal
* numbers. That is the largest legal value, divided by the
* base. An input number that is greater than this value, if
* followed by a legal input character, is too big. One that
* is equal to this value may be valid or not; the limit
* between valid and invalid numbers is then based on the last
* digit. For instance, if the range for longs is
* [-2147483648..2147483647] and the input base is 10,
* cutoff will be set to 214748364 and cutlim to either
* 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
* a value > 214748364, or equal but the next digit is > 7 (or 8),
* the number is too big, and we will return a range error.
*
* Set any if any `digits' consumed; make it negative to indicate
* overflow.
*/
cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
cutlim = cutoff % (unsigned long)base;
cutoff /= (unsigned long)base;
for (acc = 0, any = 0;; c = *s++) {
if (esp_isdigit(c))
c -= '0';
else if (esp_isalpha(c))
c -= esp_isupper(c) ? 'A' - 10 : 'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = neg ? LONG_MIN : LONG_MAX;
// errno = ERANGE;
} else if (neg)
acc = -acc;
if (endptr != 0)
*endptr = (char *)(any ? s - 1 : nptr);
return (acc);
}
static int ICACHE_FLASH_ATTR chunked_decode(char * chunked, int size)
{
char *src = chunked;
char *end = chunked + size;
int i, dst = 0;
do
{
//[chunk-size]
i = esp_strtol(src, (char **) NULL, 16);
PRINTF("Chunk Size:%d\r\n", i);
if (i <= 0)
break;
//[chunk-size-end-ptr]
src = (char *)os_strstr(src, "\r\n") + 2;
//[chunk-data]
os_memmove(&chunked[dst], src, i);
src += i + 2; /* CRLF */
dst += i;
} while (src < end);
//
//footer CRLF
//
/* decoded size */
return dst;
}
static void ICACHE_FLASH_ATTR receive_callback(void * arg, char * buf, unsigned short len)
{
struct espconn * conn = (struct espconn *)arg;
request_args * req = (request_args *)conn->reverse;
if (req->buffer == NULL) {
return;
}
// Let's do the equivalent of a realloc().
const int new_size = req->buffer_size + len;
char * new_buffer;
if (new_size > BUFFER_SIZE_MAX || NULL == (new_buffer = (char *)os_malloc(new_size))) {
os_printf("Response too long (%d)\n", new_size);
req->buffer[0] = '\0'; // Discard the buffer to avoid using an incomplete response.
if (req->secure)
#ifdef HTTPCS
espconn_secure_disconnect(conn);
#else
os_printf("SSL not available\r\n");
#endif
else
espconn_disconnect(conn);
return; // The disconnect callback will be called.
}
os_memcpy(new_buffer, req->buffer, req->buffer_size);
os_memcpy(new_buffer + req->buffer_size - 1 /*overwrite the null character*/, buf, len); // Append new data.
new_buffer[new_size - 1] = '\0'; // Make sure there is an end of string.
os_free(req->buffer);
req->buffer = new_buffer;
req->buffer_size = new_size;
}
static void ICACHE_FLASH_ATTR sent_callback(void * arg)
{
struct espconn * conn = (struct espconn *)arg;
request_args * req = (request_args *)conn->reverse;
if (req->post_data == NULL) {
PRINTF("All sent\n");
}
else {
// The headers were sent, now send the contents.
PRINTF("Sending request body\n");
if (req->secure)
#ifdef HTTPCS
espconn_secure_sent(conn, (uint8_t *)req->post_data, strlen(req->post_data));
#else
os_printf("SSL not available\r\n");
#endif
else
espconn_sent(conn, (uint8_t *)req->post_data, strlen(req->post_data));
os_free(req->post_data);
req->post_data = NULL;
}
}
static void ICACHE_FLASH_ATTR connect_callback(void * arg)
{
PRINTF("Connected\n");
struct espconn * conn = (struct espconn *)arg;
request_args * req = (request_args *)conn->reverse;
espconn_regist_recvcb(conn, receive_callback);
espconn_regist_sentcb(conn, sent_callback);
const char * method = "GET";
char post_headers[32] = "";
if (req->post_data != NULL) { // If there is data this is a POST request.
method = "POST";
os_sprintf(post_headers, "Content-Length: %d\r\n", strlen(req->post_data));
}
char buf[69 + strlen(method) + strlen(req->path) + strlen(req->hostname) +
strlen(req->headers) + strlen(post_headers)];
int len = os_sprintf(buf,
"%s %s HTTP/1.1\r\n"
"Host: %s:%d\r\n"
"Connection: close\r\n"
"User-Agent: ESP8266\r\n"
"%s"
"%s"
"\r\n",
method, req->path, req->hostname, req->port, req->headers, post_headers);
if (req->secure)
#ifdef HTTPCS
espconn_secure_sent(conn, (uint8_t *)buf, len);
#else
os_printf("SSL not available\r\n");
#endif
else
espconn_sent(conn, (uint8_t *)buf, len);
os_free(req->headers);
req->headers = NULL;
PRINTF("Sending request header\n");
}
static void ICACHE_FLASH_ATTR disconnect_callback(void * arg)
{
PRINTF("Disconnected\n");
struct espconn *conn = (struct espconn *)arg;
if(conn == NULL) {
return;
}
if(conn->reverse != NULL) {
request_args * req = (request_args *)conn->reverse;
int http_status = -1;
int body_size = 0;
char * body = "";
if (req->buffer == NULL) {
os_printf("Buffer shouldn't be NULL\n");
}
else if (req->buffer[0] != '\0') {
// FIXME: make sure this is not a partial response, using the Content-Length header.
const char * version10 = "HTTP/1.0 ";
const char * version11 = "HTTP/1.1 ";
if (os_strncmp(req->buffer, version10, strlen(version10)) != 0
&& os_strncmp(req->buffer, version11, strlen(version11)) != 0) {
os_printf("Invalid version in %s\n", req->buffer);
}
else {
http_status = atoi(req->buffer + strlen(version10));
/* find body and zero terminate headers */
body = (char *)os_strstr(req->buffer, "\r\n\r\n") + 2;
*body++ = '\0';
*body++ = '\0';
body_size = req->buffer_size - (body - req->buffer);
if(os_strstr(req->buffer, "Transfer-Encoding: chunked"))
{
body_size = chunked_decode(body, body_size);
body[body_size] = '\0';
}
}
}
if (req->user_callback != NULL) { // Callback is optional.
req->user_callback(req->hostname, req->path, body, http_status, req->buffer, body_size);
}
os_free(req->buffer);
os_free(req->hostname);
os_free(req->path);
os_free(req);
}
espconn_delete(conn);
if(conn->proto.tcp != NULL) {
os_free(conn->proto.tcp);
}
os_free(conn);
}
static void ICACHE_FLASH_ATTR error_callback(void *arg, sint8 errType)
{
PRINTF("Disconnected with error\n");
disconnect_callback(arg);
}
static void ICACHE_FLASH_ATTR dns_callback(const char * hostname, ip_addr_t * addr, void * arg)
{
request_args * req = (request_args *)arg;
if (addr == NULL) {
os_printf("DNS failed for %s\n", hostname);
if (req->user_callback != NULL) {
req->user_callback(req->hostname, req->path, "", -1, "", 0);
}
os_free(req->buffer);
os_free(req->post_data);
os_free(req->headers);
os_free(req->path);
os_free(req->hostname);
os_free(req);
}
else {
PRINTF("DNS found %s " IPSTR "\n", hostname, IP2STR(addr));
struct espconn * conn = (struct espconn *)os_malloc(sizeof(struct espconn));
conn->type = ESPCONN_TCP;
conn->state = ESPCONN_NONE;
conn->proto.tcp = (esp_tcp *)os_malloc(sizeof(esp_tcp));
conn->proto.tcp->local_port = espconn_port();
conn->proto.tcp->remote_port = req->port;
conn->reverse = req;
os_memcpy(conn->proto.tcp->remote_ip, addr, 4);
espconn_regist_connectcb(conn, connect_callback);
espconn_regist_disconcb(conn, disconnect_callback);
espconn_regist_reconcb(conn, error_callback);
if (req->secure) {
#ifdef HTTPCS
espconn_secure_set_size(ESPCONN_CLIENT,5120); // set SSL buffer size
espconn_secure_connect(conn);
#else
os_printf("SSL not available\r\n");
#endif
} else {
espconn_connect(conn);
}
}
}
void ICACHE_FLASH_ATTR http_raw_request(const char * hostname, int port, bool secure, const char * path, const char * post_data, const char * headers, http_callback user_callback)
{
PRINTF("DNS request\n");
request_args * req = (request_args *)os_malloc(sizeof(request_args));
req->hostname = esp_strdup(hostname);
req->path = esp_strdup(path);
req->port = port;
req->secure = secure;
req->headers = esp_strdup(headers);
req->post_data = esp_strdup(post_data);
req->buffer_size = 1;
req->buffer = (char *)os_malloc(1);
req->buffer[0] = '\0'; // Empty string.
req->user_callback = user_callback;
ip_addr_t addr;
err_t error = espconn_gethostbyname((struct espconn *)req, // It seems we don't need a real espconn pointer here.
hostname, &addr, dns_callback);
if (error == ESPCONN_INPROGRESS) {
PRINTF("DNS pending\n");
}
else if (error == ESPCONN_OK) {
// Already in the local names table (or hostname was an IP address), execute the callback ourselves.
dns_callback(hostname, &addr, req);
}
else {
if (error == ESPCONN_ARG) {
os_printf("DNS arg error %s\n", hostname);
}
else {
os_printf("DNS error code %d\n", error);
}
dns_callback(hostname, NULL, req); // Handle all DNS errors the same way.
}
}
/*
* Parse an URL of the form http://host:port/path
* <host> can be a hostname or an IP address
* <port> is optional
*/
void ICACHE_FLASH_ATTR http_post(const char * url, const char * post_data, const char * headers, http_callback user_callback)
{
// FIXME: handle HTTP auth with http://user:pass@host/
// FIXME: get rid of the #anchor part if present.
char hostname[128] = "";
int port = 80;
bool secure = false;
bool is_http = os_strncmp(url, "http://", strlen("http://")) == 0;
bool is_https = os_strncmp(url, "https://", strlen("https://")) == 0;
if (is_http)
url += strlen("http://"); // Get rid of the protocol.
else if (is_https) {
port = 443;
secure = true;
url += strlen("https://"); // Get rid of the protocol.
} else {
os_printf("URL is not HTTP or HTTPS %s\n", url);
return;
}
char * path = os_strchr(url, '/');
if (path == NULL) {
path = os_strchr(url, '\0'); // Pointer to end of string.
}
char * colon = os_strchr(url, ':');
if (colon > path) {
colon = NULL; // Limit the search to characters before the path.
}
if (colon == NULL) { // The port is not present.
os_memcpy(hostname, url, path - url);
hostname[path - url] = '\0';
}
else {
port = atoi(colon + 1);
if (port == 0) {
os_printf("Port error %s\n", url);
return;
}
os_memcpy(hostname, url, colon - url);
hostname[colon - url] = '\0';
}
if (path[0] == '\0') { // Empty path is not allowed.
path = "/";
}
PRINTF("hostname=%s\n", hostname);
PRINTF("port=%d\n", port);
PRINTF("path=%s\n", path);
http_raw_request(hostname, port, secure, path, post_data, headers, user_callback);
}
void ICACHE_FLASH_ATTR http_get(const char * url, const char * headers, http_callback user_callback)
{
http_post(url, NULL, headers, user_callback);
}
void ICACHE_FLASH_ATTR http_callback_example(char * response_body, int http_status, char * response_headers, int body_size)
{
os_printf("http_status=%d\n", http_status);
if (http_status != HTTP_STATUS_GENERIC_ERROR) {
os_printf("strlen(headers)=%d\n", strlen(response_headers));
os_printf("body_size=%d\n", body_size);
os_printf("body=%s<EOF>\n", response_body); // FIXME: this does not handle binary data.
}
}

Wyświetl plik

@ -0,0 +1,53 @@
/*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* Martin d'Allens <martin.dallens@gmail.com> wrote this file. As long as you retain
* this notice you can do whatever you want with this stuff. If we meet some day,
* and you think this stuff is worth it, you can buy me a beer in return.
* ----------------------------------------------------------------------------
*/
#ifndef HTTPCLIENT_H
#define HTTPCLIENT_H
//#include <espmissingincludes.h> // This can remove some warnings depending on your project setup. It is safe to remove this line.
#define HTTP_STATUS_GENERIC_ERROR -1 // In case of TCP or DNS error the callback is called with this status.
#define BUFFER_SIZE_MAX 5000 // Size of http responses that will cause an error.
/*
* "full_response" is a string containing all response headers and the response body.
* "response_body and "http_status" are extracted from "full_response" for convenience.
*
* A successful request corresponds to an HTTP status code of 200 (OK).
* More info at http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
*/
typedef void (* http_callback)(char* hostname, char* path, char * response_body, int http_status, char * response_headers, int body_size);
/*
* Download a web page from its URL.
* Try:
* http_get("http://wtfismyip.com/text", http_callback_example);
*/
void ICACHE_FLASH_ATTR http_get(const char * url, const char * headers, http_callback user_callback);
/*
* Post data to a web form.
* The data should be encoded as application/x-www-form-urlencoded.
* Try:
* http_post("http://httpbin.org/post", "first_word=hello&second_word=world", http_callback_example);
*/
void ICACHE_FLASH_ATTR http_post(const char * url, const char * post_data, const char * headers, http_callback user_callback);
/*
* Call this function to skip URL parsing if the arguments are already in separate variables.
*/
void ICACHE_FLASH_ATTR http_raw_request(const char * hostname, int port, bool secure, const char * path, const char * post_data, const char * headers, http_callback user_callback);
/*
* Output on the UART.
*/
void ICACHE_FLASH_ATTR http_callback_example(char * response_body, int http_status, char * response_headers, int body_size);
#endif

Wyświetl plik

@ -1,3 +1,19 @@
/*
* File : uart.h
* Copyright (C) 2013 - 2016, Espressif Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of version 3 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef UART_APP_H
#define UART_APP_H
@ -5,11 +21,29 @@
#include "eagle_soc.h"
#include "c_types.h"
#define RX_BUFF_SIZE 256
#define TX_BUFF_SIZE 100
#define UART_TX_BUFFER_SIZE 256 //Ring buffer length of tx buffer
#define UART_RX_BUFFER_SIZE 256 //Ring buffer length of rx buffer
#define UART_BUFF_EN 0 //use uart buffer , FOR UART0
#define UART_SELFTEST 0 //set 1:enable the loop test demo for uart buffer, FOR UART0
#define UART_HW_RTS 0 //set 1: enable uart hw flow control RTS, PIN MTDO, FOR UART0
#define UART_HW_CTS 0 //set1: enable uart hw flow contrl CTS , PIN MTCK, FOR UART0
#define _ENABLE_CONSOLE_INTEGRATION 1
#define _ENABLE_RING_BUFFER 1
#ifdef _ENABLE_RING_BUFFER
#include "ringbuf.h"
#define RX_RING_BUFFER_SIZE 250
#endif
#define UART0 0
#define UART1 1
typedef enum {
FIVE_BITS = 0x0,
SIX_BITS = 0x1,
@ -18,33 +52,48 @@ typedef enum {
} UartBitsNum4Char;
typedef enum {
ONE_STOP_BIT = 0,
ONE_HALF_STOP_BIT = BIT2,
TWO_STOP_BIT = BIT2
ONE_STOP_BIT = 0x1,
ONE_HALF_STOP_BIT = 0x2,
TWO_STOP_BIT = 0x3
} UartStopBitsNum;
typedef enum {
NONE_BITS = 0,
ODD_BITS = 0,
EVEN_BITS = BIT4
NONE_BITS = 0x2,
ODD_BITS = 1,
EVEN_BITS = 0
} UartParityMode;
typedef enum {
STICK_PARITY_DIS = 0,
STICK_PARITY_EN = BIT3 | BIT5
STICK_PARITY_EN = 1
} UartExistParity;
typedef enum {
BIT_RATE_9600 = 9600,
BIT_RATE_19200 = 19200,
BIT_RATE_38400 = 38400,
BIT_RATE_57600 = 57600,
BIT_RATE_74880 = 74880,
UART_None_Inverse = 0x0,
UART_Rxd_Inverse = UART_RXD_INV,
UART_CTS_Inverse = UART_CTS_INV,
UART_Txd_Inverse = UART_TXD_INV,
UART_RTS_Inverse = UART_RTS_INV,
} UART_LineLevelInverse;
typedef enum {
BIT_RATE_300 = 300,
BIT_RATE_600 = 600,
BIT_RATE_1200 = 1200,
BIT_RATE_2400 = 2400,
BIT_RATE_4800 = 4800,
BIT_RATE_9600 = 9600,
BIT_RATE_19200 = 19200,
BIT_RATE_38400 = 38400,
BIT_RATE_57600 = 57600,
BIT_RATE_74880 = 74880,
BIT_RATE_115200 = 115200,
BIT_RATE_230400 = 230400,
BIT_RATE_256000 = 256000,
BIT_RATE_460800 = 460800,
BIT_RATE_921600 = 921600
BIT_RATE_921600 = 921600,
BIT_RATE_1843200 = 1843200,
BIT_RATE_3686400 = 3686400,
} UartBautRate;
typedef enum {
@ -53,6 +102,13 @@ typedef enum {
XON_XOFF_CTRL
} UartFlowCtrl;
typedef enum {
USART_HardwareFlowControl_None = 0x0,
USART_HardwareFlowControl_RTS = 0x1,
USART_HardwareFlowControl_CTS = 0x2,
USART_HardwareFlowControl_CTS_RTS = 0x3
} UART_HwFlowCtrl;
typedef enum {
EMPTY,
UNDER_WRITE,
@ -85,7 +141,7 @@ typedef struct {
UartBautRate baut_rate;
UartBitsNum4Char data_bits;
UartExistParity exist_parity;
UartParityMode parity; // chip size in byte
UartParityMode parity;
UartStopBitsNum stop_bits;
UartFlowCtrl flow_ctrl;
RcvMsgBuff rcv_buff;
@ -97,5 +153,82 @@ typedef struct {
void uart_init(UartBautRate uart0_br, UartBautRate uart1_br);
void uart0_sendStr(const char *str);
///////////////////////////////////////
#define UART_FIFO_LEN 128 //define the tx fifo length
#define UART_TX_EMPTY_THRESH_VAL 0x10
struct UartBuffer{
uint32 UartBuffSize;
uint8 *pUartBuff;
uint8 *pInPos;
uint8 *pOutPos;
STATUS BuffState;
uint16 Space; //remanent space of the buffer
uint8 TcpControl;
struct UartBuffer * nextBuff;
};
struct UartRxBuff{
uint32 UartRxBuffSize;
uint8 *pUartRxBuff;
uint8 *pWritePos;
uint8 *pReadPos;
STATUS RxBuffState;
uint32 Space; //remanent space of the buffer
} ;
typedef enum {
RUN = 0,
BLOCK = 1,
} TCPState;
//void ICACHE_FLASH_ATTR uart_test_rx();
STATUS uart_tx_one_char(uint8 uart, uint8 TxChar);
STATUS uart_tx_one_char_no_wait(uint8 uart, uint8 TxChar);
void uart1_sendStr_no_wait(const char *str);
struct UartBuffer* Uart_Buf_Init();
#if UART_BUFF_EN
LOCAL void Uart_Buf_Cpy(struct UartBuffer* pCur, char* pdata , uint16 data_len);
void uart_buf_free(struct UartBuffer* pBuff);
void tx_buff_enq(char* pdata, uint16 data_len );
LOCAL void tx_fifo_insert(struct UartBuffer* pTxBuff, uint8 data_len, uint8 uart_no);
void tx_start_uart_buffer(uint8 uart_no);
uint16 rx_buff_deq(char* pdata, uint16 data_len );
void Uart_rx_buff_enq();
#endif
void uart_rx_intr_enable(uint8 uart_no);
void uart_rx_intr_disable(uint8 uart_no);
void uart0_tx_buffer(uint8 *buf, uint16 len);
//==============================================
#define FUNC_UART0_CTS 4
#define FUNC_U0CTS 4
#define FUNC_U1TXD_BK 2
#define UART_LINE_INV_MASK (0x3f<<19)
void UART_SetWordLength(uint8 uart_no, UartBitsNum4Char len);
void UART_SetStopBits(uint8 uart_no, UartStopBitsNum bit_num);
void UART_SetLineInverse(uint8 uart_no, UART_LineLevelInverse inverse_mask);
void UART_SetParity(uint8 uart_no, UartParityMode Parity_mode);
void UART_SetBaudrate(uint8 uart_no,uint32 baud_rate);
void UART_SetFlowCtrl(uint8 uart_no,UART_HwFlowCtrl flow_ctrl,uint8 rx_thresh);
void UART_WaitTxFifoEmpty(uint8 uart_no , uint32 time_out_us); //do not use if tx flow control enabled
void UART_ResetFifo(uint8 uart_no);
void UART_ClearIntrStatus(uint8 uart_no,uint32 clr_mask);
void UART_SetIntrEna(uint8 uart_no,uint32 ena_mask);
void UART_SetPrintPort(uint8 uart_no);
bool UART_CheckOutputFinished(uint8 uart_no, uint32 time_out_us);
//==============================================
void UART_init_console(UartBautRate uart0_br,
uint8 recv_task_priority,
ringbuf_t rxbuffer,
ringbuf_t txBuffer);
int UART_Echo(uint8 echo);
#endif

Wyświetl plik

@ -1,128 +1,156 @@
//Generated at 2012-07-03 18:44:06
/*
* File : uart_register.h
* Copyright (C) 2013 - 2016, Espressif Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of version 3 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Copyright (c) 2010 - 2011 Espressif System
*
*/
#ifndef UART_REGISTER_H_INCLUDED
#define UART_REGISTER_H_INCLUDED
#define REG_UART_BASE( i ) (0x60000000+(i)*0xf00)
#ifndef UART_REGISTER_H_
#define UART_REGISTER_H_
#define REG_UART_BASE(i) (0x60000000 + (i)*0xf00)
//version value:32'h062000
#define UART_FIFO( i ) (REG_UART_BASE( i ) + 0x0)
#define UART_RXFIFO_RD_BYTE 0x000000FF
#define UART_RXFIFO_RD_BYTE_S 0
#define UART_FIFO(i) (REG_UART_BASE(i) + 0x0)
#define UART_RXFIFO_RD_BYTE 0x000000FF
#define UART_RXFIFO_RD_BYTE_S 0
#define UART_INT_RAW( i ) (REG_UART_BASE( i ) + 0x4)
#define UART_RXFIFO_TOUT_INT_RAW (BIT(8))
#define UART_BRK_DET_INT_RAW (BIT(7))
#define UART_CTS_CHG_INT_RAW (BIT(6))
#define UART_DSR_CHG_INT_RAW (BIT(5))
#define UART_RXFIFO_OVF_INT_RAW (BIT(4))
#define UART_FRM_ERR_INT_RAW (BIT(3))
#define UART_PARITY_ERR_INT_RAW (BIT(2))
#define UART_TXFIFO_EMPTY_INT_RAW (BIT(1))
#define UART_RXFIFO_FULL_INT_RAW (BIT(0))
#define UART_INT_RAW(i) (REG_UART_BASE(i) + 0x4)
#define UART_RXFIFO_TOUT_INT_RAW (BIT(8))
#define UART_BRK_DET_INT_RAW (BIT(7))
#define UART_CTS_CHG_INT_RAW (BIT(6))
#define UART_DSR_CHG_INT_RAW (BIT(5))
#define UART_RXFIFO_OVF_INT_RAW (BIT(4))
#define UART_FRM_ERR_INT_RAW (BIT(3))
#define UART_PARITY_ERR_INT_RAW (BIT(2))
#define UART_TXFIFO_EMPTY_INT_RAW (BIT(1))
#define UART_RXFIFO_FULL_INT_RAW (BIT(0))
#define UART_INT_ST( i ) (REG_UART_BASE( i ) + 0x8)
#define UART_RXFIFO_TOUT_INT_ST (BIT(8))
#define UART_BRK_DET_INT_ST (BIT(7))
#define UART_CTS_CHG_INT_ST (BIT(6))
#define UART_DSR_CHG_INT_ST (BIT(5))
#define UART_RXFIFO_OVF_INT_ST (BIT(4))
#define UART_FRM_ERR_INT_ST (BIT(3))
#define UART_PARITY_ERR_INT_ST (BIT(2))
#define UART_TXFIFO_EMPTY_INT_ST (BIT(1))
#define UART_RXFIFO_FULL_INT_ST (BIT(0))
#define UART_INT_ST(i) (REG_UART_BASE(i) + 0x8)
#define UART_RXFIFO_TOUT_INT_ST (BIT(8))
#define UART_BRK_DET_INT_ST (BIT(7))
#define UART_CTS_CHG_INT_ST (BIT(6))
#define UART_DSR_CHG_INT_ST (BIT(5))
#define UART_RXFIFO_OVF_INT_ST (BIT(4))
#define UART_FRM_ERR_INT_ST (BIT(3))
#define UART_PARITY_ERR_INT_ST (BIT(2))
#define UART_TXFIFO_EMPTY_INT_ST (BIT(1))
#define UART_RXFIFO_FULL_INT_ST (BIT(0))
#define UART_INT_ENA( i ) (REG_UART_BASE( i ) + 0xC)
#define UART_RXFIFO_TOUT_INT_ENA (BIT(8))
#define UART_BRK_DET_INT_ENA (BIT(7))
#define UART_CTS_CHG_INT_ENA (BIT(6))
#define UART_DSR_CHG_INT_ENA (BIT(5))
#define UART_RXFIFO_OVF_INT_ENA (BIT(4))
#define UART_FRM_ERR_INT_ENA (BIT(3))
#define UART_PARITY_ERR_INT_ENA (BIT(2))
#define UART_TXFIFO_EMPTY_INT_ENA (BIT(1))
#define UART_RXFIFO_FULL_INT_ENA (BIT(0))
#define UART_INT_ENA(i) (REG_UART_BASE(i) + 0xC)
#define UART_RXFIFO_TOUT_INT_ENA (BIT(8))
#define UART_BRK_DET_INT_ENA (BIT(7))
#define UART_CTS_CHG_INT_ENA (BIT(6))
#define UART_DSR_CHG_INT_ENA (BIT(5))
#define UART_RXFIFO_OVF_INT_ENA (BIT(4))
#define UART_FRM_ERR_INT_ENA (BIT(3))
#define UART_PARITY_ERR_INT_ENA (BIT(2))
#define UART_TXFIFO_EMPTY_INT_ENA (BIT(1))
#define UART_RXFIFO_FULL_INT_ENA (BIT(0))
#define UART_INT_CLR( i ) (REG_UART_BASE( i ) + 0x10)
#define UART_RXFIFO_TOUT_INT_CLR (BIT(8))
#define UART_BRK_DET_INT_CLR (BIT(7))
#define UART_CTS_CHG_INT_CLR (BIT(6))
#define UART_DSR_CHG_INT_CLR (BIT(5))
#define UART_RXFIFO_OVF_INT_CLR (BIT(4))
#define UART_FRM_ERR_INT_CLR (BIT(3))
#define UART_PARITY_ERR_INT_CLR (BIT(2))
#define UART_TXFIFO_EMPTY_INT_CLR (BIT(1))
#define UART_RXFIFO_FULL_INT_CLR (BIT(0))
#define UART_INT_CLR(i) (REG_UART_BASE(i) + 0x10)
#define UART_RXFIFO_TOUT_INT_CLR (BIT(8))
#define UART_BRK_DET_INT_CLR (BIT(7))
#define UART_CTS_CHG_INT_CLR (BIT(6))
#define UART_DSR_CHG_INT_CLR (BIT(5))
#define UART_RXFIFO_OVF_INT_CLR (BIT(4))
#define UART_FRM_ERR_INT_CLR (BIT(3))
#define UART_PARITY_ERR_INT_CLR (BIT(2))
#define UART_TXFIFO_EMPTY_INT_CLR (BIT(1))
#define UART_RXFIFO_FULL_INT_CLR (BIT(0))
#define UART_CLKDIV( i ) (REG_UART_BASE( i ) + 0x14)
#define UART_CLKDIV_CNT 0x000FFFFF
#define UART_CLKDIV_S 0
#define UART_CLKDIV(i) (REG_UART_BASE(i) + 0x14)
#define UART_CLKDIV_CNT 0x000FFFFF
#define UART_CLKDIV_S 0
#define UART_AUTOBAUD( i ) (REG_UART_BASE( i ) + 0x18)
#define UART_GLITCH_FILT 0x000000FF
#define UART_GLITCH_FILT_S 8
#define UART_AUTOBAUD_EN (BIT(0))
#define UART_AUTOBAUD(i) (REG_UART_BASE(i) + 0x18)
#define UART_GLITCH_FILT 0x000000FF
#define UART_GLITCH_FILT_S 8
#define UART_AUTOBAUD_EN (BIT(0))
#define UART_STATUS( i ) (REG_UART_BASE( i ) + 0x1C)
#define UART_TXD (BIT(31))
#define UART_RTSN (BIT(30))
#define UART_DTRN (BIT(29))
#define UART_TXFIFO_CNT 0x000000FF
#define UART_TXFIFO_CNT_S 16
#define UART_RXD (BIT(15))
#define UART_CTSN (BIT(14))
#define UART_DSRN (BIT(13))
#define UART_RXFIFO_CNT 0x000000FF
#define UART_RXFIFO_CNT_S 0
#define UART_STATUS(i) (REG_UART_BASE(i) + 0x1C)
#define UART_TXD (BIT(31))
#define UART_RTSN (BIT(30))
#define UART_DTRN (BIT(29))
#define UART_TXFIFO_CNT 0x000000FF
#define UART_TXFIFO_CNT_S 16
#define UART_RXD (BIT(15))
#define UART_CTSN (BIT(14))
#define UART_DSRN (BIT(13))
#define UART_RXFIFO_CNT 0x000000FF
#define UART_RXFIFO_CNT_S 0
#define UART_CONF0( i ) (REG_UART_BASE( i ) + 0x20)
#define UART_TXFIFO_RST (BIT(18))
#define UART_RXFIFO_RST (BIT(17))
#define UART_IRDA_EN (BIT(16))
#define UART_TX_FLOW_EN (BIT(15))
#define UART_LOOPBACK (BIT(14))
#define UART_IRDA_RX_INV (BIT(13))
#define UART_IRDA_TX_INV (BIT(12))
#define UART_IRDA_WCTL (BIT(11))
#define UART_IRDA_TX_EN (BIT(10))
#define UART_IRDA_DPLX (BIT(9))
#define UART_TXD_BRK (BIT(8))
#define UART_SW_DTR (BIT(7))
#define UART_SW_RTS (BIT(6))
#define UART_STOP_BIT_NUM 0x00000003
#define UART_STOP_BIT_NUM_S 4
#define UART_BIT_NUM 0x00000003
#define UART_BIT_NUM_S 2
#define UART_PARITY_EN (BIT(1))
#define UART_PARITY (BIT(0))
#define UART_CONF0(i) (REG_UART_BASE(i) + 0x20)
#define UART_DTR_INV (BIT(24))
#define UART_RTS_INV (BIT(23))
#define UART_TXD_INV (BIT(22))
#define UART_DSR_INV (BIT(21))
#define UART_CTS_INV (BIT(20))
#define UART_RXD_INV (BIT(19))
#define UART_TXFIFO_RST (BIT(18))
#define UART_RXFIFO_RST (BIT(17))
#define UART_IRDA_EN (BIT(16))
#define UART_TX_FLOW_EN (BIT(15))
#define UART_LOOPBACK (BIT(14))
#define UART_IRDA_RX_INV (BIT(13))
#define UART_IRDA_TX_INV (BIT(12))
#define UART_IRDA_WCTL (BIT(11))
#define UART_IRDA_TX_EN (BIT(10))
#define UART_IRDA_DPLX (BIT(9))
#define UART_TXD_BRK (BIT(8))
#define UART_SW_DTR (BIT(7))
#define UART_SW_RTS (BIT(6))
#define UART_STOP_BIT_NUM 0x00000003
#define UART_STOP_BIT_NUM_S 4
#define UART_BIT_NUM 0x00000003
#define UART_BIT_NUM_S 2
#define UART_PARITY_EN (BIT(1))
#define UART_PARITY_EN_M 0x00000001
#define UART_PARITY_EN_S 1
#define UART_PARITY (BIT(0))
#define UART_PARITY_M 0x00000001
#define UART_PARITY_S 0
#define UART_CONF1( i ) (REG_UART_BASE( i ) + 0x24)
#define UART_RX_TOUT_EN (BIT(31))
#define UART_RX_TOUT_THRHD 0x0000007F
#define UART_RX_TOUT_THRHD_S 24
#define UART_RX_FLOW_EN (BIT(23))
#define UART_RX_FLOW_THRHD 0x0000007F
#define UART_RX_FLOW_THRHD_S 16
#define UART_TXFIFO_EMPTY_THRHD 0x0000007F
#define UART_TXFIFO_EMPTY_THRHD_S 8
#define UART_RXFIFO_FULL_THRHD 0x0000007F
#define UART_RXFIFO_FULL_THRHD_S 0
#define UART_CONF1(i) (REG_UART_BASE(i) + 0x24)
#define UART_RX_TOUT_EN (BIT(31))
#define UART_RX_TOUT_THRHD 0x0000007F
#define UART_RX_TOUT_THRHD_S 24
#define UART_RX_FLOW_EN (BIT(23))
#define UART_RX_FLOW_THRHD 0x0000007F
#define UART_RX_FLOW_THRHD_S 16
#define UART_TXFIFO_EMPTY_THRHD 0x0000007F
#define UART_TXFIFO_EMPTY_THRHD_S 8
#define UART_RXFIFO_FULL_THRHD 0x0000007F
#define UART_RXFIFO_FULL_THRHD_S 0
#define UART_LOWPULSE( i ) (REG_UART_BASE( i ) + 0x28)
#define UART_LOWPULSE_MIN_CNT 0x000FFFFF
#define UART_LOWPULSE_MIN_CNT_S 0
#define UART_LOWPULSE(i) (REG_UART_BASE(i) + 0x28)
#define UART_LOWPULSE_MIN_CNT 0x000FFFFF
#define UART_LOWPULSE_MIN_CNT_S 0
#define UART_HIGHPULSE( i ) (REG_UART_BASE( i ) + 0x2C)
#define UART_HIGHPULSE_MIN_CNT 0x000FFFFF
#define UART_HIGHPULSE_MIN_CNT_S 0
#define UART_HIGHPULSE(i) (REG_UART_BASE(i) + 0x2C)
#define UART_HIGHPULSE_MIN_CNT 0x000FFFFF
#define UART_HIGHPULSE_MIN_CNT_S 0
#define UART_PULSE_NUM( i ) (REG_UART_BASE( i ) + 0x30)
#define UART_PULSE_NUM(i) (REG_UART_BASE(i) + 0x30)
#define UART_PULSE_NUM_CNT 0x0003FF
#define UART_PULSE_NUM_CNT_S 0
#define UART_PULSE_NUM_CNT_S 0
#define UART_DATE(i) (REG_UART_BASE(i) + 0x78)
#define UART_ID(i) (REG_UART_BASE(i) + 0x7C)
#define UART_DATE( i ) (REG_UART_BASE( i ) + 0x78)
#define UART_ID( i ) (REG_UART_BASE( i ) + 0x7C)
#endif // UART_REGISTER_H_INCLUDED

167
include/ringbuf.h 100644
Wyświetl plik

@ -0,0 +1,167 @@
#ifndef INCLUDED_RINGBUF_H
#define INCLUDED_RINGBUF_H
/*
* ringbuf.h - C ring buffer (FIFO) interface.
*
* Written in 2011 by Drew Hess <dhess-src@bothan.net>.
*
* To the extent possible under law, the author(s) have dedicated all
* copyright and related and neighboring rights to this software to
* the public domain worldwide. This software is distributed without
* any warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication
* along with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
/*
* A byte-addressable ring buffer FIFO implementation.
*
* The ring buffer's head pointer points to the starting location
* where data should be written when copying data *into* the buffer
* (e.g., with ringbuf_read). The ring buffer's tail pointer points to
* the starting location where data should be read when copying data
* *from* the buffer (e.g., with ringbuf_write).
*/
#include <stddef.h>
#include <sys/types.h>
typedef struct ringbuf_t *ringbuf_t;
/*
* Create a new ring buffer with the given capacity (usable
* bytes). Note that the actual internal buffer size may be one or
* more bytes larger than the usable capacity, for bookkeeping.
*
* Returns the new ring buffer object, or 0 if there's not enough
* memory to fulfill the request for the given capacity.
*/
ringbuf_t
ringbuf_new(size_t capacity);
/*
* The size of the internal buffer, in bytes. One or more bytes may be
* unusable in order to distinguish the "buffer full" state from the
* "buffer empty" state.
*
* For the usable capacity of the ring buffer, use the
* ringbuf_capacity function.
*/
size_t
ringbuf_buffer_size(const struct ringbuf_t *rb);
/*
* Deallocate a ring buffer, and, as a side effect, set the pointer to
* 0.
*/
void
ringbuf_free(ringbuf_t *rb);
/*
* Reset a ring buffer to its initial state (empty).
*/
void
ringbuf_reset(ringbuf_t rb);
/*
* The usable capacity of the ring buffer, in bytes. Note that this
* value may be less than the ring buffer's internal buffer size, as
* returned by ringbuf_buffer_size.
*/
size_t
ringbuf_capacity(const struct ringbuf_t *rb);
/*
* The number of free/available bytes in the ring buffer. This value
* is never larger than the ring buffer's usable capacity.
*/
size_t
ringbuf_bytes_free(const struct ringbuf_t *rb);
/*
* The number of bytes currently being used in the ring buffer. This
* value is never larger than the ring buffer's usable capacity.
*/
size_t
ringbuf_bytes_used(const struct ringbuf_t *rb);
int
ringbuf_is_full(const struct ringbuf_t *rb);
int
ringbuf_is_empty(const struct ringbuf_t *rb);
/*
* Const access to the head and tail pointers of the ring buffer.
*/
const void *
ringbuf_tail(const struct ringbuf_t *rb);
const void *
ringbuf_head(const struct ringbuf_t *rb);
/*
* Copy n bytes from a contiguous memory area src into the ring buffer
* dst. Returns the ring buffer's new head pointer.
*
* It is possible to copy more data from src than is available in the
* buffer; i.e., it's possible to overflow the ring buffer using this
* function. When an overflow occurs, the state of the ring buffer is
* guaranteed to be consistent, including the head and tail pointers;
* old data will simply be overwritten in FIFO fashion, as
* needed. However, note that, if calling the function results in an
* overflow, the value of the ring buffer's tail pointer may be
* different than it was before the function was called.
*/
void *
ringbuf_memcpy_into(ringbuf_t dst, const void *src, size_t count);
/*
* Copy n bytes from the ring buffer src, starting from its tail
* pointer, into a contiguous memory area dst. Returns the value of
* src's tail pointer after the copy is finished.
*
* Note that this copy is destructive with respect to the ring buffer:
* the n bytes copied from the ring buffer are no longer available in
* the ring buffer after the copy is complete, and the ring buffer
* will have n more free bytes than it did before the function was
* called.
*
* This function will *not* allow the ring buffer to underflow. If
* count is greater than the number of bytes used in the ring buffer,
* no bytes are copied, and the function will return 0.
*/
void *
ringbuf_memcpy_from(void *dst, ringbuf_t src, size_t count);
/*
* Copy count bytes from ring buffer src, starting from its tail
* pointer, into ring buffer dst. Returns dst's new head pointer after
* the copy is finished.
*
* Note that this copy is destructive with respect to the ring buffer
* src: any bytes copied from src into dst are no longer available in
* src after the copy is complete, and src will have 'count' more free
* bytes than it did before the function was called.
*
* It is possible to copy more data from src than is available in dst;
* i.e., it's possible to overflow dst using this function. When an
* overflow occurs, the state of dst is guaranteed to be consistent,
* including the head and tail pointers; old data will simply be
* overwritten in FIFO fashion, as needed. However, note that, if
* calling the function results in an overflow, the value dst's tail
* pointer may be different than it was before the function was
* called.
*
* It is *not* possible to underflow src; if count is greater than the
* number of bytes used in src, no bytes are copied, and the function
* returns 0.
*/
void *
ringbuf_copy(ringbuf_t dst, ringbuf_t src, size_t count);
#endif /* INCLUDED_RINGBUF_H */

Wyświetl plik

@ -1,31 +1,13 @@
#ifndef _USER_CONFIG_H_
#define _USER_CONFIG_H_
#ifndef __USER_CONFIG_H__
#define __USER_CONFIG_H__
#define CFG_HOLDER 0x00FF55A4 /* Change this value to load default configurations */
#define CFG_LOCATION 0x3C /* Please don't change or if you know what you doing */
#define USE_OPTIMIZE_PRINTF
/*DEFAULT CONFIGURATIONS*/
#define MQTT_HOST "192.168.11.122" //or "mqtt.yourdomain.com"
#define MQTT_PORT 1880
#define MQTT_BUF_SIZE 1024
#define MQTT_KEEPALIVE 120 /*second*/
#define MQTT_CLIENT_ID "DVES_%08X"
#define MQTT_USER "DVES_USER"
#define MQTT_PASS "DVES_PASS"
#define STA_SSID "DVES_HOME"
#define STA_PASS "yourpassword"
#define STA_TYPE AUTH_WPA2_PSK
#define MQTT_RECONNECT_TIMEOUT 5 /*second*/
#define CLIENT_SSL_ENABLE
#define DEFAULT_SECURITY 0
#define QUEUE_BUFFER_SIZE 2048
#ifndef LOCAL_CONFIG_AVAILABLE
#error Please copy user_config.sample.h to user_config.local.h and modify your configurations
#else
#include "user_config.local.h"
#endif
#endif

Wyświetl plik

@ -0,0 +1,36 @@
#ifndef __MQTT_CONFIG_H__
#define __MQTT_CONFIG_H__
#define MQTT_SSL_ENABLE
/*DEFAULT CONFIGURATIONS*/
#define MQTT_HOST "192.168.0.101" //or "mqtt.yourdomain.com"
#define MQTT_PORT 1883
#define MQTT_BUF_SIZE 1024
#define MQTT_KEEPALIVE 120 /*second*/
#define MQTT_CLIENT_ID "CLIENT_1234"
#define MQTT_USER "USER"
#define MQTT_PASS "PASS"
#define MQTT_CLEAN_SESSION 1
#define MQTT_KEEPALIVE 120
#define STA_SSID "SSID"
#define STA_PASS "PASS"
#define MQTT_RECONNECT_TIMEOUT 5 /*second*/
#define DEFAULT_SECURITY 0
#define QUEUE_BUFFER_SIZE 2048
#define PROTOCOL_NAMEv31 /*MQTT version 3.1 compatible with Mosquitto v0.15*/
//PROTOCOL_NAMEv311 /*MQTT version 3.11 compatible with https://eclipse.org/paho/clients/testing/*/
#if defined(DEBUG_ON)
#define INFO( format, ... ) os_printf( format, ## __VA_ARGS__ )
#else
#define INFO( format, ... )
#endif
#endif // __MQTT_CONFIG_H__

211
ntp/ntp.c 100644
Wyświetl plik

@ -0,0 +1,211 @@
#include <c_types.h>
#include <user_interface.h>
#include <espconn.h>
#include <osapi.h>
#include <mem.h>
#include <time.h>
#include <sys_time.h>
#include "ntp.h"
#include "lwip/def.h"
#include "user_config.h"
#include "driver/uart.h"
//#include "utils.h"
#define OFFSET 2208988800ULL
static ip_addr_t ntp_server_ip = { 0 };
static os_timer_t ntp_timeout;
static struct espconn *pCon, pConDNS;
static struct timeval t_tv = { 0, 0 };
static uint64_t t_offset = 0;
static int16_t ntp_timezone = 0;
void ICACHE_FLASH_ATTR get_cur_time(struct timeval *tv) {
uint64_t t_curr = get_long_systime() - t_offset + t_tv.tv_usec;
tv->tv_sec = t_tv.tv_sec + t_curr / 1000000;
tv->tv_usec = t_curr % 1000000;
}
void ICACHE_FLASH_ATTR set_timezone(int16_t timezone) {
ntp_timezone = timezone;
}
uint8_t *ICACHE_FLASH_ATTR get_timestr() {
struct timeval tv;
static uint8_t buf[10];
get_cur_time(&tv);
tv.tv_sec += ntp_timezone * 3600;
os_sprintf(buf, "%02d:%02d:%02d", (tv.tv_sec / 3600) % 24, (tv.tv_sec / 60) % 60, tv.tv_sec % 60);
return buf;
}
static uint8_t *days[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
uint8_t *ICACHE_FLASH_ATTR get_weekday() {
struct timeval tv;
get_cur_time(&tv);
tv.tv_sec += ntp_timezone * 3600;
return days[((tv.tv_sec / (3600 * 24)) + 3) % 7];
}
void ICACHE_FLASH_ATTR ntp_to_tv(uint8_t ntp[8], struct timeval *tv) {
uint64_t aux = 0;
tv->tv_sec = ntohl(*(uint32_t *) ntp) - OFFSET;
aux = ntohl(*(uint32_t *) & ntp[4]);
// aux is the NTP fraction (0..2^32-1)
aux *= 1000000; // multiply by 1e6
aux >>= 32; // and divide by 2^32
tv->tv_usec = (uint32_t) aux;
}
LOCAL void ICACHE_FLASH_ATTR ntp_dns_found(const char *name, ip_addr_t * ipaddr, void *arg) {
struct espconn *pespconn = (struct espconn *)arg;
if (ipaddr != NULL) {
os_printf("Got NTP server: %d.%d.%d.%d\r\n", IP2STR(ipaddr));
// Call the NTP update
ntp_server_ip.addr = ipaddr->addr;
ntp_get_time();
}
}
static void ICACHE_FLASH_ATTR ntp_udp_timeout(void *arg) {
os_timer_disarm(&ntp_timeout);
os_printf("NTP timout\r\n");
// clean up connection
if (pCon) {
espconn_delete(pCon);
os_free(pCon->proto.udp);
os_free(pCon);
pCon = 0;
}
}
static void ICACHE_FLASH_ATTR ntp_udp_recv(void *arg, char *pdata, unsigned short len) {
ntp_t *ntp;
struct timeval tv;
int32_t hh, mm, ss;
if (!ntp_sync_done())
os_printf("NTP synced\r\n");
get_cur_time(&tv);
// get the according sys_time;
t_offset = get_long_systime();
os_timer_disarm(&ntp_timeout);
// extract ntp time
ntp = (ntp_t *) pdata;
ntp_to_tv(ntp->trans_time, &t_tv);
// os_printf("NTP re-sync - diff: %d usecs\r\n", t_tv.tv_usec-tv.tv_usec);
/*
ss = t_tv.tv_sec%60;
mm = (t_tv.tv_sec/60)%60;
hh = (t_tv.tv_sec/3600)%24;
os_printf("time: %2d:%02d:%02d\r\n", hh, mm, ss);
os_printf("Day: %s\r\n", get_weekday());
*/
// clean up connection
if (pCon) {
espconn_delete(pCon);
os_free(pCon->proto.udp);
os_free(pCon);
pCon = 0;
}
}
void ICACHE_FLASH_ATTR ntp_set_server(uint8_t * ntp_server) {
ntp_server_ip.addr = 0;
// invalid arg?
if (ntp_server == NULL)
return;
// ip or DNS name?
if (UTILS_IsIPV4(ntp_server)) {
// read address
UTILS_StrToIP(ntp_server, &ntp_server_ip);
ntp_get_time();
} else {
// call DNS and wait for callback
espconn_gethostbyname(&pConDNS, ntp_server, &ntp_server_ip, ntp_dns_found);
}
}
bool ICACHE_FLASH_ATTR ntp_sync_done() {
return t_offset != 0;
}
void ICACHE_FLASH_ATTR ntp_get_time() {
ntp_t ntp;
// either ongoing request or invalid ip?
if (pCon != 0 || ntp_server_ip.addr == 0)
return;
// set up the udp "connection"
pCon = (struct espconn *)os_zalloc(sizeof(struct espconn));
pCon->type = ESPCONN_UDP;
pCon->state = ESPCONN_NONE;
pCon->proto.udp = (esp_udp *) os_zalloc(sizeof(esp_udp));
pCon->proto.udp->local_port = espconn_port();
pCon->proto.udp->remote_port = 123;
os_memcpy(pCon->proto.udp->remote_ip, &ntp_server_ip, 4);
// create a really simple ntp request packet
os_memset(&ntp, 0, sizeof(ntp_t));
ntp.options = 0b00011011; // leap = 0, version = 3, mode = 3 (client)
// set timeout timer
os_timer_disarm(&ntp_timeout);
os_timer_setfn(&ntp_timeout, (os_timer_func_t *) ntp_udp_timeout, pCon);
os_timer_arm(&ntp_timeout, NTP_TIMEOUT_MS, 0);
// send the ntp request
espconn_create(pCon);
espconn_regist_recvcb(pCon, ntp_udp_recv);
espconn_sent(pCon, (uint8 *) & ntp, sizeof(ntp_t));
}
void ICACHE_FLASH_ATTR set_time_local(uint16_t h, uint16_t m, uint16_t s) {
// get the according sys_time;
t_offset = get_long_systime();
t_tv.tv_sec -= t_tv.tv_sec % (3600 * 24);
t_tv.tv_sec += (h%24)*3600 + (m%60)*60 + s%60;
t_tv.tv_usec = 0;
}
bool ICACHE_FLASH_ATTR set_weekday_local(char *day) {
int i;
for (i = 0; i<7; i++) {
if (os_strcmp(day, days[i]) == 0)
break;
}
if (i>=7)
return false;
t_tv.tv_sec = t_tv.tv_sec % (3600 * 24);
t_tv.tv_sec += (7 + i-3) * (3600 * 24);
return true;
}

32
ntp/ntp.h 100644
Wyświetl plik

@ -0,0 +1,32 @@
#ifndef __NTP_H__
#define __NTP_H__
#include <sys/time.h>
#define NTP_TIMEOUT_MS 5000
typedef struct {
uint8 options;
uint8 stratum;
uint8 poll;
uint8 precision;
uint32 root_delay;
uint32 root_disp;
uint32 ref_id;
uint8 ref_time[8];
uint8 orig_time[8];
uint8 recv_time[8];
uint8 trans_time[8];
} ntp_t;
void ntp_set_server(uint8_t *ntp_server);
bool ntp_sync_done();
void ntp_get_time();
void get_cur_time(struct timeval *tv);
void set_timezone(int16_t timezone);
uint8_t *get_timestr();
uint8_t *get_weekday();
void set_time_local(uint16_t h, uint16_t m, uint16_t s);
bool set_weekday_local(char *day);
#endif

340
pwm/LICENSE 100644
Wyświetl plik

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{description}
Copyright (C) {year} {fullname}
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
{signature of Ty Coon}, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

455
pwm/pwm.c 100644
Wyświetl plik

@ -0,0 +1,455 @@
/*
* Copyright (C) 2016 Stefan Brüns <stefan.bruens@rwth-aachen.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* Set the following three defines to your needs */
#include "user_config.h"
#ifndef SDK_PWM_PERIOD_COMPAT_MODE
#define SDK_PWM_PERIOD_COMPAT_MODE 0
#endif
#ifndef PWM_MAX_CHANNELS
#define PWM_MAX_CHANNELS 8
#endif
#define PWM_DEBUG 0
#define PWM_USE_NMI 1
/* no user servicable parts beyond this point */
#define PWM_MAX_TICKS 0x7fffff
#if SDK_PWM_PERIOD_COMPAT_MODE
#define PWM_PERIOD_TO_TICKS(x) (x * 0.2)
#define PWM_DUTY_TO_TICKS(x) (x * 5)
#define PWM_MAX_DUTY (PWM_MAX_TICKS * 0.2)
#define PWM_MAX_PERIOD (PWM_MAX_TICKS * 5)
#else
#define PWM_PERIOD_TO_TICKS(x) (x)
#define PWM_DUTY_TO_TICKS(x) (x)
#define PWM_MAX_DUTY PWM_MAX_TICKS
#define PWM_MAX_PERIOD PWM_MAX_TICKS
#endif
#include <c_types.h>
#include <pwm.h>
#include <eagle_soc.h>
#include <ets_sys.h>
#include "easygpio.h"
// from SDK hw_timer.c
#define TIMER1_DIVIDE_BY_16 0x0004
#define TIMER1_ENABLE_TIMER 0x0080
struct pwm_phase {
uint32_t ticks; ///< delay until next phase, in 200ns units
uint16_t on_mask; ///< GPIO mask to switch on
uint16_t off_mask; ///< GPIO mask to switch off
};
/* Three sets of PWM phases, the active one, the one used
* starting with the next cycle, and the one updated
* by pwm_start. After the update pwm_next_set
* is set to the last updated set. pwm_current_set is set to
* pwm_next_set from the interrupt routine during the first
* pwm phase
*/
typedef struct pwm_phase (pwm_phase_array)[PWM_MAX_CHANNELS + 2];
static pwm_phase_array pwm_phases[3];
static struct {
struct pwm_phase* next_set;
struct pwm_phase* current_set;
uint8_t current_phase;
} pwm_state;
static uint32_t pwm_period;
static uint32_t pwm_period_ticks;
static uint32_t pwm_duty[PWM_MAX_CHANNELS];
static uint16_t gpio_mask[PWM_MAX_CHANNELS];
static uint8_t pwm_channels;
// 3-tuples of MUX_REGISTER, MUX_VALUE and GPIO number
typedef uint32_t (pin_info_type)[3];
struct gpio_regs {
uint32_t out; /* 0x60000300 */
uint32_t out_w1ts; /* 0x60000304 */
uint32_t out_w1tc; /* 0x60000308 */
uint32_t enable; /* 0x6000030C */
uint32_t enable_w1ts; /* 0x60000310 */
uint32_t enable_w1tc; /* 0x60000314 */
uint32_t in; /* 0x60000318 */
uint32_t status; /* 0x6000031C */
uint32_t status_w1ts; /* 0x60000320 */
uint32_t status_w1tc; /* 0x60000324 */
};
static struct gpio_regs* gpio = (struct gpio_regs*)(0x60000300);
struct timer_regs {
uint32_t frc1_load; /* 0x60000600 */
uint32_t frc1_count; /* 0x60000604 */
uint32_t frc1_ctrl; /* 0x60000608 */
uint32_t frc1_int; /* 0x6000060C */
uint8_t pad[16];
uint32_t frc2_load; /* 0x60000620 */
uint32_t frc2_count; /* 0x60000624 */
uint32_t frc2_ctrl; /* 0x60000628 */
uint32_t frc2_int; /* 0x6000062C */
uint32_t frc2_alarm; /* 0x60000630 */
};
static struct timer_regs* timer = (struct timer_regs*)(0x60000600);
static void
pwm_intr_handler(void)
{
if ((pwm_state.current_set[pwm_state.current_phase].off_mask == 0) &&
(pwm_state.current_set[pwm_state.current_phase].on_mask == 0)) {
pwm_state.current_set = pwm_state.next_set;
pwm_state.current_phase = 0;
}
do {
// force write to GPIO registers on each loop
asm volatile ("" : : : "memory");
gpio->out_w1ts = (uint32_t)(pwm_state.current_set[pwm_state.current_phase].on_mask);
gpio->out_w1tc = (uint32_t)(pwm_state.current_set[pwm_state.current_phase].off_mask);
uint32_t ticks = pwm_state.current_set[pwm_state.current_phase].ticks;
pwm_state.current_phase++;
if (ticks) {
if (ticks >= 16) {
// constant interrupt overhead
ticks -= 9;
timer->frc1_int &= ~FRC1_INT_CLR_MASK;
WRITE_PERI_REG(&timer->frc1_load, ticks);
return;
}
ticks *= 4;
do {
ticks -= 1;
// stop compiler from optimizing delay loop to noop
asm volatile ("" : : : "memory");
} while (ticks > 0);
}
} while (1);
}
/**
* period: initial period (base unit 1us OR 200ns)
* duty: array of initial duty values, may be NULL, may be freed after pwm_init
* pwm_channel_num: number of channels to use
* pin_info_list: array of pin_info
*/
void ICACHE_FLASH_ATTR
pwm_init(uint32_t period, uint32_t *duty, uint32_t pwm_channel_num,
uint32_t (*pin_info_list)[3])
{
int i, j, n;
pwm_channels = pwm_channel_num;
if (pwm_channels > PWM_MAX_CHANNELS)
pwm_channels = PWM_MAX_CHANNELS;
for (i = 0; i < 3; i++) {
for (j = 0; j < (PWM_MAX_CHANNELS + 2); j++) {
pwm_phases[i][j].ticks = 0;
pwm_phases[i][j].on_mask = 0;
pwm_phases[i][j].off_mask = 0;
}
}
pwm_state.current_set = pwm_state.next_set = 0;
pwm_state.current_phase = 0;
uint32_t all = 0;
// PIN info: MUX-Register, Mux-Setting, PIN-Nr
for (n = 0; n < pwm_channels; n++) {
pin_info_type* pin_info = &pin_info_list[n];
// PIN_FUNC_SELECT((*pin_info)[0], (*pin_info)[1]);
easygpio_pinMode((*pin_info)[2], EASYGPIO_NOPULL, EASYGPIO_OUTPUT);
gpio_mask[n] = 1 << (*pin_info)[2];
all |= 1 << (*pin_info)[2];
if (duty)
pwm_set_duty(duty[n], n);
}
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, all);
GPIO_REG_WRITE(GPIO_ENABLE_W1TS_ADDRESS, all);
pwm_set_period(period);
#if PWM_USE_NMI
ETS_FRC_TIMER1_NMI_INTR_ATTACH(pwm_intr_handler);
#else
ETS_FRC_TIMER1_INTR_ATTACH(pwm_intr_handler, NULL);
#endif
TM1_EDGE_INT_ENABLE();
timer->frc1_int &= ~FRC1_INT_CLR_MASK;
timer->frc1_ctrl = 0;
pwm_start();
}
__attribute__ ((noinline))
static uint8_t ICACHE_FLASH_ATTR
_pwm_phases_prep(struct pwm_phase* pwm)
{
uint8_t n, phases;
uint16_t off_mask = 0;
for (n = 0; n < pwm_channels + 2; n++) {
pwm[n].ticks = 0;
pwm[n].on_mask = 0;
pwm[n].off_mask = 0;
}
phases = 1;
for (n = 0; n < pwm_channels; n++) {
uint32_t ticks = PWM_DUTY_TO_TICKS(pwm_duty[n]);
if (ticks == 0) {
pwm[0].off_mask |= gpio_mask[n];
} else if (ticks >= pwm_period_ticks) {
pwm[0].on_mask |= gpio_mask[n];
} else {
if (ticks < (pwm_period_ticks/2)) {
pwm[phases].ticks = ticks;
pwm[0].on_mask |= gpio_mask[n];
pwm[phases].off_mask = gpio_mask[n];
} else {
pwm[phases].ticks = pwm_period_ticks - ticks;
pwm[phases].on_mask = gpio_mask[n];
pwm[0].off_mask |= gpio_mask[n];
}
phases++;
}
}
pwm[phases].ticks = pwm_period_ticks;
// bubble sort, lowest to hightest duty
n = 2;
while (n < phases) {
if (pwm[n].ticks < pwm[n - 1].ticks) {
struct pwm_phase t = pwm[n];
pwm[n] = pwm[n - 1];
pwm[n - 1] = t;
if (n > 2)
n--;
} else {
n++;
}
}
#if PWM_DEBUG
int t = 0;
for (t = 0; t <= phases; t++) {
ets_printf("%d @%d: %04x %04x\n", t, pwm[t].ticks, pwm[t].on_mask, pwm[t].off_mask);
}
#endif
// shift left to align right edge;
uint8_t l = 0, r = 1;
while (r <= phases) {
uint32_t diff = pwm[r].ticks - pwm[l].ticks;
if (diff && (diff <= 16)) {
uint16_t mask = pwm[r].on_mask | pwm[r].off_mask;
pwm[l].off_mask ^= pwm[r].off_mask;
pwm[l].on_mask ^= pwm[r].on_mask;
pwm[0].off_mask ^= pwm[r].on_mask;
pwm[0].on_mask ^= pwm[r].off_mask;
pwm[r].ticks = pwm_period_ticks - diff;
pwm[r].on_mask ^= mask;
pwm[r].off_mask ^= mask;
} else {
l = r;
}
r++;
}
#if PWM_DEBUG
for (t = 0; t <= phases; t++) {
ets_printf("%d @%d: %04x %04x\n", t, pwm[t].ticks, pwm[t].on_mask, pwm[t].off_mask);
}
#endif
// sort again
n = 2;
while (n <= phases) {
if (pwm[n].ticks < pwm[n - 1].ticks) {
struct pwm_phase t = pwm[n];
pwm[n] = pwm[n - 1];
pwm[n - 1] = t;
if (n > 2)
n--;
} else {
n++;
}
}
// merge same duty
l = 0, r = 1;
while (r <= phases) {
if (pwm[r].ticks == pwm[l].ticks) {
pwm[l].off_mask |= pwm[r].off_mask;
pwm[l].on_mask |= pwm[r].on_mask;
pwm[r].on_mask = 0;
pwm[r].off_mask = 0;
} else {
l++;
if (l != r) {
struct pwm_phase t = pwm[l];
pwm[l] = pwm[r];
pwm[r] = t;
}
}
r++;
}
phases = l;
#if PWM_DEBUG
for (t = 0; t <= phases; t++) {
ets_printf("%d @%d: %04x %04x\n", t, pwm[t].ticks, pwm[t].on_mask, pwm[t].off_mask);
}
#endif
// transform absolute end time to phase durations
for (n = 0; n < phases; n++) {
pwm[n].ticks =
pwm[n + 1].ticks - pwm[n].ticks;
// subtract common overhead
pwm[n].ticks--;
}
pwm[phases].ticks = 0;
// do a cyclic shift if last phase is short
if (pwm[phases - 1].ticks < 16) {
for (n = 0; n < phases - 1; n++) {
struct pwm_phase t = pwm[n];
pwm[n] = pwm[n + 1];
pwm[n + 1] = t;
}
}
#if PWM_DEBUG
for (t = 0; t <= phases; t++) {
ets_printf("%d +%d: %04x %04x\n", t, pwm[t].ticks, pwm[t].on_mask, pwm[t].off_mask);
}
ets_printf("\n");
#endif
return phases;
}
void ICACHE_FLASH_ATTR
pwm_start(void)
{
pwm_phase_array* pwm = &pwm_phases[0];
if ((*pwm == pwm_state.next_set) ||
(*pwm == pwm_state.current_set))
pwm++;
if ((*pwm == pwm_state.next_set) ||
(*pwm == pwm_state.current_set))
pwm++;
uint8_t phases = _pwm_phases_prep(*pwm);
// all with 0% / 100% duty - stop timer
if (phases == 1) {
if (pwm_state.next_set) {
#if PWM_DEBUG
ets_printf("PWM stop\n");
#endif
timer->frc1_ctrl = 0;
ETS_FRC1_INTR_DISABLE();
}
pwm_state.next_set = NULL;
GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, (*pwm)[0].on_mask);
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, (*pwm)[0].off_mask);
return;
}
// start if not running
if (!pwm_state.next_set) {
#if PWM_DEBUG
ets_printf("PWM start\n");
#endif
pwm_state.current_set = pwm_state.next_set = *pwm;
pwm_state.current_phase = phases - 1;
ETS_FRC1_INTR_ENABLE();
RTC_REG_WRITE(FRC1_LOAD_ADDRESS, 0);
timer->frc1_ctrl = TIMER1_DIVIDE_BY_16 | TIMER1_ENABLE_TIMER;
return;
}
pwm_state.next_set = *pwm;
}
void ICACHE_FLASH_ATTR
pwm_set_duty(uint32_t duty, uint8_t channel)
{
if (channel > PWM_MAX_CHANNELS)
return;
if (duty > PWM_MAX_DUTY)
duty = PWM_MAX_DUTY;
pwm_duty[channel] = duty;
}
uint32_t ICACHE_FLASH_ATTR
pwm_get_duty(uint8_t channel)
{
if (channel > PWM_MAX_CHANNELS)
return 0;
return pwm_duty[channel];
}
void ICACHE_FLASH_ATTR
pwm_set_period(uint32_t period)
{
pwm_period = period;
if (pwm_period > PWM_MAX_PERIOD)
pwm_period = PWM_MAX_PERIOD;
pwm_period_ticks = PWM_PERIOD_TO_TICKS(period);
}
uint32_t ICACHE_FLASH_ATTR
pwm_get_period(void)
{
return pwm_period;
}
uint32_t ICACHE_FLASH_ATTR
get_pwm_version(void)
{
return 1;
}
void ICACHE_FLASH_ATTR
set_pwm_debug_en(uint8_t print_en)
{
(void) print_en;
}

15
scripts/script.adc 100644
Wyświetl plik

@ -0,0 +1,15 @@
% Config params, overwrite any previous settings from the commandline
% Nothing here
% Now the events, checked whenever something happens
on init
do
settimer 1 1000
on timer 1
do
println "ADC value: " | $adc
settimer 1 1000

Wyświetl plik

@ -0,0 +1,44 @@
%
% Script for a fully transparent MQTT bridge
%
% Parameters for the other broker
config mqtt_host martinshome
%config mqtt_user test
%config mqtt_password secret
config speed 160
% The initialization, this is done once after booting
on init
do
println "Starting the bridge script"
setvar $local_pub = ""
subscribe local "#"
% This is done after each MQTT (re)connect
on mqttconnect
do
subscribe remote "#"
% Now the events, checked whenever something happens
% The generic local topic handler
on topic local "#"
do
println "Got " | $this_topic | " " | $this_data
% Publish this remotly
if not ($local_pub = $this_topic) then
publish remote $this_topic $this_data
else
setvar $local_pub = ""
endif
% The generic remote topic handler
on topic remote "#"
do
% Publish this locally
setvar $local_pub = $this_topic
publish local $this_topic $this_data

Wyświetl plik

@ -0,0 +1,17 @@
% Config params, overwrite any previous settings from the commandline
% Nothing here
% Now the events, checked whenever something happens
on wificonnect
do
println "get http://wtfismyip.com/text"
http_get "http://wtfismyip.com/text"
on http_response
do
println "called url: " | $this_http_host | $this_http_path
println "return code: " | $this_http_code
println $this_http_body

Wyświetl plik

@ -0,0 +1,59 @@
% Sample for a script that communicates with a HomeVision Controller via the serial interface
% Incoming MQTT messages result in serial input to the HV Controller.
% The controller can initiate MQTT publications via sending "pub,topic,item" to the serial output
% Config params, overwrite any previous settings from the commandline
config bitrate 19200
config system_output 0
on init
% Subscribe
do
subscribe local stat/Woonkmr/POWER
subscribe local stat/Buiten/POWER
subscribe local stat/SVTest/POWER
% ... (additional subscribes, one for each of the remaining devices)
% Woonkmr -> flag 32
on topic local stat/Woonkamer/POWER
do
if $this_data = "on" then
serial_out ",>2001" | #0d
else
if $this_data = "off" then
serial_out ",>2000" | #0d
endif
endif
% Buiten -> flag 33
on topic local stat/Buiten/POWER
do
if $this_data = "on" then
serial_out ",>2101" | #0d
else
if $this_data = "off" then
serial_out ",>2100" | #0d
endif
endif
% SVTest -> flag 34
on topic local stat/SVTest/POWER
do
if $this_data = "on" then
serial_out ",>2201" | #0d
else
if $this_data = "off" then
serial_out ",>2200" | #0d
endif
endif
%... (additional similar "on topic"s for each remaining device)
on serial
do
% parse inputs of the form: pub,{topic},{payload}
setvar $topic_str = csvstr($this_serial,1,",")
setvar $data_str = csvstr($this_serial,2,",")
if csvstr($this_serial,0,",") = "pub" then
publish local $topic_str $data_str
endif

Wyświetl plik

@ -0,0 +1,21 @@
% This is a sample script that disables the UART and uses GPIO 1 and GPIO 3
% as normal digital I/O pins (useful e.g. on a ESP01)
% Config params, overwrite any previous settings from the commandline
% disable all output on the UART
config system_output 0
% Now the initialization, this is done once after booting
on init
do
gpio_pinmode 1 input pullup
gpio_pinmode 3 input pullup
% Now the events, checked whenever something happens
on gpio_interrupt 1 pullup
do
println "Interrupt GPIO 1: " | $this_gpio
on gpio_interrupt 3 pullup
do
println "Interrupt GPIO 3: " | $this_gpio

72
scripts/script.pir 100644
Wyświetl plik

@ -0,0 +1,72 @@
%
% Demo script for an ESP-01 module with a PIR (movement) sensor connected to GPIO 2.
% An indicator LED is connected to GPIO 0.
% The sensor connects to the Sonoff switch modul running the esp_uMQTT_broker.
%
% Config params, overwrite any previous settings from the commandline
% No AP, no broker
config ap_on 0
config broker_access 0
config ssid MQTTbroker
config password stupidPassword
% Give us a time
config ntp_server 1.de.pool.ntp.org
% Connect to the broker on the Sonoff
config mqtt_host 192.168.178.32
config mqtt_user Martin
config mqtt_password secret
config speed 160
% Now the initialization, this is done once after booting
on init
do
println "Starting the PIR script"
% Device number ("* 1" to make even "" a number)
setvar $device_number = @1 * 1
% Read delay constanst in secs from flash @2
setvar $delay = @2 * 1
if $delay = 0 then
% Write default
setvar $delay = 10
setvar @2 = $delay
endif
% Status of the PIR
setvar $pir_status=0
gpio_out 0 $pir_status
% Command topic of the switch
setvar $command_topic="/martinshome/switch/1/command"
% Status topic
setvar $status_topic="/martinshome/pir/" | $device_number | "/status"
% Now the events, checked whenever something happens
% The PIR
on gpio_interrupt 2 pullup
do
println "New state GPIO 2: " | $this_gpio
setvar $pir_status = $this_gpio
gpio_out 0 $pir_status
publish remote $status_topic $pir_status retained
if $pir_status = 1 then
publish remote $command_topic "on"
endif
settimer 1 $delay*1000
% Turn off again if nothing happens
on timer 1
do
if $pir_status = 0 then
publish remote $command_topic "off"
endif

41
scripts/script.pwm 100644
Wyświetl plik

@ -0,0 +1,41 @@
%
% Let the build-in LED (GPIO 2) glow up and down
%
% Config params, overwrite any previous settings from the commandline
% Nothing here
% Initialization, this is done once after booting
on init
do
% PWM
setvar $pwm_val = 1000
setvar $pwm_inc = "-10"
gpio_pwm 2 $pwm_val
settimer 1 10
% Now the events, checked whenever something happens
% Timer (every 10ms)
on timer 1
do
setvar $pwm_val = $pwm_val + $pwm_inc
% Under 0 (lower limit)? Reverse increment
if 0 > $pwm_val then
setvar $pwm_inc = 0 - $pwm_inc
setvar $pwm_val = $pwm_inc
endif
% Over 1000 (upper limit)? Reverse increment
if $pwm_val > 1000 then
setvar $pwm_inc = 0 - $pwm_inc
setvar $pwm_val = 1000 + $pwm_inc
endif
gpio_pwm 2 $pwm_val
settimer 1 10

Wyświetl plik

@ -0,0 +1,108 @@
% Config params, overwrite any previous settings from the commandline
config ap_ssid MQTTbroker
config ap_password stupidPassword
config ntp_server 1.de.pool.ntp.org
config broker_user Martin
config broker_password secret
config mqtt_host martinshome.fritz.box
config speed 160
% Now the initialization, this is done once after booting
on init
do
% Device number ("* 1" to make even "" a number)
setvar $device_number = @1 * 1
% @<num> vars are stored in flash and are persistent even after reboot
setvar $run = @2 + 1
setvar @2 = $run
println "This is reboot no "|$run
% Status of the relay
setvar $relay_status=0
gpio_out 12 $relay_status
gpio_out 13 not ($relay_status)
% Blink flag
setvar $blink=0
% Command topic
setvar $command_topic="/martinshome/switch/" | $device_number | "/command"
% Status topic
setvar $status_topic="/martinshome/switch/" | $device_number | "/status"
publish local $status_topic $relay_status retained
% local subscriptions once in 'init'
subscribe local $command_topic
% Now the MQTT client init, this is done each time the client connects
on mqttconnect
do
% remote subscriptions for each connection in 'mqttconnect'
subscribe remote $command_topic
publish remote $status_topic $relay_status retained
% Now the events, checked whenever something happens
% Is there a remote command?
on topic remote $command_topic
do
println "Received remote command: " | $this_data
% republish this locally - this does the action
publish local $command_topic $this_data
% Is there a local command?
on topic local $command_topic
do
println "Received local command: " | $this_data
if $this_data = "on" then
setvar $relay_status = 1
setvar $blink = 0
gpio_out 12 $relay_status
gpio_out 13 not ($relay_status)
else
if $this_data = "off" then
setvar $relay_status = 0
setvar $blink = 0
gpio_out 12 $relay_status
gpio_out 13 not ($relay_status)
endif
endif
if $this_data = "toggle" then
setvar $relay_status = not ($relay_status)
gpio_out 12 $relay_status
gpio_out 13 not ($relay_status)
endif
if $this_data = "blink" then
setvar $blink = 1
settimer 1 500
endif
publish local $status_topic $relay_status retained
publish remote $status_topic $relay_status retained
% The local pushbutton
on gpio_interrupt 0 pullup
do
println "New state GPIO 0: " | $this_gpio
if $this_gpio = 0 then
setvar $blink = 0
publish local $command_topic "toggle"
endif
% Blinking
on timer 1
do
if $blink = 1 then
publish local $command_topic "toggle"
settimer 1 500
endif

Wyświetl plik

@ -0,0 +1,69 @@
% Config params, overwrite any previous settings from the commandline
% Nothing here
% Now the events, checked whenever something happens
% Now the initialization, this is done once after booting
on init
do
% Enter your local coordinates here:
setvar $service_url = "https://api.sunrise-sunset.org/json?lat=50.734579&lng=7.090007&date=today&formatted=0"
% Daily lookup time
setalarm 3 01:00:00
on wificonnect
do
println $service_url
http_get $service_url
% Retry on no response
settimer 1 20000
on http_response
do
println "return code: " | $this_http_code
if not($this_http_code = 200) then
% Retry on failue
settimer 1 20000
else
settimer 1 0
println $this_http_body
setvar $sunrise = substr(json_parse("results.sunrise", $this_http_body), 11, 8)
setvar $sunset = substr(json_parse("results.sunset", $this_http_body), 11, 8)
println "Sunrise: " | $sunrise
println "Sunset: " | $sunset
setalarm 1 $sunset
setalarm 2 $sunrise
endif
% Retry timer
on timer 1
do
println "Retry: " | $service_url
http_get $service_url
% Switch on
on alarm 1
do
publish local /time/sunset $sunset
println "Sunset - switch on at " | $timestamp
gpio_out 2 0
% Switch off
on alarm 2
do
publish local /time/sunrise $sunrise
println "Sunrise - switch off at " | $timestamp
gpio_out 2 1
% Get new values
on alarm 3
do
println $service_url
http_get $service_url

Wyświetl plik

@ -0,0 +1,50 @@
% Timeclock example for using alarms
% Publish time values (format hh:mm:ss) on the "/timeclock/on_time" and "/timeclock/off_time" topics
% to the brocker and the build-in LED will switch at the given times.
% Config params, overwrite any previous settings from the commandline
config ntp_server 1.pool.ntp.org
config ntp_timezone 1
% Now the initialization, this is done once after booting
on init
do
% Command prefix
setvar $command_prefix = "/timeclock"
% Command topic
setvar $command_topic = $command_prefix | "/#"
% local subscriptions once in 'init'
subscribe local $command_topic
% Now the events, checked whenever something happens
% Is there a remote command?
on topic local $command_topic
do
if ($this_topic = $command_prefix | "/on-time") then
println "Received on command: " | $this_data
setalarm 1 $this_data
endif
if ($this_topic = $command_prefix | "/off-time") then
println "Received off command: " | $this_data
setalarm 2 $this_data
endif
if ($this_topic = $command_prefix | "/switch") then
println "Received switch command: " | $this_data
gpio_out 2 not($this_data)
endif
% Switch on
on alarm 1
do
println "Switch on at " | $timestamp
gpio_out 2 0
% Switch off
on alarm 2
do
println "Switch off at " | $timestamp
gpio_out 2 1

1
uMQTTBroker 160000

@ -0,0 +1 @@
Subproject commit 2c51baaf43a0ec7bf7a813b06aee24963b5b828f

Wyświetl plik

@ -39,8 +39,6 @@ endif
INCLUDES := $(INCLUDES) -I $(PDIR)include
INCLUDES += -I ./
INCLUDES += -I ../../rom/include
INCLUDES += -I ../../include/ets
PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile

1108
user/cli.c 100644

Plik diff jest za duży Load Diff

Wyświetl plik

@ -1,107 +0,0 @@
/*
/* config.c
*
* Copyright (c) 2014-2015, Tuan PM <tuanpm at live dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "ets_sys.h"
#include "os_type.h"
#include "mem.h"
#include "osapi.h"
#include "user_interface.h"
#include "mqtt.h"
#include "config.h"
#include "user_config.h"
#include "debug.h"
SYSCFG sysCfg;
SAVE_FLAG saveFlag;
void CFG_Save()
{
spi_flash_read((CFG_LOCATION + 3) * SPI_FLASH_SEC_SIZE,
(uint32 *)&saveFlag, sizeof(SAVE_FLAG));
if (saveFlag.flag == 0) {
spi_flash_erase_sector(CFG_LOCATION + 1);
spi_flash_write((CFG_LOCATION + 1) * SPI_FLASH_SEC_SIZE,
(uint32 *)&sysCfg, sizeof(SYSCFG));
saveFlag.flag = 1;
spi_flash_erase_sector(CFG_LOCATION + 3);
spi_flash_write((CFG_LOCATION + 3) * SPI_FLASH_SEC_SIZE,
(uint32 *)&saveFlag, sizeof(SAVE_FLAG));
} else {
spi_flash_erase_sector(CFG_LOCATION + 0);
spi_flash_write((CFG_LOCATION + 0) * SPI_FLASH_SEC_SIZE,
(uint32 *)&sysCfg, sizeof(SYSCFG));
saveFlag.flag = 0;
spi_flash_erase_sector(CFG_LOCATION + 3);
spi_flash_write((CFG_LOCATION + 3) * SPI_FLASH_SEC_SIZE,
(uint32 *)&saveFlag, sizeof(SAVE_FLAG));
}
}
void CFG_Load()
{
INFO("\r\nload ...\r\n");
spi_flash_read((CFG_LOCATION + 3) * SPI_FLASH_SEC_SIZE,
(uint32 *)&saveFlag, sizeof(SAVE_FLAG));
if (saveFlag.flag == 0) {
spi_flash_read((CFG_LOCATION + 0) * SPI_FLASH_SEC_SIZE,
(uint32 *)&sysCfg, sizeof(SYSCFG));
} else {
spi_flash_read((CFG_LOCATION + 1) * SPI_FLASH_SEC_SIZE,
(uint32 *)&sysCfg, sizeof(SYSCFG));
}
if(sysCfg.cfg_holder != CFG_HOLDER){
os_memset(&sysCfg, 0x00, sizeof sysCfg);
sysCfg.cfg_holder = CFG_HOLDER;
os_sprintf(sysCfg.sta_ssid, "%s", STA_SSID);
os_sprintf(sysCfg.sta_pwd, "%s", STA_PASS);
sysCfg.sta_type = STA_TYPE;
os_sprintf(sysCfg.device_id, MQTT_CLIENT_ID, system_get_chip_id());
os_sprintf(sysCfg.mqtt_host, "%s", MQTT_HOST);
sysCfg.mqtt_port = MQTT_PORT;
os_sprintf(sysCfg.mqtt_user, "%s", MQTT_USER);
os_sprintf(sysCfg.mqtt_pass, "%s", MQTT_PASS);
sysCfg.security = DEFAULT_SECURITY; /* default non ssl */
sysCfg.mqtt_keepalive = MQTT_KEEPALIVE;
INFO(" default configurations\r\n");
CFG_Save();
}
}

Wyświetl plik

@ -1,61 +0,0 @@
/* config.h
*
* Copyright (c) 2014-2015, Tuan PM <tuanpm at live dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef USER_CONFIG_H_
#define USER_CONFIG_H_
#include "os_type.h"
#include "user_config.h"
typedef struct{
uint32_t cfg_holder;
uint8_t device_id[16];
uint8_t sta_ssid[64];
uint8_t sta_pwd[64];
uint32_t sta_type;
uint8_t mqtt_host[64];
uint32_t mqtt_port;
uint8_t mqtt_user[32];
uint8_t mqtt_pass[32];
uint32_t mqtt_keepalive;
uint8_t security;
} SYSCFG;
typedef struct {
uint8 flag;
uint8 pad[3];
} SAVE_FLAG;
void CFG_Save();
void CFG_Load();
extern SYSCFG sysCfg;
#endif /* USER_CONFIG_H_ */

188
user/config_flash.c 100644
Wyświetl plik

@ -0,0 +1,188 @@
#include "user_interface.h"
#include "config_flash.h"
/* From the document 99A-SDK-Espressif IOT Flash RW Operation_v0.2 *
* -------------------------------------------------------------------------*
* Flash is erased sector by sector, which means it has to erase 4Kbytes one
* time at least. When you want to change some data in flash, you have to
* erase the whole sector, and then write it back with the new data.
*--------------------------------------------------------------------------*/
void ICACHE_FLASH_ATTR config_load_default(sysconfig_p config) {
uint8_t mac[6];
os_memset(config, 0, sizeof(sysconfig_t));
os_printf("Loading default configuration\r\n");
config->magic_number = MAGIC_NUMBER;
config->length = sizeof(sysconfig_t);
os_sprintf(config->ssid, "%s", WIFI_SSID);
os_sprintf(config->password, "%s", WIFI_PASSWORD);
config->auto_connect = 0;
os_sprintf(config->ap_ssid, "%s", WIFI_AP_SSID);
os_sprintf(config->ap_password, "%s", WIFI_AP_PASSWORD);
config->ap_channel = WIFI_AP_CHANNEL;
config->ap_open = 1;
config->ap_on = 1;
config->locked = 0;
config->lock_password[0] = '\0';
IP4_ADDR(&config->network_addr, 192, 168, 4, 1);
config->dns_addr.addr = 0; // use DHCP
config->my_addr.addr = 0; // use DHCP
config->my_netmask.addr = 0; // use DHCP
config->my_gw.addr = 0; // use DHCP
config->system_output = SYSTEM_OUTPUT_INFO;
config->bit_rate = 115200;
config->mdns_mode = 0; // no mDNS
config->clock_speed = 80;
config->config_port = CONSOLE_SERVER_PORT;
config->config_access = LOCAL_ACCESS | REMOTE_ACCESS;
config->mqtt_broker_port = MQTT_PORT;
config->max_subscriptions = 30;
config->max_retained_messages = 30;
config->max_clients = 0;
config->auto_retained = 0;
os_sprintf(config->mqtt_broker_user, "%s", "none");
config->mqtt_broker_password[0] = 0;
config->mqtt_broker_access = LOCAL_ACCESS | REMOTE_ACCESS;
#ifdef MQTT_CLIENT
os_sprintf(config->mqtt_host, "%s", "none");
config->mqtt_port = 1883;
config->mqtt_ssl = false;
os_sprintf(config->mqtt_user, "%s", "none");
config->mqtt_password[0] = 0;
wifi_get_macaddr(0, mac);
os_sprintf(config->mqtt_id, "%s_%02x%02x%02x", MQTT_ID, mac[3], mac[4], mac[5]);
#endif
#ifdef NTP
os_sprintf(config->ntp_server, "%s", "1.pool.ntp.org");
config->ntp_interval = 300000000;
config->ntp_timezone = 0;
#endif
#ifdef DNS_RESP
os_sprintf(config->broker_dns_name, "%s", "none");
#endif
#ifdef GPIO
#ifdef GPIO_PWM
config->pwm_period = 5000;
#endif
#endif
}
int ICACHE_FLASH_ATTR config_load(sysconfig_p config) {
if (config == NULL)
return -1;
uint16_t base_address = FLASH_BLOCK_NO;
spi_flash_read(base_address * SPI_FLASH_SEC_SIZE, &config->magic_number, 4);
if ((config->magic_number != MAGIC_NUMBER)) {
os_printf("\r\nNo config found, saving default in flash\r\n");
config_load_default(config);
config_save(config);
return -1;
}
os_printf("\r\nConfig found and loaded\r\n");
spi_flash_read(base_address * SPI_FLASH_SEC_SIZE, (uint32 *) config, sizeof(sysconfig_t));
if (config->length != sizeof(sysconfig_t)) {
os_printf("Length Mismatch, probably old version of config, loading defaults\r\n");
config_load_default(config);
config_save(config);
return -1;
}
return 0;
}
void ICACHE_FLASH_ATTR config_save(sysconfig_p config) {
uint16_t base_address = FLASH_BLOCK_NO;
os_printf("Saving configuration\r\n");
spi_flash_erase_sector(base_address);
spi_flash_write(base_address * SPI_FLASH_SEC_SIZE, (uint32 *) config, sizeof(sysconfig_t));
}
void ICACHE_FLASH_ATTR blob_save(uint8_t blob_no, uint32_t * data, uint16_t len) {
uint16_t base_address = FLASH_BLOCK_NO + 1 + blob_no;
spi_flash_erase_sector(base_address);
spi_flash_write(base_address * SPI_FLASH_SEC_SIZE, data, len);
}
void ICACHE_FLASH_ATTR blob_load(uint8_t blob_no, uint32_t * data, uint16_t len) {
uint16_t base_address = FLASH_BLOCK_NO + 1 + blob_no;
spi_flash_read(base_address * SPI_FLASH_SEC_SIZE, data, len);
}
void ICACHE_FLASH_ATTR blob_zero(uint8_t blob_no, uint16_t len) {
int i;
uint8_t z[len];
os_memset(z, 0, len);
uint16_t base_address = FLASH_BLOCK_NO + 1 + blob_no;
spi_flash_erase_sector(base_address);
spi_flash_write(base_address * SPI_FLASH_SEC_SIZE, (uint32_t *) z, len);
}
const uint8_t esp_init_data_default[] = {
"\x05\x08\x04\x02\x05\x05\x05\x02\x05\x00\x04\x05\x05\x04\x05\x05"
"\x04\xFE\xFD\xFF\xF0\xF0\xF0\xE0\xE0\xE0\xE1\x0A\xFF\xFF\xF8\x00"
"\xF8\xF8\x4E\x4A\x46\x40\x3C\x38\x00\x00\x01\x01\x02\x03\x04\x05"
"\x01\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\xE1\x0A\x00\x00\x00\x00\x00\x00\x00\x00\x01\x93\x43\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"};
void user_rf_pre_init() {
uint8_t esp_init_data_current[sizeof(esp_init_data_default)];
enum flash_size_map size_map = system_get_flash_size_map();
uint32 rf_cal_sec = 0, addr, i;
//os_printf("\nUser preinit: ");
switch (size_map) {
case FLASH_SIZE_4M_MAP_256_256:
rf_cal_sec = 128 - 5;
break;
case FLASH_SIZE_8M_MAP_512_512:
rf_cal_sec = 256 - 5;
break;
case FLASH_SIZE_16M_MAP_512_512:
case FLASH_SIZE_16M_MAP_1024_1024:
rf_cal_sec = 512 - 5;
break;
case FLASH_SIZE_32M_MAP_512_512:
case FLASH_SIZE_32M_MAP_1024_1024:
rf_cal_sec = 1024 - 5;
break;
default:
rf_cal_sec = 0;
break;
}
addr = ((rf_cal_sec) * SPI_FLASH_SEC_SIZE)+SPI_FLASH_SEC_SIZE;
spi_flash_read(addr, (uint32_t *)esp_init_data_current, sizeof(esp_init_data_current));
for (i=0; i<sizeof(esp_init_data_default); i++) {
if (esp_init_data_current[i] != esp_init_data_default[i]) {
spi_flash_erase_sector(rf_cal_sec);
spi_flash_erase_sector(rf_cal_sec+1);
spi_flash_erase_sector(rf_cal_sec+2);
addr = ((rf_cal_sec) * SPI_FLASH_SEC_SIZE)+SPI_FLASH_SEC_SIZE;
os_printf("Storing rfcal init data @ address=0x%08X\n", addr);
spi_flash_write(addr, (uint32 *)esp_init_data_default, sizeof(esp_init_data_default));
break;
}
/* else {
os_printf("RF data[%u] is ok\n", i);
}*/
}
}

105
user/config_flash.h 100644
Wyświetl plik

@ -0,0 +1,105 @@
#ifndef _CONFIG_FLASH_H_
#define _CONFIG_FLASH_H_
#include "c_types.h"
#include "mem.h"
#include "ets_sys.h"
#include "osapi.h"
#include "gpio.h"
#include "os_type.h"
#include "spi_flash.h"
#include "user_config.h"
#define FLASH_BLOCK_NO 0xc
#define MAGIC_NUMBER 0x015034fd
#define SYSTEM_OUTPUT_INFO 2
#define SYSTEM_OUTPUT_CMD 1
#define SYSTEM_OUTPUT_NONE 0
#define MQTT_PORT 1883
typedef struct
{
// To check if the structure is initialized or not in flash
uint32_t magic_number;
// Length of the structure, since this is a evolving library, the variant may change
// hence used for verification
uint16_t length;
/* Below variables are specific to my code */
uint8_t ssid[32]; // SSID of the AP to connect to
uint8_t password[64]; // Password of the network
uint8_t auto_connect; // Should we auto connect
uint8_t ap_ssid[32]; // SSID of the own AP
uint8_t ap_password[64]; // Password of the own network
uint8_t ap_channel; // Channel of the AP
uint8_t ap_open; // Should we use no WPA?
uint8_t ap_on; // AP enabled?
uint8_t locked; // Should we allow for config changes
uint8_t lock_password[32]; // Password of config lock
ip_addr_t network_addr; // Address of the internal network
ip_addr_t dns_addr; // Optional: address of the dns server
ip_addr_t my_addr; // Optional (if not DHCP): IP address of the uplink side
ip_addr_t my_netmask; // Optional (if not DHCP): IP netmask of the uplink side
ip_addr_t my_gw; // Optional (if not DHCP): Gateway of the uplink side
uint8_t mdns_mode; // Selects, which interface should be announced via mDNS (default: none)
uint16_t clock_speed; // Freq of the CPU
uint16_t config_port; // Port on which the concole listenes (0 if no access)
uint8_t config_access; // Controls the interfaces that allow config access (default LOCAL_ACCESS | REMOTE_ACCESS)
uint8_t system_output; // Disable system info and warnings
uint32_t bit_rate; // Bit rate of serial link
uint16_t mqtt_broker_port; // Port where the MQTT broker listens (1883 default)
uint16_t max_subscriptions; // Upper limit on subscribed topics
uint16_t max_retained_messages; // Upper limit on stored retained messages
uint16_t max_clients; // Upper limit on concurrently connected clients (0: mem is the limit)
uint8_t auto_retained; // Automatically save retained messages to flash (default: off)
uint8_t mqtt_broker_user[32]; // Username for client login, "none" if empty
uint8_t mqtt_broker_password[32]; // Password for client login
uint8_t mqtt_broker_access; // Controls the interfaces that allow MQTT access (default LOCAL_ACCESS | REMOTE_ACCESS)
#ifdef MQTT_CLIENT
uint8_t mqtt_host[32]; // IP or hostname of the MQTT broker, "none" if empty
uint16_t mqtt_port; // Port of the MQTT broker
uint8_t mqtt_ssl; // Use SSL (default: no)
uint8_t mqtt_user[32]; // Username for broker login, "none" if empty
uint8_t mqtt_password[32]; // Password for broker login
uint8_t mqtt_id[48]; // MQTT clientId
#endif
#ifdef NTP
uint8_t ntp_server[32]; // IP or hostname of the MQTT broker, "none" if empty
uint32_t ntp_interval; // Sync interval in usec
int16_t ntp_timezone; // Timezone (hour offset to GMT)
#endif
#ifdef DNS_RESP
uint8_t broker_dns_name[32]; // DNS name of the MQTT broker in the SoftAP network, "none" if empty
#endif
#ifdef GPIO
#ifdef GPIO_PWM
uint32_t pwm_period; // PWM period
#endif
#endif
} sysconfig_t, *sysconfig_p;
// The global config
extern sysconfig_t config;
int config_load(sysconfig_p config);
void config_save(sysconfig_p config);
void blob_save(uint8_t blob_no, uint32_t *data, uint16_t len);
void blob_load(uint8_t blob_no, uint32_t *data, uint16_t len);
void blob_zero(uint8_t blob_no, uint16_t len);
#endif

Wyświetl plik

@ -1,15 +0,0 @@
/*
* debug.h
*
* Created on: Dec 4, 2014
* Author: Minh
*/
#ifndef USER_DEBUG_H_
#define USER_DEBUG_H_
#define INFO os_printf
#endif /* USER_DEBUG_H_ */

Wyświetl plik

@ -0,0 +1,807 @@
#include "c_types.h"
#include "mem.h"
#include "ets_sys.h"
#include "osapi.h"
#include "gpio.h"
#include "os_type.h"
#include "lwip/def.h"
#include "user_interface.h"
#include "espconn.h"
#include "dns_responder.h"
//#define DNS_RESP_DEBUG 1
/*
* This software is licensed under the CC0.
*
* This is a _basic_ DNS Server for educational use.
* It does not prevent invalid packets from crashing
* the server.
*
* Originating from:
* https://github.com/mwarning/SimpleDNS
*
*/
LOCAL struct espconn dns_espconn;
struct Message msg;
LOCAL uint8_t dns_mode;
/*
* Masks and constants.
*/
static const uint32_t QR_MASK = 0x8000;
static const uint32_t OPCODE_MASK = 0x7800;
static const uint32_t AA_MASK = 0x0400;
static const uint32_t TC_MASK = 0x0200;
static const uint32_t RD_MASK = 0x0100;
static const uint32_t RA_MASK = 0x8000;
static const uint32_t RCODE_MASK = 0x000F;
/* Response Type */
enum {
Ok_ResponseType = 0,
FormatError_ResponseType = 1,
ServerFailure_ResponseType = 2,
NameError_ResponseType = 3,
NotImplemented_ResponseType = 4,
Refused_ResponseType = 5
};
/* Resource Record Types */
enum {
A_Resource_RecordType = 1,
NS_Resource_RecordType = 2,
CNAME_Resource_RecordType = 5,
SOA_Resource_RecordType = 6,
PTR_Resource_RecordType = 12,
MX_Resource_RecordType = 15,
TXT_Resource_RecordType = 16,
AAAA_Resource_RecordType = 28,
SRV_Resource_RecordType = 33
};
/* Operation Code */
enum {
QUERY_OperationCode = 0, /* standard query */
IQUERY_OperationCode = 1, /* inverse query */
STATUS_OperationCode = 2, /* server status request */
NOTIFY_OperationCode = 4, /* request zone transfer */
UPDATE_OperationCode = 5 /* change resource records */
};
/* Response Code */
enum {
NoError_ResponseCode = 0,
FormatError_ResponseCode = 1,
ServerFailure_ResponseCode = 2,
NameError_ResponseCode = 3
};
/* Query Type */
enum {
IXFR_QueryType = 251,
AXFR_QueryType = 252,
MAILB_QueryType = 253,
MAILA_QueryType = 254,
STAR_QueryType = 255
};
/*
* Types.
*/
/* Question Section */
struct Question {
char *qName;
uint16_t qType;
uint16_t qClass;
struct Question* next; // for linked list
};
/* Data part of a Resource Record */
union ResourceData {
struct {
char *txt_data;
} txt_record;
struct {
uint8_t addr[4];
} a_record;
struct {
char* MName;
char* RName;
uint32_t serial;
uint32_t refresh;
uint32_t retry;
uint32_t expire;
uint32_t minimum;
} soa_record;
struct {
char *name;
} name_server_record;
struct {
char name;
} cname_record;
struct {
char *name;
} ptr_record;
struct {
uint16_t preference;
char *exchange;
} mx_record;
struct {
uint8_t addr[16];
} aaaa_record;
struct {
uint16_t priority;
uint16_t weight;
uint16_t port;
char *target;
} srv_record;
};
/* Resource Record Section */
struct ResourceRecord {
char *name;
uint16_t type;
uint16_t class;
uint16_t ttl;
uint16_t rd_length;
union ResourceData rd_data;
struct ResourceRecord* next; // for linked list
};
struct Message {
uint16_t id; /* Identifier */
/* Flags */
uint16_t qr; /* Query/Response Flag */
uint16_t opcode; /* Operation Code */
uint16_t aa; /* Authoritative Answer Flag */
uint16_t tc; /* Truncation Flag */
uint16_t rd; /* Recursion Desired */
uint16_t ra; /* Recursion Available */
uint16_t rcode; /* Response Code */
uint16_t qdCount; /* Question Count */
uint16_t anCount; /* Answer Record Count */
uint16_t nsCount; /* Authority Record Count */
uint16_t arCount; /* Additional Record Count */
/* At least one question; questions are copied to the response 1:1 */
struct Question* questions;
/*
* Resource records to be send back.
* Every resource record can be in any of the following places.
* But every place has a different semantic.
*/
struct ResourceRecord* answers;
struct ResourceRecord* authorities;
struct ResourceRecord* additionals;
};
/*
int ICACHE_FLASH_ATTR get_A_Record(uint8_t addr[4], const char domain_name[])
{
if (strcmp("foo.bar.com", domain_name) == 0)
{
addr[0] = 192;
addr[1] = 168;
addr[2] = 1;
addr[3] = 1;
return 0;
}
else
{
return -1;
}
}
int ICACHE_FLASH_ATTR get_AAAA_Record(uint8_t addr[16], const char domain_name[])
{
if (strcmp("foo.bar.com", domain_name) == 0)
{
addr[0] = 0xfe;
addr[1] = 0x80;
addr[2] = 0x00;
addr[3] = 0x00;
addr[4] = 0x00;
addr[5] = 0x00;
addr[6] = 0x00;
addr[7] = 0x00;
addr[8] = 0x00;
addr[9] = 0x00;
addr[10] = 0x00;
addr[11] = 0x00;
addr[12] = 0x00;
addr[13] = 0x00;
addr[14] = 0x00;
addr[15] = 0x01;
return 0;
}
else
{
return -1;
}
}
*/
/*
* Debugging functions.
*/
#ifdef DNS_RESP_DEBUG
void ICACHE_FLASH_ATTR print_hex(uint8_t* buf, size_t len)
{
int i;
os_printf("%zu bytes:\n", len);
for(i = 0; i < len; ++i)
os_printf("%02x ", buf[i]);
os_printf("\n");
}
void print_resource_record(struct ResourceRecord* rr)
{
int i;
while (rr)
{
os_printf(" ResourceRecord { name '%s', type %u, class %u, ttl %u, rd_length %u, ",
rr->name,
rr->type,
rr->class,
rr->ttl,
rr->rd_length
);
union ResourceData *rd = &rr->rd_data;
switch (rr->type)
{
case A_Resource_RecordType:
os_printf("Address Resource Record { address ");
for(i = 0; i < 4; ++i)
os_printf("%s%u", (i ? "." : ""), rd->a_record.addr[i]);
os_printf(" }");
break;
case NS_Resource_RecordType:
os_printf("Name Server Resource Record { name %s }",
rd->name_server_record.name
);
break;
case CNAME_Resource_RecordType:
os_printf("Canonical Name Resource Record { name %u }",
rd->cname_record.name
);
break;
case SOA_Resource_RecordType:
os_printf("SOA { MName '%s', RName '%s', serial %u, refresh %u, retry %u, expire %u, minimum %u }",
rd->soa_record.MName,
rd->soa_record.RName,
rd->soa_record.serial,
rd->soa_record.refresh,
rd->soa_record.retry,
rd->soa_record.expire,
rd->soa_record.minimum
);
break;
case PTR_Resource_RecordType:
os_printf("Pointer Resource Record { name '%s' }",
rd->ptr_record.name
);
break;
case MX_Resource_RecordType:
os_printf("Mail Exchange Record { preference %u, exchange '%s' }",
rd->mx_record.preference,
rd->mx_record.exchange
);
break;
case TXT_Resource_RecordType:
os_printf("Text Resource Record { txt_data '%s' }",
rd->txt_record.txt_data
);
break;
case AAAA_Resource_RecordType:
os_printf("AAAA Resource Record { address ");
for(i = 0; i < 16; ++i)
os_printf("%s%02x", (i ? ":" : ""), rd->aaaa_record.addr[i]);
os_printf(" }");
break;
default:
os_printf("Unknown Resource Record { ??? }");
}
os_printf("}\n");
rr = rr->next;
}
}
void ICACHE_FLASH_ATTR print_query(struct Message* msg)
{
os_printf("QUERY { ID: %02x", msg->id);
os_printf(". FIELDS: [ QR: %u, OpCode: %u ]", msg->qr, msg->opcode);
os_printf(", QDcount: %u", msg->qdCount);
os_printf(", ANcount: %u", msg->anCount);
os_printf(", NScount: %u", msg->nsCount);
os_printf(", ARcount: %u,\n", msg->arCount);
struct Question* q = msg->questions;
while (q)
{
os_printf(" Question { qName '%s', qType %u, qClass %u }\n",
q->qName,
q->qType,
q->qClass
);
q = q->next;
}
print_resource_record(msg->answers);
print_resource_record(msg->authorities);
print_resource_record(msg->additionals);
os_printf("}\n");
}
#endif
/*
* Basic memory operations.
*/
size_t ICACHE_FLASH_ATTR get16bits(const uint8_t** buffer)
{
uint16_t value;
os_memcpy(&value, *buffer, 2);
*buffer += 2;
return ntohs(value);
}
void ICACHE_FLASH_ATTR put8bits(uint8_t** buffer, uint8_t value)
{
os_memcpy(*buffer, &value, 1);
*buffer += 1;
}
void ICACHE_FLASH_ATTR put16bits(uint8_t** buffer, uint16_t value)
{
value = htons(value);
os_memcpy(*buffer, &value, 2);
*buffer += 2;
}
void ICACHE_FLASH_ATTR put32bits(uint8_t** buffer, uint32_t value)
{
value = htons(value);
os_memcpy(*buffer, &value, 4);
*buffer += 4;
}
/*
* Deconding/Encoding functions.
*/
// 3foo3bar3com0 => foo.bar.com
char* ICACHE_FLASH_ATTR decode_domain_name(const uint8_t** buffer)
{
char name[256];
const uint8_t* buf = *buffer;
int j = 0;
int i = 0;
while (buf[i] != 0)
{
//if (i >= buflen || i > sizeof(name))
// return NULL;
if (i != 0)
{
name[j] = '.';
j += 1;
}
int len = buf[i];
i += 1;
os_memcpy(name+j, buf+i, len);
i += len;
j += len;
}
name[j] = '\0';
*buffer += i + 1; //also jump over the last 0
//return strdup(name);
uint8_t *ret = os_malloc(os_strlen(name)+1);
os_strcpy(ret, name);
return ret;
}
char ICACHE_FLASH_ATTR *_strchr(const char *s, int c) {
while (*s != (char)c)
if (!*s++)
return 0;
return (char *)s;
}
// foo.bar.com => 3foo3bar3com0
void ICACHE_FLASH_ATTR encode_domain_name(uint8_t** buffer, const char* domain)
{
uint8_t* buf = *buffer;
const char* beg = domain;
const char* pos;
int len = 0;
int i = 0;
while ((pos = _strchr(beg, '.')))
{
len = pos - beg;
buf[i] = len;
i += 1;
os_memcpy(buf+i, beg, len);
i += len;
beg = pos + 1;
}
len = os_strlen(domain) - (beg - domain);
buf[i] = len;
i += 1;
os_memcpy(buf + i, beg, len);
i += len;
buf[i] = 0;
i += 1;
*buffer += i;
}
void ICACHE_FLASH_ATTR decode_header(struct Message* msg, const uint8_t** buffer)
{
msg->id = get16bits(buffer);
uint32_t fields = get16bits(buffer);
msg->qr = (fields & QR_MASK) >> 15;
msg->opcode = (fields & OPCODE_MASK) >> 11;
msg->aa = (fields & AA_MASK) >> 10;
msg->tc = (fields & TC_MASK) >> 9;
msg->rd = (fields & RD_MASK) >> 8;
msg->ra = (fields & RA_MASK) >> 7;
msg->rcode = (fields & RCODE_MASK) >> 0;
msg->qdCount = get16bits(buffer);
msg->anCount = get16bits(buffer);
msg->nsCount = get16bits(buffer);
msg->arCount = get16bits(buffer);
}
void ICACHE_FLASH_ATTR encode_header(struct Message* msg, uint8_t** buffer)
{
put16bits(buffer, msg->id);
int fields = 0;
fields |= (msg->qr << 15) & QR_MASK;
fields |= (msg->rcode << 0) & RCODE_MASK;
// TODO: insert the rest of the fields
put16bits(buffer, fields);
put16bits(buffer, msg->qdCount);
put16bits(buffer, msg->anCount);
put16bits(buffer, msg->nsCount);
put16bits(buffer, msg->arCount);
}
int ICACHE_FLASH_ATTR decode_msg(struct Message* msg, const uint8_t* buffer, int size)
{
int i;
decode_header(msg, &buffer);
if (msg->anCount != 0 || msg->nsCount != 0)
{
os_printf("Only questions expected!\n");
return -1;
}
// parse questions
uint32_t qcount = msg->qdCount;
struct Question* qs = msg->questions;
for (i = 0; i < qcount; ++i)
{
struct Question* q = os_malloc(sizeof(struct Question));
q->qName = decode_domain_name(&buffer);
q->qType = get16bits(&buffer);
q->qClass = get16bits(&buffer);
// prepend question to questions list
q->next = qs;
msg->questions = q;
}
// We do not expect any resource records to parse here.
return 0;
}
// For every question in the message add a appropiate resource record
// in either section 'answers', 'authorities' or 'additionals'.
void ICACHE_FLASH_ATTR resolver_process(struct Message* msg)
{
struct ResourceRecord* beg;
struct ResourceRecord* rr;
struct Question* q;
int rc;
// leave most values intact for response
msg->qr = 1; // this is a response
msg->aa = 1; // this server is authoritative
msg->ra = 0; // no recursion available
msg->rcode = Ok_ResponseType;
// should already be 0
msg->anCount = 0;
msg->nsCount = 0;
msg->arCount = 0;
// for every question append resource records
q = msg->questions;
while (q)
{
rr = os_malloc(sizeof(struct ResourceRecord));
os_memset(rr, 0, sizeof(struct ResourceRecord));
//rr->name = strdup(q->qName);
rr->name = os_malloc(os_strlen(q->qName)+1);
os_strcpy(rr->name, q->qName);
rr->type = q->qType;
rr->class = q->qClass;
rr->ttl = 60*60; // in seconds; 0 means no caching
#ifdef DNS_RESP_DEBUG
os_printf("Query for '%s'\n", q->qName);
#endif
// We only can only answer two question types so far
// and the answer (resource records) will be all put
// into the answers list.
// This behavior is probably non-standard!
switch (q->qType)
{
case A_Resource_RecordType:
rr->rd_length = 4;
rc = get_A_Record(rr->rd_data.a_record.addr, q->qName);
if (rc < 0)
{
os_free(rr->name);
os_free(rr);
goto next;
}
break;
/*
case AAAA_Resource_RecordType:
rr->rd_length = 16;
rc = get_AAAA_Record(rr->rd_data.aaaa_record.addr, q->qName);
if (rc < 0)
{
os_free(rr->name);
os_free(rr);
goto next;
}
break;
*/
/*
case NS_Resource_RecordType:
case CNAME_Resource_RecordType:
case SOA_Resource_RecordType:
case PTR_Resource_RecordType:
case MX_Resource_RecordType:
case TXT_Resource_RecordType:
*/
default:
os_free(rr);
msg->rcode = NotImplemented_ResponseType;
#ifdef DNS_RESP_DEBUG
os_printf("Cannot answer question of type %d.\n", q->qType);
#endif
goto next;
}
msg->anCount++;
// prepend resource record to answers list
beg = msg->answers;
msg->answers = rr;
rr->next = beg;
// jump here to omit question
next:
// process next question
q = q->next;
}
}
/* @return 0 upon failure, 1 upon success */
int ICACHE_FLASH_ATTR encode_resource_records(struct ResourceRecord* rr, uint8_t** buffer)
{
int i;
while (rr)
{
// Answer questions by attaching resource sections.
encode_domain_name(buffer, rr->name);
put16bits(buffer, rr->type);
put16bits(buffer, rr->class);
put32bits(buffer, rr->ttl);
put16bits(buffer, rr->rd_length);
switch (rr->type)
{
case A_Resource_RecordType:
for(i = 0; i < 4; ++i)
put8bits(buffer, rr->rd_data.a_record.addr[i]);
break;
/*
case AAAA_Resource_RecordType:
for(i = 0; i < 16; ++i)
put8bits(buffer, rr->rd_data.aaaa_record.addr[i]);
break;
*/
default:
os_printf("Unknown type %u. => Ignore resource record.\n", rr->type);
return 1;
}
rr = rr->next;
}
return 0;
}
/* @return 0 upon failure, 1 upon success */
int ICACHE_FLASH_ATTR encode_msg(struct Message* msg, uint8_t** buffer)
{
struct Question* q;
int rc;
encode_header(msg, buffer);
q = msg->questions;
while (q)
{
encode_domain_name(buffer, q->qName);
put16bits(buffer, q->qType);
put16bits(buffer, q->qClass);
q = q->next;
}
rc = 0;
rc |= encode_resource_records(msg->answers, buffer);
rc |= encode_resource_records(msg->authorities, buffer);
rc |= encode_resource_records(msg->additionals, buffer);
return rc;
}
void ICACHE_FLASH_ATTR free_resource_records(struct ResourceRecord* rr)
{
struct ResourceRecord* next;
while (rr) {
os_free(rr->name);
next = rr->next;
os_free(rr);
rr = next;
}
}
void ICACHE_FLASH_ATTR free_questions(struct Question* qq)
{
struct Question* next;
while (qq) {
os_free(qq->qName);
next = qq->next;
os_free(qq);
qq = next;
}
}
LOCAL void ICACHE_FLASH_ATTR
user_udp_recv(void *arg, char *pusrdata, unsigned short length)
{
uint8_t hwaddr[6];
uint8_t buffer[1024];
struct ip_info ipconfig;
struct espconn *pespconn = (struct espconn *)arg;
remot_info *premot = NULL;
if (espconn_get_connection_info(pespconn,&premot,0) == ESPCONN_OK){
pespconn->proto.udp->remote_port = premot->remote_port;
pespconn->proto.udp->remote_ip[0] = premot->remote_ip[0];
pespconn->proto.udp->remote_ip[1] = premot->remote_ip[1];
pespconn->proto.udp->remote_ip[2] = premot->remote_ip[2];
pespconn->proto.udp->remote_ip[3] = premot->remote_ip[3];
} else {
return;
}
if (wifi_get_opmode() == STATION_MODE) {
//udp packet is received from ESP8266 station
if (!(dns_mode & DNS_MODE_STA))
return;
} else {
wifi_get_ip_info(SOFTAP_IF, &ipconfig);
wifi_get_macaddr(SOFTAP_IF, hwaddr);
if (!ip_addr_netcmp((struct ip_addr *)pespconn->proto.udp->remote_ip, &ipconfig.ip, &ipconfig.netmask)) {
//udp packet is received from ESP8266 station
if (!(dns_mode & DNS_MODE_STA))
return;
} else {
//udp packet is received from ESP8266 softAP
if (!(dns_mode & DNS_MODE_AP))
return;
}
}
if (pusrdata == NULL)
return;
free_questions(msg.questions);
free_resource_records(msg.answers);
free_resource_records(msg.authorities);
free_resource_records(msg.additionals);
os_memset(&msg, 0, sizeof(struct Message));
if (decode_msg(&msg, pusrdata, length) != 0) {
return;
}
#ifdef DNS_RESP_DEBUG
/* Print query */
print_query(&msg);
#endif
resolver_process(&msg);
#ifdef DNS_RESP_DEBUG
/* Print response */
print_query(&msg);
#endif
uint8_t *p = buffer;
if (encode_msg(&msg, &p) != 0) {
return;
}
espconn_sent(pespconn, buffer, p - buffer);
}
void ICACHE_FLASH_ATTR
dns_resp_init(uint8_t mode)
{
dns_mode = mode;
dns_espconn.type = ESPCONN_UDP;
dns_espconn.proto.udp = (esp_udp *)os_zalloc(sizeof(esp_udp));
dns_espconn.proto.udp->local_port = 53; // DNS udp port
espconn_regist_recvcb(&dns_espconn, user_udp_recv); // register a udp packet receiving callback
espconn_create(&dns_espconn); // create udp
}

Wyświetl plik

@ -0,0 +1,8 @@
#define DNS_MODE_STA 0x01
#define DNS_MODE_AP 0x02
#define DNS_MODE_STATIONAP 0x03
void dns_resp_init(uint8_t mode);
int get_A_Record(uint8_t addr[4], const char domain_name[]);

52
user/global.h 100644
Wyświetl plik

@ -0,0 +1,52 @@
#include "user_interface.h"
#include "ringbuf.h"
#include "user_config.h"
#include "config_flash.h"
#include "mqtt/mqtt_server.h"
#include "mqtt/mqtt_topiclist.h"
#include "mqtt/mqtt_retainedlist.h"
#ifdef SCRIPTED
#include "lang.h"
#include "pub_list.h"
#endif
/* Hold the system wide configuration */
#define user_procTaskPrio 0
extern sysconfig_t config;
extern ringbuf_t console_rx_buffer, console_tx_buffer;
extern struct espconn *console_conn;
extern uint8_t remote_console_disconnect;
extern bool mqtt_enabled, mqtt_connected;
extern ip_addr_t my_ip;
extern ip_addr_t dns_ip;
extern bool connected;
extern uint8_t my_channel;
extern bool do_ip_config;
#ifdef MQTT_CLIENT
extern MQTT_Client mqttClient;
extern bool mqtt_enabled, mqtt_connected;
#endif
#ifdef SCRIPTED
extern uint8_t *my_script;
extern struct espconn *downloadCon;
extern struct espconn *scriptcon;
void http_script_cb(char* hostname, char* path, char *response_body, int http_status, char *response_headers, int body_size);
void script_connected_cb(void *arg);
#endif
#ifdef BACKLOG
ringbuf_t backlog_buffer;
#endif
void console_handle_command(struct espconn *pespconn);
void to_console(char *str);
void do_command(char *t1, char *t2, char *t3);
void con_print(uint8_t *str);
void serial_out(uint8_t *str);

107
user/json_path.c 100644
Wyświetl plik

@ -0,0 +1,107 @@
#include "c_types.h"
#include "mem.h"
#include "ets_sys.h"
#include "osapi.h"
#include "os_type.h"
#include "user_interface.h"
#include "string.h"
#include "json/jsonparse.h"
bool ICACHE_FLASH_ATTR find_next_pair(struct jsonparse_state *state, char *name, int level) {
int json_type;
//os_printf ("name: %s level: %d\r\n", name, level);
while((json_type = jsonparse_next(state))) {
//os_printf ("json_type: %d json_level: %d\r\n", json_type, state->depth);
if (state->depth < level-1)
return false;
if (state->depth == level && json_type == JSON_TYPE_PAIR_NAME &&
jsonparse_strcmp_value(state, name) == 0)
return true;
}
return false;
}
bool ICACHE_FLASH_ATTR find_index(struct jsonparse_state *state, int index, int level) {
int json_type;
//os_printf ("index: %d level: %d\r\n", index, level);
index++;
while(index > 0 && (json_type = jsonparse_next(state))) {
//os_printf ("json_type: %d json_level: %d index: %d\r\n", json_type, state->depth, index);
if (state->depth < level-1)
return false;
if (state->depth == level && (json_type == JSON_TYPE_ARRAY || json_type == ',')) {
index--;
}
}
return index == 0;
}
void ICACHE_FLASH_ATTR json_path(char *json, char *path, char *buf, int *buf_size)
{
char *p;
char *ids[JSONPARSE_MAX_DEPTH];
char tmppath[strlen(path)+1];
int i_max = 0;
os_strcpy(tmppath, path);
ids[i_max++] = tmppath;
for (p=tmppath; *p != '\0'; p++) {
if (*p == '.') {
*p = '\0';
ids[i_max++] = p+1;
}
if (*p == '[') {
*p = '\0';
ids[i_max++] = p+1;
}
}
int i;
int level = 1;
struct jsonparse_state state;
int json_type;
bool hit;
int array_count = -1;
jsonparse_setup(&state, json, os_strlen(json));
if (*buf_size > 0)
buf[0] = '\0';
for (i = 0, hit = true; hit && i<i_max; i++) {
if (isdigit(ids[i][0]))
hit = find_index(&state, atoi(ids[i]), level);
else
hit = find_next_pair(&state, ids[i], level);
level += 2;
}
if (!hit) {
*buf_size = 0;
return;
}
level -= 2;
while ((json_type = jsonparse_next(&state))) {
//os_printf ("level: %d json_type: %d json_level: %d\r\n", level, json_type, state.depth);
if (state.depth < level) {
*buf_size = 0;
return;
}
if (json_type == JSON_TYPE_STRING || json_type == JSON_TYPE_INT ||
json_type == JSON_TYPE_NUMBER) {
jsonparse_copy_value(&state, buf, *buf_size);
*buf_size = jsonparse_get_len(&state);
return;
}
}
*buf_size = 0;
return;
}

4
user/json_path.h 100644
Wyświetl plik

@ -0,0 +1,4 @@
#ifndef JSON_PATH_H
#define JSON_PATH_H
void json_path(char *json, char *path, char *buf, int *buf_size);
#endif

2012
user/lang.c 100644

Plik diff jest za duży Load Diff

55
user/lang.h 100644
Wyświetl plik

@ -0,0 +1,55 @@
#ifndef _LANG_
#define _LANG_
#include "mqtt/mqtt_server.h"
typedef enum {SYNTAX_CHECK, CONFIG, INIT, MQTT_CLIENT_CONNECT, WIFI_CONNECT, WIFI_DISCONNECT, TOPIC_LOCAL, TOPIC_REMOTE, TIMER, SERIAL_INPUT, GPIO_INT, ALARM, HTTP_RESPONSE} Interpreter_Status;
typedef enum {STRING_T, DATA_T} Value_Type;
typedef struct _var_entry_t {
uint8_t name[15];
uint8_t free;
uint32_t buffer_len;
uint8_t *data;
uint32_t data_len;
Value_Type data_type;
} var_entry_t;
extern var_entry_t vars[];
extern MQTT_Client mqttClient;
extern bool mqtt_enabled, mqtt_connected;
extern bool lang_logging;
uint8_t tmp_buffer[128];
uint32_t loop_time;
uint32_t loop_count;
int text_into_tokens(char *str);
void free_tokens(void);
bool is_token(int i, char *s);
int search_token(int i, char *s);
int syntax_error(int i, char *message);
int parse_statement(int next_token);
int parse_event(int next_token, bool *happened);
int parse_action(int next_token, bool doit);
int parse_expression(int next_token, char **data, int *data_len, Value_Type * data_type, bool doit);
int parse_value(int next_token, char **data, int *data_len, Value_Type *data_type);
extern bool script_enabled;
int interpreter_syntax_check();
int interpreter_config();
int interpreter_init();
int interpreter_mqtt_connect(void);
int interpreter_wifi_connect(void);
int interpreter_wifi_disconnect(void);
int interpreter_topic_received(const char *topic, const char *data, int data_len, bool local);
int interpreter_serial_input(const char *data, int data_len);
void init_timestamps(uint8_t *curr_time);
void check_timestamps(uint8_t *curr_time);
void init_gpios();
void stop_gpios();
#endif /* _LANG_ */

Wyświetl plik

@ -1,595 +0,0 @@
/* mqtt.c
* Protocol: http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html
*
* Copyright (c) 2014-2015, Tuan PM <tuanpm at live dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "user_interface.h"
#include "osapi.h"
#include "espconn.h"
#include "os_type.h"
#include "mem.h"
#include "mqtt_msg.h"
#include "debug.h"
#include "user_config.h"
#include "config.h"
#include "driver/uart.h"
#include "mqtt.h"
#include "queue.h"
#define MQTT_TASK_PRIO 0
#define MQTT_TASK_QUEUE_SIZE 1
#define MQTT_SEND_TIMOUT 5
#ifndef QUEUE_BUFFER_SIZE
#define QUEUE_BUFFER_SIZE 2048
#endif
unsigned char *default_certificate;
unsigned int default_certificate_len = 0;
unsigned char *default_private_key;
unsigned int default_private_key_len = 0;
os_event_t mqtt_procTaskQueue[MQTT_TASK_QUEUE_SIZE];
LOCAL void ICACHE_FLASH_ATTR
mqtt_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
{
struct espconn *pConn = (struct espconn *)arg;
MQTT_Client* client = (MQTT_Client *)pConn->reverse;
if(ipaddr == NULL)
{
INFO("DNS: Found, but got no ip, try to reconnect\r\n");
client->connState = TCP_RECONNECT_REQ;
return;
}
INFO("DNS: found ip %d.%d.%d.%d\n",
*((uint8 *) &ipaddr->addr),
*((uint8 *) &ipaddr->addr + 1),
*((uint8 *) &ipaddr->addr + 2),
*((uint8 *) &ipaddr->addr + 3));
if(client->ip.addr == 0 && ipaddr->addr != 0)
{
os_memcpy(client->pCon->proto.tcp->remote_ip, &ipaddr->addr, 4);
if(client->security){
espconn_secure_connect(client->pCon);
}
else {
espconn_connect(client->pCon);
}
client->connState = TCP_CONNECTING;
INFO("TCP: connecting...\r\n");
}
system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
}
LOCAL void ICACHE_FLASH_ATTR
deliver_publish(MQTT_Client* client, uint8_t* message, int length)
{
mqtt_event_data_t event_data;
event_data.topic_length = length;
event_data.topic = mqtt_get_publish_topic(message, &event_data.topic_length);
event_data.data_length = length;
event_data.data = mqtt_get_publish_data(message, &event_data.data_length);
if(client->dataCb)
client->dataCb((uint32_t*)client, event_data.topic, event_data.topic_length, event_data.data, event_data.data_length);
}
/**
* @brief Client received callback function.
* @param arg: contain the ip link information
* @param pdata: received data
* @param len: the lenght of received data
* @retval None
*/
void ICACHE_FLASH_ATTR
mqtt_tcpclient_recv(void *arg, char *pdata, unsigned short len)
{
uint8_t msg_type;
uint8_t msg_qos;
uint16_t msg_id;
struct espconn *pCon = (struct espconn*)arg;
MQTT_Client *client = (MQTT_Client *)pCon->reverse;
INFO("TCP: data received\r\n");
if(len < MQTT_BUF_SIZE && len > 0){
os_memcpy(client->mqtt_state.in_buffer, pdata, len);
switch(client->connState){
case MQTT_DATA:
client->mqtt_state.message_length_read = len;
client->mqtt_state.message_length = mqtt_get_total_length(client->mqtt_state.in_buffer, client->mqtt_state.message_length_read);
msg_type = mqtt_get_type(client->mqtt_state.in_buffer);
msg_qos = mqtt_get_qos(client->mqtt_state.in_buffer);
msg_id = mqtt_get_id(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_length);
INFO("MQTT: type: %d, qos: %d, id: %04X\r\n", msg_type, msg_qos, msg_id);
switch(msg_type)
{
case MQTT_MSG_TYPE_CONNACK:
if(client->mqtt_state.pending_msg_type != MQTT_MSG_TYPE_CONNECT){
INFO("MQTT: Invalid packet\r\n");
if(client->security){
espconn_secure_disconnect(client->pCon);
}
else {
espconn_disconnect(client->pCon);
}
} else {
INFO("MQTT: Connected to %s:%d\r\n", client->host, client->port);
if(client->connectedCb)
client->connectedCb((uint32_t*)client);
}
break;
case MQTT_MSG_TYPE_SUBACK:
if(client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_SUBSCRIBE && client->mqtt_state.pending_msg_id == msg_id)
INFO("MQTT: Subscribe successful\r\n");
break;
case MQTT_MSG_TYPE_UNSUBACK:
if(client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_UNSUBSCRIBE && client->mqtt_state.pending_msg_id == msg_id)
INFO("MQTT: UnSubscribe successful\r\n");
break;
case MQTT_MSG_TYPE_PUBLISH:
if(msg_qos == 1)
client->mqtt_state.outbound_message = mqtt_msg_puback(&client->mqtt_state.mqtt_connection, msg_id);
else if(msg_qos == 2)
client->mqtt_state.outbound_message = mqtt_msg_pubrec(&client->mqtt_state.mqtt_connection, msg_id);
if(msg_qos == 1 || msg_qos == 2){
INFO("MQTT: Queue response QoS: %d\r\n", msg_qos);
if(QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){
INFO("MQTT: Exceed the amount of queues\r\n");
}
}
deliver_publish(client, client->mqtt_state.in_buffer, client->mqtt_state.message_length_read);
break;
case MQTT_MSG_TYPE_PUBACK:
if(client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && client->mqtt_state.pending_msg_id == msg_id){
INFO("MQTT: received MQTT_MSG_TYPE_PUBACK, finish QoS1 publish\r\n");
}
break;
case MQTT_MSG_TYPE_PUBREC:
client->mqtt_state.outbound_message = mqtt_msg_pubrel(&client->mqtt_state.mqtt_connection, msg_id);
if(QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){
INFO("MQTT: Exceed the amount of queues\r\n");
}
break;
case MQTT_MSG_TYPE_PUBREL:
client->mqtt_state.outbound_message = mqtt_msg_pubcomp(&client->mqtt_state.mqtt_connection, msg_id);
if(QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){
INFO("MQTT: Exceed the amount of queues\r\n");
}
break;
case MQTT_MSG_TYPE_PUBCOMP:
if(client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && client->mqtt_state.pending_msg_id == msg_id){
INFO("MQTT: receive MQTT_MSG_TYPE_PUBCOMP, finish QoS2 publish\r\n");
}
break;
case MQTT_MSG_TYPE_PINGREQ:
client->mqtt_state.outbound_message = mqtt_msg_pingresp(&client->mqtt_state.mqtt_connection);
if(QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){
INFO("MQTT: Exceed the amount of queues\r\n");
}
break;
case MQTT_MSG_TYPE_PINGRESP:
// Ignore
break;
}
// NOTE: this is done down here and not in the switch case above
// because the PSOCK_READBUF_LEN() won't work inside a switch
// statement due to the way protothreads resume.
if(msg_type == MQTT_MSG_TYPE_PUBLISH)
{
uint16_t len;
// adjust message_length and message_length_read so that
// they only account for the publish data and not the rest of the
// message, this is done so that the offset passed with the
// continuation event is the offset within the publish data and
// not the offset within the message as a whole.
len = client->mqtt_state.message_length_read;
mqtt_get_publish_data(client->mqtt_state.in_buffer, &len);
len = client->mqtt_state.message_length_read - len;
client->mqtt_state.message_length -= len;
client->mqtt_state.message_length_read -= len;
if(client->mqtt_state.message_length_read < client->mqtt_state.message_length)
{
//client->connState = MQTT_PUBLISH_RECV;
//Not Implement yet
INFO("We have more data, read: %d, total: %d\r\n", client->mqtt_state.message_length_read, client->mqtt_state.message_length);
}
}
break;
}
} else {
INFO("ERROR: Too long message\r\n");
}
system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
}
/**
* @brief Client send over callback function.
* @param arg: contain the ip link information
* @retval None
*/
void ICACHE_FLASH_ATTR
mqtt_tcpclient_sent_cb(void *arg)
{
struct espconn *pCon = (struct espconn *)arg;
MQTT_Client* client = (MQTT_Client *)pCon->reverse;
INFO("TCP: Sent\r\n");
client->sendTimeout = 0;
if(client->connState == MQTT_DATA && client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH){
if(client->publishedCb)
client->publishedCb((uint32_t*)client);
}
system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
}
void ICACHE_FLASH_ATTR mqtt_timer(void *arg)
{
MQTT_Client* client = (MQTT_Client*)arg;
if(client->connState == MQTT_DATA){
client->keepAliveTick ++;
if(client->keepAliveTick > client->mqtt_state.connect_info->keepalive){
INFO("\r\nMQTT: Send keepalive packet to %s:%d!\r\n", client->host, client->port);
client->mqtt_state.outbound_message = mqtt_msg_pingreq(&client->mqtt_state.mqtt_connection);
if(QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){
INFO("MQTT: Exceed the amount of queues\r\n");
}
client->keepAliveTick = 0;
system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
}
} else if(client->connState == TCP_RECONNECT_REQ){
client->reconnectTick ++;
if(client->reconnectTick > MQTT_RECONNECT_TIMEOUT) {
client->reconnectTick = 0;
client->connState = TCP_RECONNECT;
system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
}
}
if(client->sendTimeout > 0)
client->sendTimeout --;
}
void ICACHE_FLASH_ATTR
mqtt_tcpclient_discon_cb(void *arg)
{
struct espconn *pespconn = (struct espconn *)arg;
MQTT_Client* client = (MQTT_Client *)pespconn->reverse;
INFO("TCP: Disconnected callback\r\n");
client->connState = TCP_RECONNECT_REQ;
if(client->disconnectedCb)
client->disconnectedCb((uint32_t*)client);
system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
}
/**
* @brief Tcp client connect success callback function.
* @param arg: contain the ip link information
* @retval None
*/
void ICACHE_FLASH_ATTR
mqtt_tcpclient_connect_cb(void *arg)
{
struct espconn *pCon = (struct espconn *)arg;
MQTT_Client* client = (MQTT_Client *)pCon->reverse;
espconn_regist_disconcb(client->pCon, mqtt_tcpclient_discon_cb);
espconn_regist_recvcb(client->pCon, mqtt_tcpclient_recv);////////
espconn_regist_sentcb(client->pCon, mqtt_tcpclient_sent_cb);///////
INFO("MQTT: Connected to broker %s:%d\r\n", client->host, client->port);
mqtt_msg_init(&client->mqtt_state.mqtt_connection, client->mqtt_state.out_buffer, client->mqtt_state.out_buffer_length);
client->mqtt_state.outbound_message = mqtt_msg_connect(&client->mqtt_state.mqtt_connection, client->mqtt_state.connect_info);
if(QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){
INFO("MQTT: Exceed the amount of queues\r\n");
}
client->mqtt_state.outbound_message = NULL;
client->connState = MQTT_DATA;
system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
}
/**
* @brief Tcp client connect repeat callback function.
* @param arg: contain the ip link information
* @retval None
*/
void ICACHE_FLASH_ATTR
mqtt_tcpclient_recon_cb(void *arg, sint8 errType)
{
struct espconn *pCon = (struct espconn *)arg;
MQTT_Client* client = (MQTT_Client *)pCon->reverse;
INFO("TCP: Reconnect to %s:%d\r\n", client->host, client->port);
client->connState = TCP_RECONNECT_REQ;
system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
}
/**
* @brief MQTT publish function.
* @param client: MQTT_Client reference
* @param topic: string topic will publish to
* @param data: buffer data send point to
* @param data_length: length of data
* @param qos: qos
* @param retain: retain
* @retval TRUE if success queue
*/
BOOL ICACHE_FLASH_ATTR
MQTT_Publish(MQTT_Client *client, const char* topic, const char* data, int data_length, int qos, int retain)
{
mqtt_message_t* outbound_message;
outbound_message = mqtt_msg_publish(&client->mqtt_state.mqtt_connection,
topic, data, data_length,
qos, retain,
&client->mqtt_state.pending_msg_id);
INFO("MQTT: queuing publish, length: %d...\r\n", outbound_message->length);
if(QUEUE_Puts(&client->msgQueue, outbound_message->data, outbound_message->length) == -1){
INFO("MQTT: Exceed the amount of queues\r\n");
return FALSE;
}
system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
return TRUE;
}
/**
* @brief MQTT subscibe function.
* @param client: MQTT_Client reference
* @param topic: string topic will subscribe
* @param qos: qos
* @retval TRUE if success queue
*/
BOOL ICACHE_FLASH_ATTR
MQTT_Subscribe(MQTT_Client *client, char* topic, uint8_t qos)
{
client->mqtt_state.outbound_message = mqtt_msg_subscribe(&client->mqtt_state.mqtt_connection,
topic, 0,
&client->mqtt_state.pending_msg_id);
INFO("MQTT: queue subscribe, topic\"%s\", id: %d\r\n",topic, client->mqtt_state.pending_msg_id);
if(QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){
INFO("MQTT: Exceed the amount of queues\r\n");
return FALSE;
}
system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
return TRUE;
}
void ICACHE_FLASH_ATTR
MQTT_Task(os_event_t *e)
{
MQTT_Client* client = (MQTT_Client*)e->par;
uint8_t dataBuffer[MQTT_BUF_SIZE];
uint16_t dataLen;
switch(client->connState){
case TCP_RECONNECT_REQ:
break;
case TCP_RECONNECT:
MQTT_Connect(client);
INFO("TCP:Reconect to: %s:%d\r\n", client->host, client->port);
client->connState = TCP_CONNECTING;
break;
case MQTT_DATA:
if(QUEUE_IsEmpty(&client->msgQueue) || client->sendTimeout != 0) {
break;
}
if(QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == 0){
client->mqtt_state.pending_msg_type = mqtt_get_type(dataBuffer);
client->mqtt_state.pending_msg_id = mqtt_get_id(dataBuffer, dataLen);
client->sendTimeout = MQTT_SEND_TIMOUT;
INFO("MQTT: Sending, type: %d, id: %04X\r\n",client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id);
if(client->security){
espconn_secure_sent(client->pCon, dataBuffer, dataLen);
}
else{
espconn_sent(client->pCon, dataBuffer, dataLen);
}
client->mqtt_state.outbound_message = NULL;
break;
}
break;
}
}
/**
* @brief MQTT initialization connection function
* @param client: MQTT_Client reference
* @param host: Domain or IP string
* @param port: Port to connect
* @param security: 1 for ssl, 0 for none
* @retval None
*/
void MQTT_InitConnection(MQTT_Client *mqttClient, uint8_t* host, uint32 port, uint8_t security)
{
uint32_t temp;
INFO("MQTT_InitConnection\r\n");
os_memset(mqttClient, 0, sizeof(MQTT_Client));
mqttClient->pCon = (struct espconn *)os_zalloc(sizeof(struct espconn));
mqttClient->pCon->type = ESPCONN_TCP;
mqttClient->pCon->state = ESPCONN_NONE;
mqttClient->pCon->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp));
mqttClient->pCon->proto.tcp->local_port = espconn_port();
mqttClient->pCon->proto.tcp->remote_port = port;
temp = os_strlen(host);
mqttClient->host = (uint8_t*)os_zalloc(temp + 1);
os_strcpy(mqttClient->host, host);
mqttClient->host[temp] = 0;
mqttClient->port = port;
mqttClient->security = security;
mqttClient->pCon->reverse = mqttClient;
espconn_regist_connectcb(mqttClient->pCon, mqtt_tcpclient_connect_cb);
espconn_regist_reconcb(mqttClient->pCon, mqtt_tcpclient_recon_cb);
}
/**
* @brief MQTT initialization mqtt client function
* @param client: MQTT_Client reference
* @param clientid: MQTT client id
* @param client_user:MQTT client user
* @param client_pass:MQTT client password
* @param client_pass:MQTT keep alive timer, in second
* @retval None
*/
void MQTT_InitClient(MQTT_Client *mqttClient, uint8_t* client_id, uint8_t* client_user, uint8_t* client_pass, uint32_t keepAliveTime, uint8_t cleanSession)
{
uint32_t temp;
INFO("MQTT_InitClient\r\n");
os_memset(&mqttClient->connect_info, 0, sizeof(mqtt_connect_info_t));
temp = os_strlen(client_id);
mqttClient->connect_info.client_id = (uint8_t*)os_zalloc(temp + 1);
os_strcpy(mqttClient->connect_info.client_id, client_id);
mqttClient->connect_info.client_id[temp] = 0;
temp = os_strlen(client_user);
mqttClient->connect_info.username = (uint8_t*)os_zalloc(temp + 1);
os_strcpy(mqttClient->connect_info.username, client_user);
mqttClient->connect_info.username[temp] = 0;
temp = os_strlen(client_pass);
mqttClient->connect_info.password = (uint8_t*)os_zalloc(temp + 1);
os_strcpy(mqttClient->connect_info.password, client_pass);
mqttClient->connect_info.password[temp] = 0;
mqttClient->connect_info.keepalive = keepAliveTime;
mqttClient->connect_info.clean_session = cleanSession;
mqttClient->mqtt_state.in_buffer = (uint8_t *)os_zalloc(MQTT_BUF_SIZE);
mqttClient->mqtt_state.in_buffer_length = MQTT_BUF_SIZE;
mqttClient->mqtt_state.out_buffer = (uint8_t *)os_zalloc(MQTT_BUF_SIZE);
mqttClient->mqtt_state.out_buffer_length = MQTT_BUF_SIZE;
mqttClient->mqtt_state.connect_info = &mqttClient->connect_info;
mqttClient->keepAliveTick = 0;
mqttClient->reconnectTick = 0;
os_timer_disarm(&mqttClient->mqttTimer);
os_timer_setfn(&mqttClient->mqttTimer, (os_timer_func_t *)mqtt_timer, mqttClient);
os_timer_arm(&mqttClient->mqttTimer, 1000, 1);
QUEUE_Init(&mqttClient->msgQueue, QUEUE_BUFFER_SIZE);
system_os_task(MQTT_Task, MQTT_TASK_PRIO, mqtt_procTaskQueue, MQTT_TASK_QUEUE_SIZE);
system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)mqttClient);
}
void MQTT_InitLWT(MQTT_Client *mqttClient, uint8_t* will_topic, uint8_t* will_msg, uint8_t will_qos, uint8_t will_retain)
{
uint32_t temp;
temp = os_strlen(will_topic);
mqttClient->connect_info.will_topic = (uint8_t*)os_zalloc(temp + 1);
os_strcpy(mqttClient->connect_info.will_topic, will_topic);
mqttClient->connect_info.will_topic[temp] = 0;
temp = os_strlen(will_msg);
mqttClient->connect_info.will_message = (uint8_t*)os_zalloc(temp + 1);
os_strcpy(mqttClient->connect_info.will_message, will_msg);
mqttClient->connect_info.will_message[temp] = 0;
mqttClient->connect_info.will_qos = will_qos;
mqttClient->connect_info.will_retain = will_retain;
}
/**
* @brief Begin connect to MQTT broker
* @param client: MQTT_Client reference
* @retval None
*/
void MQTT_Connect(MQTT_Client *mqttClient)
{
if(UTILS_StrToIP(mqttClient->host, &mqttClient->pCon->proto.tcp->remote_ip)) {
INFO("TCP: Connect to ip %s:%d\r\n", mqttClient->host, mqttClient->port);
if(mqttClient->security){
espconn_secure_connect(mqttClient->pCon);
}
else {
espconn_connect(mqttClient->pCon);
}
}
else {
INFO("TCP: Connect to domain %s:%d\r\n", mqttClient->host, mqttClient->port);
espconn_gethostbyname(mqttClient->pCon, mqttClient->host, &mqttClient->ip, mqtt_dns_found);
}
mqttClient->connState = TCP_CONNECTING;
}
void MQTT_OnConnected(MQTT_Client *mqttClient, MqttCallback connectedCb)
{
mqttClient->connectedCb = connectedCb;
}
void MQTT_OnDisconnected(MQTT_Client *mqttClient, MqttCallback disconnectedCb)
{
mqttClient->disconnectedCb = disconnectedCb;
}
void MQTT_OnData(MQTT_Client *mqttClient, MqttDataCallback dataCb)
{
mqttClient->dataCb = dataCb;
}
void MQTT_OnPublished(MQTT_Client *mqttClient, MqttCallback publishedCb)
{
mqttClient->publishedCb = publishedCb;
}

Wyświetl plik

@ -1,136 +0,0 @@
/* mqtt.h
*
* Copyright (c) 2014-2015, Tuan PM <tuanpm at live dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef USER_AT_MQTT_H_
#define USER_AT_MQTT_H_
#include "mqtt_msg.h"
#include "user_interface.h"
#include "queue.h"
typedef struct mqtt_event_data_t
{
uint8_t type;
const char* topic;
const char* data;
uint16_t topic_length;
uint16_t data_length;
uint16_t data_offset;
} mqtt_event_data_t;
typedef struct mqtt_state_t
{
uint16_t port;
int auto_reconnect;
mqtt_connect_info_t* connect_info;
uint8_t* in_buffer;
uint8_t* out_buffer;
int in_buffer_length;
int out_buffer_length;
uint16_t message_length;
uint16_t message_length_read;
mqtt_message_t* outbound_message;
mqtt_connection_t mqtt_connection;
uint16_t pending_msg_id;
int pending_msg_type;
int pending_publish_qos;
} mqtt_state_t;
typedef enum {
WIFI_INIT,
WIFI_CONNECTING,
WIFI_CONNECTING_ERROR,
WIFI_CONNECTED,
DNS_RESOLVE,
TCP_DISCONNECTED,
TCP_RECONNECT_REQ,
TCP_RECONNECT,
TCP_CONNECTING,
TCP_CONNECTING_ERROR,
TCP_CONNECTED,
MQTT_CONNECT_SEND,
MQTT_CONNECT_SENDING,
MQTT_SUBSCIBE_SEND,
MQTT_SUBSCIBE_SENDING,
MQTT_DATA,
MQTT_PUBLISH_RECV,
MQTT_PUBLISHING
} tConnState;
typedef void (*MqttCallback)(uint32_t *args);
typedef void (*MqttDataCallback)(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t lengh);
typedef struct {
struct espconn *pCon;
uint8_t security;
uint8_t* host;
uint32_t port;
ip_addr_t ip;
mqtt_state_t mqtt_state;
mqtt_connect_info_t connect_info;
MqttCallback connectedCb;
MqttCallback disconnectedCb;
MqttCallback publishedCb;
MqttDataCallback dataCb;
ETSTimer mqttTimer;
uint32_t keepAliveTick;
uint32_t reconnectTick;
uint32_t sendTimeout;
tConnState connState;
QUEUE msgQueue;
} MQTT_Client;
#define SEC_NONSSL 0
#define SEC_SSL 1
#define MQTT_FLAG_CONNECTED 1
#define MQTT_FLAG_READY 2
#define MQTT_FLAG_EXIT 4
#define MQTT_EVENT_TYPE_NONE 0
#define MQTT_EVENT_TYPE_CONNECTED 1
#define MQTT_EVENT_TYPE_DISCONNECTED 2
#define MQTT_EVENT_TYPE_SUBSCRIBED 3
#define MQTT_EVENT_TYPE_UNSUBSCRIBED 4
#define MQTT_EVENT_TYPE_PUBLISH 5
#define MQTT_EVENT_TYPE_PUBLISHED 6
#define MQTT_EVENT_TYPE_EXITED 7
#define MQTT_EVENT_TYPE_PUBLISH_CONTINUATION 8
void MQTT_InitConnection(MQTT_Client *mqttClient, uint8_t* host, uint32 port, uint8_t security);
void MQTT_InitClient(MQTT_Client *mqttClient, uint8_t* client_id, uint8_t* client_user, uint8_t* client_pass, uint32_t keepAliveTime, uint8_t cleanSession);
void MQTT_InitLWT(MQTT_Client *mqttClient, uint8_t* will_topic, uint8_t* will_msg, uint8_t will_qos, uint8_t will_retain);
void MQTT_OnConnected(MQTT_Client *mqttClient, MqttCallback connectedCb);
void MQTT_OnDisconnected(MQTT_Client *mqttClient, MqttCallback disconnectedCb);
void MQTT_OnPublished(MQTT_Client *mqttClient, MqttCallback publishedCb);
void MQTT_OnData(MQTT_Client *mqttClient, MqttDataCallback dataCb);
BOOL MQTT_Subscribe(MQTT_Client *client, char* topic, uint8_t qos);
void MQTT_Connect(MQTT_Client *mqttClient);
BOOL MQTT_Publish(MQTT_Client *client, const char* topic, const char* data, int data_length, int qos, int retain);
#endif /* USER_AT_MQTT_H_ */

Wyświetl plik

@ -1,457 +0,0 @@
/*
* Copyright (c) 2014, Stephen Robinson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <string.h>
#include "mqtt_msg.h"
#define MQTT_MAX_FIXED_HEADER_SIZE 3
enum mqtt_connect_flag
{
MQTT_CONNECT_FLAG_USERNAME = 1 << 7,
MQTT_CONNECT_FLAG_PASSWORD = 1 << 6,
MQTT_CONNECT_FLAG_WILL_RETAIN = 1 << 5,
MQTT_CONNECT_FLAG_WILL = 1 << 2,
MQTT_CONNECT_FLAG_CLEAN_SESSION = 1 << 1
};
struct __attribute((__packed__)) mqtt_connect_variable_header
{
uint8_t lengthMsb;
uint8_t lengthLsb;
uint8_t magic[6];
uint8_t version;
uint8_t flags;
uint8_t keepaliveMsb;
uint8_t keepaliveLsb;
};
static int append_string(mqtt_connection_t* connection, const char* string, int len)
{
if(connection->message.length + len + 2 > connection->buffer_length)
return -1;
connection->buffer[connection->message.length++] = len >> 8;
connection->buffer[connection->message.length++] = len & 0xff;
memcpy(connection->buffer + connection->message.length, string, len);
connection->message.length += len;
return len + 2;
}
static uint16_t append_message_id(mqtt_connection_t* connection, uint16_t message_id)
{
// If message_id is zero then we should assign one, otherwise
// we'll use the one supplied by the caller
while(message_id == 0)
message_id = ++connection->message_id;
if(connection->message.length + 2 > connection->buffer_length)
return 0;
connection->buffer[connection->message.length++] = message_id >> 8;
connection->buffer[connection->message.length++] = message_id & 0xff;
return message_id;
}
static int init_message(mqtt_connection_t* connection)
{
connection->message.length = MQTT_MAX_FIXED_HEADER_SIZE;
return MQTT_MAX_FIXED_HEADER_SIZE;
}
static mqtt_message_t* fail_message(mqtt_connection_t* connection)
{
connection->message.data = connection->buffer;
connection->message.length = 0;
return &connection->message;
}
static mqtt_message_t* fini_message(mqtt_connection_t* connection, int type, int dup, int qos, int retain)
{
int remaining_length = connection->message.length - MQTT_MAX_FIXED_HEADER_SIZE;
if(remaining_length > 127)
{
connection->buffer[0] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1);
connection->buffer[1] = 0x80 | (remaining_length % 128);
connection->buffer[2] = remaining_length / 128;
connection->message.length = remaining_length + 3;
connection->message.data = connection->buffer;
}
else
{
connection->buffer[1] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1);
connection->buffer[2] = remaining_length;
connection->message.length = remaining_length + 2;
connection->message.data = connection->buffer + 1;
}
return &connection->message;
}
void mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length)
{
memset(connection, 0, sizeof(connection));
connection->buffer = buffer;
connection->buffer_length = buffer_length;
}
int mqtt_get_total_length(uint8_t* buffer, uint16_t length)
{
int i;
int totlen = 0;
for(i = 1; i < length; ++i)
{
totlen += (buffer[i] & 0x7f) << (7 * (i - 1));
if((buffer[i] & 0x80) == 0)
{
++i;
break;
}
}
totlen += i;
return totlen;
}
const char* mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length)
{
int i;
int totlen = 0;
int topiclen;
for(i = 1; i < *length; ++i)
{
totlen += (buffer[i] & 0x7f) << (7 * (i -1));
if((buffer[i] & 0x80) == 0)
{
++i;
break;
}
}
totlen += i;
if(i + 2 >= *length)
return NULL;
topiclen = buffer[i++] << 8;
topiclen |= buffer[i++];
if(i + topiclen > *length)
return NULL;
*length = topiclen;
return (const char*)(buffer + i);
}
const char* mqtt_get_publish_data(uint8_t* buffer, uint16_t* length)
{
int i;
int totlen = 0;
int topiclen;
for(i = 1; i < *length; ++i)
{
totlen += (buffer[i] & 0x7f) << (7 * (i - 1));
if((buffer[i] & 0x80) == 0)
{
++i;
break;
}
}
totlen += i;
if(i + 2 >= *length)
return NULL;
topiclen = buffer[i++] << 8;
topiclen |= buffer[i++];
if(i + topiclen >= *length){
*length = 0;
return NULL;
}
i += topiclen;
if(mqtt_get_qos(buffer) > 0)
{
if(i + 2 >= *length)
return NULL;
i += 2;
}
if(totlen < i)
return NULL;
if(totlen <= *length)
*length = totlen - i;
else
*length = *length - i;
return (const char*)(buffer + i);
}
uint16_t mqtt_get_id(uint8_t* buffer, uint16_t length)
{
if(length < 1)
return 0;
switch(mqtt_get_type(buffer))
{
case MQTT_MSG_TYPE_PUBLISH:
{
int i;
int topiclen;
for(i = 1; i < length; ++i)
{
if((buffer[i] & 0x80) == 0)
{
++i;
break;
}
}
if(i + 2 >= length)
return 0;
topiclen = buffer[i++] << 8;
topiclen |= buffer[i++];
if(i + topiclen >= length)
return 0;
i += topiclen;
if(mqtt_get_qos(buffer) > 0)
{
if(i + 2 >= length)
return 0;
//i += 2;
} else {
return 0;
}
return (buffer[i] << 8) | buffer[i + 1];
}
case MQTT_MSG_TYPE_PUBACK:
case MQTT_MSG_TYPE_PUBREC:
case MQTT_MSG_TYPE_PUBREL:
case MQTT_MSG_TYPE_PUBCOMP:
case MQTT_MSG_TYPE_SUBACK:
case MQTT_MSG_TYPE_UNSUBACK:
case MQTT_MSG_TYPE_SUBSCRIBE:
{
// This requires the remaining length to be encoded in 1 byte,
// which it should be.
if(length >= 4 && (buffer[1] & 0x80) == 0)
return (buffer[2] << 8) | buffer[3];
else
return 0;
}
default:
return 0;
}
}
mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info)
{
struct mqtt_connect_variable_header* variable_header;
init_message(connection);
if(connection->message.length + sizeof(*variable_header) > connection->buffer_length)
return fail_message(connection);
variable_header = (void*)(connection->buffer + connection->message.length);
connection->message.length += sizeof(*variable_header);
variable_header->lengthMsb = 0;
variable_header->lengthLsb = 6;
memcpy(variable_header->magic, "MQIsdp", 6);
variable_header->version = 3;
variable_header->flags = 0;
variable_header->keepaliveMsb = info->keepalive >> 8;
variable_header->keepaliveLsb = info->keepalive & 0xff;
if(info->clean_session)
variable_header->flags |= MQTT_CONNECT_FLAG_CLEAN_SESSION;
if(info->client_id != NULL && info->client_id[0] != '\0')
{
if(append_string(connection, info->client_id, strlen(info->client_id)) < 0)
return fail_message(connection);
}
else
return fail_message(connection);
if(info->will_topic != NULL && info->will_topic[0] != '\0')
{
if(append_string(connection, info->will_topic, strlen(info->will_topic)) < 0)
return fail_message(connection);
if(append_string(connection, info->will_message, strlen(info->will_message)) < 0)
return fail_message(connection);
variable_header->flags |= MQTT_CONNECT_FLAG_WILL;
if(info->will_retain)
variable_header->flags |= MQTT_CONNECT_FLAG_WILL_RETAIN;
variable_header->flags |= (info->will_qos & 3) << 4;
}
if(info->username != NULL && info->username[0] != '\0')
{
if(append_string(connection, info->username, strlen(info->username)) < 0)
return fail_message(connection);
variable_header->flags |= MQTT_CONNECT_FLAG_USERNAME;
}
if(info->password != NULL && info->password[0] != '\0')
{
if(append_string(connection, info->password, strlen(info->password)) < 0)
return fail_message(connection);
variable_header->flags |= MQTT_CONNECT_FLAG_PASSWORD;
}
return fini_message(connection, MQTT_MSG_TYPE_CONNECT, 0, 0, 0);
}
mqtt_message_t* mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id)
{
init_message(connection);
if(topic == NULL || topic[0] == '\0')
return fail_message(connection);
if(append_string(connection, topic, strlen(topic)) < 0)
return fail_message(connection);
if(qos > 0)
{
if((*message_id = append_message_id(connection, 0)) == 0)
return fail_message(connection);
}
else
*message_id = 0;
if(connection->message.length + data_length > connection->buffer_length)
return fail_message(connection);
memcpy(connection->buffer + connection->message.length, data, data_length);
connection->message.length += data_length;
return fini_message(connection, MQTT_MSG_TYPE_PUBLISH, 0, qos, retain);
}
mqtt_message_t* mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id)
{
init_message(connection);
if(append_message_id(connection, message_id) == 0)
return fail_message(connection);
return fini_message(connection, MQTT_MSG_TYPE_PUBACK, 0, 0, 0);
}
mqtt_message_t* mqtt_msg_pubrec(mqtt_connection_t* connection, uint16_t message_id)
{
init_message(connection);
if(append_message_id(connection, message_id) == 0)
return fail_message(connection);
return fini_message(connection, MQTT_MSG_TYPE_PUBREC, 0, 0, 0);
}
mqtt_message_t* mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id)
{
init_message(connection);
if(append_message_id(connection, message_id) == 0)
return fail_message(connection);
return fini_message(connection, MQTT_MSG_TYPE_PUBREL, 0, 1, 0);
}
mqtt_message_t* mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id)
{
init_message(connection);
if(append_message_id(connection, message_id) == 0)
return fail_message(connection);
return fini_message(connection, MQTT_MSG_TYPE_PUBCOMP, 0, 0, 0);
}
mqtt_message_t* mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id)
{
init_message(connection);
if(topic == NULL || topic[0] == '\0')
return fail_message(connection);
if((*message_id = append_message_id(connection, 0)) == 0)
return fail_message(connection);
if(append_string(connection, topic, strlen(topic)) < 0)
return fail_message(connection);
if(connection->message.length + 1 > connection->buffer_length)
return fail_message(connection);
connection->buffer[connection->message.length++] = qos;
return fini_message(connection, MQTT_MSG_TYPE_SUBSCRIBE, 0, 1, 0);
}
mqtt_message_t* mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id)
{
init_message(connection);
if(topic == NULL || topic[0] == '\0')
return fail_message(connection);
if((*message_id = append_message_id(connection, 0)) == 0)
return fail_message(connection);
if(append_string(connection, topic, strlen(topic)) < 0)
return fail_message(connection);
return fini_message(connection, MQTT_MSG_TYPE_SUBSCRIBE, 0, 1, 0);
}
mqtt_message_t* mqtt_msg_pingreq(mqtt_connection_t* connection)
{
init_message(connection);
return fini_message(connection, MQTT_MSG_TYPE_PINGREQ, 0, 0, 0);
}
mqtt_message_t* mqtt_msg_pingresp(mqtt_connection_t* connection)
{
init_message(connection);
return fini_message(connection, MQTT_MSG_TYPE_PINGRESP, 0, 0, 0);
}
mqtt_message_t* mqtt_msg_disconnect(mqtt_connection_t* connection)
{
init_message(connection);
return fini_message(connection, MQTT_MSG_TYPE_DISCONNECT, 0, 0, 0);
}

Wyświetl plik

@ -1,129 +0,0 @@
/*
* File: mqtt_msg.h
* Author: Minh Tuan
*
* Created on July 12, 2014, 1:05 PM
*/
#ifndef MQTT_MSG_H
#define MQTT_MSG_H
#include "c_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* Copyright (c) 2014, Stephen Robinson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
/* 7 6 5 4 3 2 1 0*/
/*| --- Message Type---- | DUP Flag | QoS Level | Retain |
/* Remaining Length */
enum mqtt_message_type
{
MQTT_MSG_TYPE_CONNECT = 1,
MQTT_MSG_TYPE_CONNACK = 2,
MQTT_MSG_TYPE_PUBLISH = 3,
MQTT_MSG_TYPE_PUBACK = 4,
MQTT_MSG_TYPE_PUBREC = 5,
MQTT_MSG_TYPE_PUBREL = 6,
MQTT_MSG_TYPE_PUBCOMP = 7,
MQTT_MSG_TYPE_SUBSCRIBE = 8,
MQTT_MSG_TYPE_SUBACK = 9,
MQTT_MSG_TYPE_UNSUBSCRIBE = 10,
MQTT_MSG_TYPE_UNSUBACK = 11,
MQTT_MSG_TYPE_PINGREQ = 12,
MQTT_MSG_TYPE_PINGRESP = 13,
MQTT_MSG_TYPE_DISCONNECT = 14
};
typedef struct mqtt_message
{
uint8_t* data;
uint16_t length;
} mqtt_message_t;
typedef struct mqtt_connection
{
mqtt_message_t message;
uint16_t message_id;
uint8_t* buffer;
uint16_t buffer_length;
} mqtt_connection_t;
typedef struct mqtt_connect_info
{
char* client_id;
char* username;
char* password;
char* will_topic;
char* will_message;
int keepalive;
int will_qos;
int will_retain;
int clean_session;
} mqtt_connect_info_t;
static inline int mqtt_get_type(uint8_t* buffer) { return (buffer[0] & 0xf0) >> 4; }
static inline int mqtt_get_dup(uint8_t* buffer) { return (buffer[0] & 0x08) >> 3; }
static inline int mqtt_get_qos(uint8_t* buffer) { return (buffer[0] & 0x06) >> 1; }
static inline int mqtt_get_retain(uint8_t* buffer) { return (buffer[0] & 0x01); }
void mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length);
int mqtt_get_total_length(uint8_t* buffer, uint16_t length);
const char* mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length);
const char* mqtt_get_publish_data(uint8_t* buffer, uint16_t* length);
uint16_t mqtt_get_id(uint8_t* buffer, uint16_t length);
mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info);
mqtt_message_t* mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id);
mqtt_message_t* mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id);
mqtt_message_t* mqtt_msg_pubrec(mqtt_connection_t* connection, uint16_t message_id);
mqtt_message_t* mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id);
mqtt_message_t* mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id);
mqtt_message_t* mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id);
mqtt_message_t* mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id);
mqtt_message_t* mqtt_msg_pingreq(mqtt_connection_t* connection);
mqtt_message_t* mqtt_msg_pingresp(mqtt_connection_t* connection);
mqtt_message_t* mqtt_msg_disconnect(mqtt_connection_t* connection);
#ifdef __cplusplus
}
#endif
#endif /* MQTT_MSG_H */

Wyświetl plik

@ -1,129 +0,0 @@
#include "proto.h"
#include "ringbuf.h"
I8 PROTO_Init(PROTO_PARSER *parser, PROTO_PARSE_CALLBACK *completeCallback, U8 *buf, U16 bufSize)
{
parser->buf = buf;
parser->bufSize = bufSize;
parser->dataLen = 0;
parser->callback = completeCallback;
parser->isEsc = 0;
return 0;
}
I8 PROTO_ParseByte(PROTO_PARSER *parser, U8 value)
{
switch(value){
case 0x7D:
parser->isEsc = 1;
break;
case 0x7E:
parser->dataLen = 0;
parser->isEsc = 0;
parser->isBegin = 1;
break;
case 0x7F:
if (parser->callback != NULL)
parser->callback();
parser->isBegin = 0;
return 0;
break;
default:
if(parser->isBegin == 0) break;
if(parser->isEsc){
value ^= 0x20;
parser->isEsc = 0;
}
if(parser->dataLen < parser->bufSize)
parser->buf[parser->dataLen++] = value;
break;
}
return -1;
}
I8 PROTO_Parse(PROTO_PARSER *parser, U8 *buf, U16 len)
{
while(len--)
PROTO_ParseByte(parser, *buf++);
return 0;
}
I16 PROTO_ParseRb(RINGBUF* rb, U8 *bufOut, U16* len, U16 maxBufLen)
{
U8 c;
PROTO_PARSER proto;
PROTO_Init(&proto, NULL, bufOut, maxBufLen);
while(RINGBUF_Get(rb, &c) == 0){
if(PROTO_ParseByte(&proto, c) == 0){
*len = proto.dataLen;
return 0;
}
}
return -1;
}
I16 PROTO_Add(U8 *buf, const U8 *packet, I16 bufSize)
{
U16 i = 2;
U16 len = *(U16*) packet;
if (bufSize < 1) return -1;
*buf++ = 0x7E;
bufSize--;
while (len--) {
switch (*packet) {
case 0x7D:
case 0x7E:
case 0x7F:
if (bufSize < 2) return -1;
*buf++ = 0x7D;
*buf++ = *packet++ ^ 0x20;
i += 2;
bufSize -= 2;
break;
default:
if (bufSize < 1) return -1;
*buf++ = *packet++;
i++;
bufSize--;
break;
}
}
if (bufSize < 1) return -1;
*buf++ = 0x7F;
return i;
}
I16 PROTO_AddRb(RINGBUF *rb, const U8 *packet, I16 len)
{
U16 i = 2;
if(RINGBUF_Put(rb, 0x7E) == -1) return -1;
while (len--) {
switch (*packet) {
case 0x7D:
case 0x7E:
case 0x7F:
if(RINGBUF_Put(rb, 0x7D) == -1) return -1;
if(RINGBUF_Put(rb, *packet++ ^ 0x20) == -1) return -1;
i += 2;
break;
default:
if(RINGBUF_Put(rb, *packet++) == -1) return -1;
i++;
break;
}
}
if(RINGBUF_Put(rb, 0x7F) == -1) return -1;
return i;
}

Wyświetl plik

@ -1,32 +0,0 @@
/*
* File: proto.h
* Author: ThuHien
*
* Created on November 23, 2012, 8:57 AM
*/
#ifndef _PROTO_H_
#define _PROTO_H_
#include <stdlib.h>
#include "typedef.h"
#include "ringbuf.h"
typedef void(PROTO_PARSE_CALLBACK)();
typedef struct{
U8 *buf;
U16 bufSize;
U16 dataLen;
U8 isEsc;
U8 isBegin;
PROTO_PARSE_CALLBACK* callback;
}PROTO_PARSER;
I8 PROTO_Init(PROTO_PARSER *parser, PROTO_PARSE_CALLBACK *completeCallback, U8 *buf, U16 bufSize);
I8 PROTO_Parse(PROTO_PARSER *parser, U8 *buf, U16 len);
I16 PROTO_Add(U8 *buf, const U8 *packet, I16 bufSize);
I16 PROTO_AddRb(RINGBUF *rb, const U8 *packet, I16 len);
I8 PROTO_ParseByte(PROTO_PARSER *parser, U8 value);
I16 PROTO_ParseRb(RINGBUF *rb, U8 *bufOut, U16* len, U16 maxBufLen);
#endif

65
user/pub_list.c 100644
Wyświetl plik

@ -0,0 +1,65 @@
#include "c_types.h"
#include "mem.h"
#include "osapi.h"
#include "user_config.h"
#include "lang.h"
#include "pub_list.h"
typedef struct _pub_entry {
char *topic;
char *data;
uint32_t data_len;
bool local;
struct _pub_entry *next;
} pub_entry;
static pub_entry *pub_list = NULL;
void ICACHE_FLASH_ATTR pub_insert(const char* topic, uint32_t topic_len, const char *data, uint32_t data_len, bool local)
{
pub_entry *pub = (pub_entry *)os_malloc(sizeof(pub_entry));
if (pub == NULL)
return;
pub->topic = (char*)os_malloc(topic_len+1);
if (pub->topic == NULL) {
os_free(pub);
return;
}
pub->data = (char*)os_malloc(data_len+1);
if (pub->data == NULL) {
os_free(pub->topic);
os_free(pub);
return;
}
os_memcpy(pub->topic, topic, topic_len);
pub->topic[topic_len] = '\0';
os_memcpy(pub->data, data, data_len);
pub->data_len = data_len;
pub->data[data_len] = '\0';
pub->local = local;
pub->next = pub_list;
pub_list = pub;
}
void ICACHE_FLASH_ATTR pub_process()
{
pub_entry **pre_last, *last;
while (pub_list != NULL) {
pre_last = &pub_list;
while ((*pre_last)->next != NULL)
pre_last = &((*pre_last)->next);
last = *pre_last;
*pre_last = NULL;
interpreter_topic_received(last->topic, last->data, last->data_len, last->local);
os_free(last->topic);
os_free(last->data);
os_free(last);
}
}

7
user/pub_list.h 100644
Wyświetl plik

@ -0,0 +1,7 @@
#ifndef _PUB_LIST_
#define _PUB_LIST_
void pub_insert(const char* topic, uint32_t topic_len, const char *data, uint32_t data_len, bool local);
void pub_process();
#endif /* _PUB_LIST_ */

Wyświetl plik

@ -1,57 +0,0 @@
/* str_queue.c
*
* Copyright (c) 2014-2015, Tuan PM <tuanpm at live dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "queue.h"
#include "user_interface.h"
#include "osapi.h"
#include "os_type.h"
#include "mem.h"
#include "proto.h"
void QUEUE_Init(QUEUE *queue, int bufferSize)
{
queue->buf = (uint8_t*)os_zalloc(bufferSize);
RINGBUF_Init(&queue->rb, queue->buf, bufferSize);
}
int32_t QUEUE_Puts(QUEUE *queue, uint8_t* buffer, uint16_t len)
{
return PROTO_AddRb(&queue->rb, buffer, len);
}
int32_t QUEUE_Gets(QUEUE *queue, uint8_t* buffer, uint16_t* len, uint16_t maxLen)
{
return PROTO_ParseRb(&queue->rb, buffer, len, maxLen);
}
BOOL QUEUE_IsEmpty(QUEUE *queue)
{
if(queue->rb.fill_cnt<=0)
return TRUE;
return FALSE;
}

Wyświetl plik

@ -1,44 +0,0 @@
/* str_queue.h --
*
* Copyright (c) 2014-2015, Tuan PM <tuanpm at live dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef USER_QUEUE_H_
#define USER_QUEUE_H_
#include "os_type.h"
#include "ringbuf.h"
typedef struct {
uint8_t *buf;
RINGBUF rb;
} QUEUE;
void QUEUE_Init(QUEUE *queue, int bufferSize);
int32_t QUEUE_Puts(QUEUE *queue, uint8_t* buffer, uint16_t len);
int32_t QUEUE_Gets(QUEUE *queue, uint8_t* buffer, uint16_t* len, uint16_t maxLen);
BOOL QUEUE_IsEmpty(QUEUE *queue);
#endif /* USER_QUEUE_H_ */

74
user/rfinit.c 100644
Wyświetl plik

@ -0,0 +1,74 @@
/******************************************************************************
* Copyright 2016 Vowstar
*
* FileName: init.c
*
* Description: System and user APP initialization.
*
* Modification history:
* 2016/03/24, v1.0 create this file.
*******************************************************************************/
#include "ets_sys.h"
#include "osapi.h"
#include "user_interface.h"
/******************************************************************************
* FunctionName : user_rf_cal_sector_set
* Description : SDK just reversed 4 sectors, used for rf init data and paramters.
* We add this function to force users to set rf cal sector, since
* we don't know which sector is free in user's application.
* sector map for last several sectors : ABCCC
* A : rf cal
* B : rf init data
* C : sdk parameters
* Parameters : none
* Returns : rf cal sector
*******************************************************************************/
uint32 ICACHE_FLASH_ATTR __attribute__ ((weak))
user_rf_cal_sector_set(void) {
enum flash_size_map size_map = system_get_flash_size_map();
uint32 rf_cal_sec = 0;
switch (size_map) {
case FLASH_SIZE_4M_MAP_256_256:
rf_cal_sec = 128 - 5;
break;
case FLASH_SIZE_8M_MAP_512_512:
rf_cal_sec = 256 - 5;
break;
case FLASH_SIZE_16M_MAP_512_512:
case FLASH_SIZE_16M_MAP_1024_1024:
rf_cal_sec = 512 - 5;
break;
case FLASH_SIZE_32M_MAP_512_512:
case FLASH_SIZE_32M_MAP_1024_1024:
rf_cal_sec = 1024 - 5;
break;
default:
rf_cal_sec = 0;
break;
}
return rf_cal_sec;
}
void __attribute__ ((weak))
user_rf_pre_init(void) {
// Warning: IF YOU DON'T KNOW WHAT YOU ARE DOING, DON'T TOUCH THESE CODE
// Control RF_CAL by esp_init_data_default.bin(0~127byte) 108 byte when wakeup
// Will low current
// system_phy_set_rfoption(0)
// Process RF_CAL when wakeup.
// Will high current
system_phy_set_rfoption(1);
// Set Wi-Fi Tx Power, Unit: 0.25dBm, Range: [0, 82]
system_phy_set_max_tpw(82);
}

Wyświetl plik

@ -1,67 +1,216 @@
/**
* \file
* Ring Buffer library
*/
/*
* ringbuf.c - C ring buffer (FIFO) implementation.
*
* Written in 2011 by Drew Hess <dhess-src@bothan.net>.
*
* To the extent possible under law, the author(s) have dedicated all
* copyright and related and neighboring rights to this software to
* the public domain worldwide. This software is distributed without
* any warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication
* along with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include "ringbuf.h"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/param.h>
/**
* \brief init a RINGBUF object
* \param r pointer to a RINGBUF object
* \param buf pointer to a byte array
* \param size size of buf
* \return 0 if successfull, otherwise failed
*/
I16 RINGBUF_Init(RINGBUF *r, U8* buf, I32 size)
{
if(r == NULL || buf == NULL || size < 2) return -1;
r->p_o = r->p_r = r->p_w = buf;
r->fill_cnt = 0;
r->size = size;
return 0;
#include "osapi.h"
#include "mem.h"
#define assert(x)
/*
* The code is written for clarity, not cleverness or performance, and
* contains many assert()s to enforce invariant assumptions and catch
* bugs. Feel free to optimize the code and to remove asserts for use
* in your own projects, once you're comfortable that it functions as
* intended.
*/
struct ringbuf_t {
uint8_t *buf;
uint8_t *head, *tail;
size_t size;
};
ringbuf_t ringbuf_new(size_t capacity) {
ringbuf_t rb = (ringbuf_t) os_malloc(sizeof(struct ringbuf_t));
if (rb) {
/* One byte is used for detecting the full condition. */
rb->size = capacity + 1;
rb->buf = (uint8_t *) os_malloc(rb->size);
if (rb->buf)
ringbuf_reset(rb);
else {
os_free(rb);
return 0;
}
}
return rb;
}
/**
* \brief put a character into ring buffer
* \param r pointer to a ringbuf object
* \param c character to be put
* \return 0 if successfull, otherwise failed
*/
I16 RINGBUF_Put(RINGBUF *r, U8 c)
{
if(r->fill_cnt>=r->size)return -1; // ring buffer is full, this should be atomic operation
r->fill_cnt++; // increase filled slots count, this should be atomic operation
*r->p_w++ = c; // put character into buffer
if(r->p_w >= r->p_o + r->size) // rollback if write pointer go pass
r->p_w = r->p_o; // the physical boundary
return 0;
size_t ringbuf_buffer_size(const struct ringbuf_t * rb) {
return rb->size;
}
/**
* \brief get a character from ring buffer
* \param r pointer to a ringbuf object
* \param c read character
* \return 0 if successfull, otherwise failed
*/
I16 RINGBUF_Get(RINGBUF *r, U8* c)
{
if(r->fill_cnt<=0)return -1; // ring buffer is empty, this should be atomic operation
r->fill_cnt--; // decrease filled slots count
*c = *r->p_r++; // get the character out
if(r->p_r >= r->p_o + r->size) // rollback if write pointer go pass
r->p_r = r->p_o; // the physical boundary
return 0;
void ringbuf_reset(ringbuf_t rb) {
rb->head = rb->tail = rb->buf;
}
void ringbuf_free(ringbuf_t * rb) {
assert(rb && *rb);
os_free((*rb)->buf);
os_free(*rb);
*rb = 0;
}
size_t ringbuf_capacity(const struct ringbuf_t *rb) {
return ringbuf_buffer_size(rb) - 1;
}
/*
* Return a pointer to one-past-the-end of the ring buffer's
* contiguous buffer. You shouldn't normally need to use this function
* unless you're writing a new ringbuf_* function.
*/
static const uint8_t *ringbuf_end(const struct ringbuf_t *rb) {
return rb->buf + ringbuf_buffer_size(rb);
}
size_t ringbuf_bytes_free(const struct ringbuf_t * rb) {
if (rb->head >= rb->tail)
return ringbuf_capacity(rb) - (rb->head - rb->tail);
else
return rb->tail - rb->head - 1;
}
size_t ringbuf_bytes_used(const struct ringbuf_t * rb) {
return ringbuf_capacity(rb) - ringbuf_bytes_free(rb);
}
int ringbuf_is_full(const struct ringbuf_t *rb) {
return ringbuf_bytes_free(rb) == 0;
}
int ringbuf_is_empty(const struct ringbuf_t *rb) {
return ringbuf_bytes_free(rb) == ringbuf_capacity(rb);
}
const void *ringbuf_tail(const struct ringbuf_t *rb) {
return rb->tail;
}
const void *ringbuf_head(const struct ringbuf_t *rb) {
return rb->head;
}
/*
* Given a ring buffer rb and a pointer to a location within its
* contiguous buffer, return the a pointer to the next logical
* location in the ring buffer.
*/
static uint8_t *ringbuf_nextp(ringbuf_t rb, const uint8_t * p) {
/*
* The assert guarantees the expression (++p - rb->buf) is
* non-negative; therefore, the modulus operation is safe and
* portable.
*/
assert((p >= rb->buf) && (p < ringbuf_end(rb)));
return rb->buf + ((++p - rb->buf) % ringbuf_buffer_size(rb));
}
void *ringbuf_memcpy_into(ringbuf_t dst, const void *src, size_t count) {
const uint8_t *u8src = src;
const uint8_t *bufend = ringbuf_end(dst);
int overflow = count > ringbuf_bytes_free(dst);
size_t nread = 0;
while (nread != count) {
/* don't copy beyond the end of the buffer */
assert(bufend > dst->head);
size_t n = MIN(bufend - dst->head, count - nread);
os_memcpy(dst->head, u8src + nread, n);
dst->head += n;
nread += n;
/* wrap? */
if (dst->head == bufend)
dst->head = dst->buf;
}
if (overflow) {
dst->tail = ringbuf_nextp(dst, dst->head);
assert(ringbuf_is_full(dst));
}
return dst->head;
}
void *ringbuf_memcpy_from(void *dst, ringbuf_t src, size_t count) {
size_t bytes_used = ringbuf_bytes_used(src);
if (count > bytes_used)
return 0;
uint8_t *u8dst = dst;
const uint8_t *bufend = ringbuf_end(src);
size_t nwritten = 0;
while (nwritten != count) {
assert(bufend > src->tail);
size_t n = MIN(bufend - src->tail, count - nwritten);
os_memcpy(u8dst + nwritten, src->tail, n);
src->tail += n;
nwritten += n;
/* wrap ? */
if (src->tail == bufend)
src->tail = src->buf;
}
assert(count + ringbuf_bytes_used(src) == bytes_used);
return src->tail;
}
void *ringbuf_copy(ringbuf_t dst, ringbuf_t src, size_t count) {
size_t src_bytes_used = ringbuf_bytes_used(src);
if (count > src_bytes_used)
return 0;
int overflow = count > ringbuf_bytes_free(dst);
const uint8_t *src_bufend = ringbuf_end(src);
const uint8_t *dst_bufend = ringbuf_end(dst);
size_t ncopied = 0;
while (ncopied != count) {
assert(src_bufend > src->tail);
size_t nsrc = MIN(src_bufend - src->tail, count - ncopied);
assert(dst_bufend > dst->head);
size_t n = MIN(dst_bufend - dst->head, nsrc);
os_memcpy(dst->head, src->tail, n);
src->tail += n;
dst->head += n;
ncopied += n;
/* wrap ? */
if (src->tail == src_bufend)
src->tail = src->buf;
if (dst->head == dst_bufend)
dst->head = dst->buf;
}
assert(count + ringbuf_bytes_used(src) == src_bytes_used);
if (overflow) {
dst->tail = ringbuf_nextp(dst, dst->head);
assert(ringbuf_is_full(dst));
}
return dst->head;
}

Wyświetl plik

@ -1,19 +0,0 @@
#ifndef _RING_BUF_H_
#define _RING_BUF_H_
#include <os_type.h>
#include <stdlib.h>
#include "typedef.h"
typedef struct{
U8* p_o; /**< Original pointer */
U8* volatile p_r; /**< Read pointer */
U8* volatile p_w; /**< Write pointer */
volatile I32 fill_cnt; /**< Number of filled slots */
I32 size; /**< Buffer size */
}RINGBUF;
I16 RINGBUF_Init(RINGBUF *r, U8* buf, I32 size);
I16 RINGBUF_Put(RINGBUF *r, U8 c);
I16 RINGBUF_Get(RINGBUF *r, U8* c);
#endif

30
user/sys_time.c 100644
Wyświetl plik

@ -0,0 +1,30 @@
#include "c_types.h"
#include "osapi.h"
typedef union _timer {
uint32_t time_s[2];
uint64_t time_l;
} long_time_t;
static long_time_t time;
static uint32_t old;
uint64_t ICACHE_FLASH_ATTR get_long_systime() {
uint32_t now = system_get_time();
if (now < old) {
time.time_s[1]++;
}
old = now;
time.time_s[0] = now;
return time.time_l;
}
uint64_t ICACHE_FLASH_ATTR get_low_systime() {
get_long_systime();
return time.time_s[0];
}
void init_long_systime() {
old = system_get_time();
time.time_l = (uint64_t) old;
}

15
user/sys_time.h 100644
Wyświetl plik

@ -0,0 +1,15 @@
#ifndef _SYS_TIME_
#define _SYS_TIME_
#include "c_types.h"
// returns time until boot in us
uint64_t ICACHE_FLASH_ATTR get_long_systime();
// returns lower half of time until boot in us
uint64_t ICACHE_FLASH_ATTR get_low_systime();
// initializes the timer
void init_long_systime();
#endif /* _SYS_TIME_ */

Wyświetl plik

@ -1,17 +0,0 @@
/**
* \file
* Standard Types definition
*/
#ifndef _TYPE_DEF_H_
#define _TYPE_DEF_H_
typedef char I8;
typedef unsigned char U8;
typedef short I16;
typedef unsigned short U16;
typedef long I32;
typedef unsigned long U32;
typedef unsigned long long U64;
#endif

135
user/user_config.h 100644
Wyświetl plik

@ -0,0 +1,135 @@
#ifndef _USER_CONFIG_
#define _USER_CONFIG_
#define ESP_UBROKER_VERSION "V2.0.10"
#define WIFI_SSID "ssid"
#define WIFI_PASSWORD "password"
#define WIFI_AP_SSID "MyAP"
#define WIFI_AP_PASSWORD "none"
#define WIFI_AP_CHANNEL 1
#define MAX_CLIENTS 8
//
// Here the MQTT stuff
//
//
// Define this if you want to have it work as a MQTT client
// Define MQTT_SSL_ENABLE if you need SSL for the *MQTT client*
//
#define MQTT_CLIENT 1
#define MQTT_SSL_ENABLE 1
//
// Change this to adjust memory consuption of one MQTT connection
// MQTT_BUF_SIZE is the max. size of pending inbound messages for one connection
// QUEUE_BUFFER_SIZE is the max. size of all pending outbound messages for one connection
//
#define MQTT_BUF_SIZE 2048
#define QUEUE_BUFFER_SIZE 2048
#define MQTT_KEEPALIVE 120 /*seconds*/
#define MQTT_RECONNECT_TIMEOUT 5 /*seconds*/
//#define PROTOCOL_NAMEv31 /*MQTT version 3.1 compatible with Mosquitto v0.15*/
#define PROTOCOL_NAMEv311 /*MQTT version 3.11 compatible with https://eclipse.org/paho/clients/testing/*/
#define MQTT_ID "ESPBroker"
//
// Define this if you want to have script support.
//
#define SCRIPTED 1
// Some params for scripts
#define MAX_SCRIPT_SIZE 0x1000
#define MAX_TIMERS 4
#define MAX_GPIOS 3
#define PWM_MAX_CHANNELS 8
#define MAX_VARS 10
#define DEFAULT_VAR_LEN 16
#define MAX_TIMESTAMPS 6
#define MAX_FLASH_SLOTS 8
#define FLASH_SLOT_LEN 64
//
// Define this if you want to have GPIO OUT support in scripts.
// Define GPIO_PWM if you want to have additionally GPIO PWM support in scripts.
//
#define GPIO 1
#define GPIO_PWM 1
//
// Define this if you want to have ADC support.
//
#define ADC 1
//
// Define this if you want to have HTTP client support in scripts.
// Define HTTPCS if you want to have additional HTTPS support.
//
#define HTTPC 1
#define HTTPCS 1
//
// Define this if you want to have JSON parse support in scripts.
//
#define JSON_PARSE 1
//
// Define this if you want to have NTP support.
//
#define NTP 1
//
// Define this if you want to have mDNS support.
//
#define MDNS 1
//
// Define this if you want to have access the DNS responder.
// Experimental feature - not yet tested
//
#define DNS_RESP 1
//
// Define this to support the "scan" command for AP search
//
#define ALLOW_SCANNING 1
//
// Define this if you want to have access to the config console via TCP.
// Otherwise only local access via serial is possible
//
#define REMOTE_CONFIG 1
#define CONSOLE_SERVER_PORT 7777
//
// Define this to support console backlog
//
#define BACKLOG 1
//
// Size of the console buffers
//
#define MAX_CON_SEND_SIZE 1024
#define MAX_CON_CMD_SIZE 160
//
// Flash save slots (currently max. 0-2)
//
#define SCRIPT_SLOT 0
#define VARS_SLOT 1
#define RETAINED_SLOT 2
#define MAX_RETAINED_LEN 0x1000
typedef enum {SIG_DO_NOTHING=0, SIG_START_SERVER=1, SIG_UART0, SIG_TOPIC_RECEIVED, SIG_SCRIPT_LOADED, SIG_SCRIPT_HTTP_LOADED, SIG_CONSOLE_TX_RAW, SIG_CONSOLE_TX, SIG_CONSOLE_RX} USER_SIGNALS;
#define LOCAL_ACCESS 0x01
#define REMOTE_ACCESS 0x02
#endif /* _USER_CONFIG_ */

Plik diff jest za duży Load Diff

Wyświetl plik

@ -1,149 +0,0 @@
/*
* Copyright (c) 2014, Tuan PM
* Email: tuanpm@live.com
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <stddef.h>
#include "utils.h"
uint8_t UTILS_IsIPV4 (int8_t *str)
{
uint8_t segs = 0; /* Segment count. */
uint8_t chcnt = 0; /* Character count within segment. */
uint8_t accum = 0; /* Accumulator for segment. */
/* Catch NULL pointer. */
if (str == 0)
return 0;
/* Process every character in string. */
while (*str != '\0') {
/* Segment changeover. */
if (*str == '.') {
/* Must have some digits in segment. */
if (chcnt == 0)
return 0;
/* Limit number of segments. */
if (++segs == 4)
return 0;
/* Reset segment values and restart loop. */
chcnt = accum = 0;
str++;
continue;
}
/* Check numeric. */
if ((*str < '0') || (*str > '9'))
return 0;
/* Accumulate and check segment. */
if ((accum = accum * 10 + *str - '0') > 255)
return 0;
/* Advance other segment specific stuff and continue loop. */
chcnt++;
str++;
}
/* Check enough segments and enough characters in last segment. */
if (segs != 3)
return 0;
if (chcnt == 0)
return 0;
/* Address okay. */
return 1;
}
uint8_t UTILS_StrToIP(const int8_t* str, void *ip)
{
/* The count of the number of bytes processed. */
int i;
/* A pointer to the next digit to process. */
const char * start;
start = str;
for (i = 0; i < 4; i++) {
/* The digit being processed. */
char c;
/* The value of this byte. */
int n = 0;
while (1) {
c = * start;
start++;
if (c >= '0' && c <= '9') {
n *= 10;
n += c - '0';
}
/* We insist on stopping at "." if we are still parsing
the first, second, or third numbers. If we have reached
the end of the numbers, we will allow any character. */
else if ((i < 3 && c == '.') || i == 3) {
break;
}
else {
return 0;
}
}
if (n >= 256) {
return 0;
}
((uint8_t*)ip)[i] = n;
}
return 1;
}
uint32_t UTILS_Atoh(const int8_t *s)
{
uint32_t value = 0, digit;
int8_t c;
while((c = *s++)){
if('0' <= c && c <= '9')
digit = c - '0';
else if('A' <= c && c <= 'F')
digit = c - 'A' + 10;
else if('a' <= c && c<= 'f')
digit = c - 'a' + 10;
else break;
value = (value << 4) | digit;
}
return value;
}

Wyświetl plik

@ -1,10 +0,0 @@
#ifndef _UTILS_H_
#define _UTILS_H_
#include "c_types.h"
uint32_t UTILS_Atoh(const int8_t *s);
uint8_t UTILS_StrToIP(const int8_t* str, void *ip);
uint8_t UTILS_IsIPV4 (int8_t *str);
char *ULTILS_StrReplace(char *orig, char *rep, char *with);
#endif

Wyświetl plik

@ -1,100 +0,0 @@
/*
* wifi.c
*
* Created on: Dec 30, 2014
* Author: Minh
*/
#include "wifi.h"
#include "user_interface.h"
#include "osapi.h"
#include "espconn.h"
#include "os_type.h"
#include "mem.h"
#include "mqtt_msg.h"
#include "debug.h"
#include "user_config.h"
#include "config.h"
#include "driver/uart.h"
static ETSTimer WiFiLinker;
WifiCallback wifiCb = NULL;
static uint8_t wifiStatus = STATION_IDLE, lastWifiStatus = STATION_IDLE;
static void ICACHE_FLASH_ATTR wifi_check_ip(void *arg)
{
struct ip_info ipConfig;
os_timer_disarm(&WiFiLinker);
wifi_get_ip_info(STATION_IF, &ipConfig);
wifiStatus = wifi_station_get_connect_status();
if (wifiStatus == STATION_GOT_IP && ipConfig.ip.addr != 0)
{
os_timer_setfn(&WiFiLinker, (os_timer_func_t *)wifi_check_ip, NULL);
os_timer_arm(&WiFiLinker, 2000, 0);
}
else
{
if(wifi_station_get_connect_status() == STATION_WRONG_PASSWORD)
{
INFO("STATION_WRONG_PASSWORD\r\n");
wifi_station_connect();
}
else if(wifi_station_get_connect_status() == STATION_NO_AP_FOUND)
{
INFO("STATION_NO_AP_FOUND\r\n");
wifi_station_connect();
}
else if(wifi_station_get_connect_status() == STATION_CONNECT_FAIL)
{
INFO("STATION_CONNECT_FAIL\r\n");
wifi_station_connect();
}
else
{
INFO("STATION_IDLE\r\n");
}
os_timer_setfn(&WiFiLinker, (os_timer_func_t *)wifi_check_ip, NULL);
os_timer_arm(&WiFiLinker, 500, 0);
}
if(wifiStatus != lastWifiStatus){
lastWifiStatus = wifiStatus;
if(wifiCb)
wifiCb(wifiStatus);
}
}
void WIFI_Connect(uint8_t* ssid, uint8_t* pass, WifiCallback cb)
{
struct station_config stationConf;
INFO("WIFI_INIT\r\n");
wifi_set_opmode(STATION_MODE);
wifi_station_set_auto_connect(FALSE);
wifiCb = cb;
os_memset(&stationConf, 0, sizeof(struct station_config));
os_sprintf(stationConf.ssid, "%s", ssid);
os_sprintf(stationConf.password, "%s", pass);
wifi_station_set_config(&stationConf);
os_timer_disarm(&WiFiLinker);
os_timer_setfn(&WiFiLinker, (os_timer_func_t *)wifi_check_ip, NULL);
os_timer_arm(&WiFiLinker, 1000, 0);
wifi_station_set_auto_connect(TRUE);
wifi_station_connect();
}

Wyświetl plik

@ -1,15 +0,0 @@
/*
* wifi.h
*
* Created on: Dec 30, 2014
* Author: Minh
*/
#ifndef USER_WIFI_H_
#define USER_WIFI_H_
#include "os_type.h"
typedef void (*WifiCallback)(uint8_t);
void WIFI_Connect(uint8_t* ssid, uint8_t* pass, WifiCallback cb);
#endif /* USER_WIFI_H_ */

Wyświetl plik

@ -0,0 +1,25 @@
#ifndef __MQTT_CONFIG_H__
#define __MQTT_CONFIG_H__
/*DEFAULT CONFIGURATIONS*/
#define MQTT_PORT 1883
#define MQTT_BUF_SIZE 1024
#define MQTT_KEEPALIVE 120 /*second*/
#define MQTT_RECONNECT_TIMEOUT 5 /*seconds*/
#define MQTT_MAX_SUBSCRIPTIONS 30
#define MQTT_MAX_RETAINED_TOPICS 30
#define TCP_MAX_CONNECTIONS 10
#define STA_SSID "SSID"
#define STA_PASS "PASSWD"
#define PROTOCOL_NAMEv31 /*MQTT version 3.1 compatible with Mosquitto v0.15*/
//PROTOCOL_NAMEv311 /*MQTT version 3.11 compatible with https://eclipse.org/paho/clients/testing/*/
typedef enum {SIG_DO_NOTHING=0, SIG_UART0, SIG_CONSOLE_RX, SIG_CONSOLE_TX} USER_SIGNALS;
#endif // __MQTT_CONFIG_H__

Wyświetl plik

@ -0,0 +1,27 @@
#include "user_interface.h"
#include "mqtt/mqtt_server.h"
#include "user_config.h"
void ICACHE_FLASH_ATTR user_init() {
struct station_config stationConf;
// Initialize the UART
uart_div_modify(0, UART_CLK_FREQ / 115200);
os_printf("\r\n\r\nMQTT Broker starting\r\n");
// Setup STA
wifi_set_opmode(STATIONAP_MODE);
stationConf.bssid_set = 0;
os_strcpy(&stationConf.ssid, STA_SSID);
os_strcpy(&stationConf.password, STA_PASS);
wifi_station_set_config(&stationConf);
wifi_station_set_auto_connect(1);
// Allow larger number of TCP (=MQTT) clients
espconn_tcp_set_max_con(TCP_MAX_CONNECTIONS);
os_printf("Max number of TCP clients: %d\r\n", espconn_tcp_get_max_con());
//Start MQTT broker
MQTT_server_start(MQTT_PORT, MQTT_MAX_SUBSCRIPTIONS, MQTT_MAX_RETAINED_TOPICS);
}