diff --git a/.gitignore b/.gitignore index d88f1f2daf..3c8c0fe5c3 100644 --- a/.gitignore +++ b/.gitignore @@ -72,4 +72,3 @@ nbproject build/macosx/esptool-*-osx.zip build/macosx/dist/osx-xtensa-lx106-elf.tgz -/hardware/esp8266com/esp8266/tools diff --git a/README.md b/README.md index 373b645a4d..02b9eaee11 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Arduino-compatible IDE with ESP8266 support =========================================== -![Linux build status](http://img.shields.io/travis/igrr/Arduino.svg) +[![Linux build status](http://img.shields.io/travis/igrr/Arduino.svg)](https://travis-ci.org/igrr/Arduino) [![Donate](http://img.shields.io/paypal/donate.png?color=yellow)](https://www.paypal.com/webscr?cmd=_s-xclick&hosted_button_id=4M56YCWV6PX66) This project brings support for ESP8266 chip to the Arduino environment. ESP8266WiFi library bundled with this project has the same interface as the WiFi Shield library, making it easy to re-use existing code and libraries. @@ -102,9 +102,9 @@ This is mostly similar to WiFi shield library. Differences include: - ```WiFi.RSSI()``` doesn't work - ```WiFi.printDiag(Serial);``` will print out some diagnostic info - ```WiFiUDP``` class supports sending and receiving multicast packets on STA interface. -When sending a multicast packet, replace ```udp.beginPacket(addr, port)``` with +When sending a multicast packet, replace ```udp.beginPacket(addr, port)``` with ```udp.beginPacketMulticast(addr, port, WiFi.localIP())```. -When listening to multicast packets, replace ```udp.begin(port)``` with +When listening to multicast packets, replace ```udp.begin(port)``` with ```udp.beginMulticast(WiFi.localIP(), multicast_ip_addr, port)```. You can use ```udp.destinationIP()``` to tell whether the packet received was sent to the multicast or unicast address. @@ -117,7 +117,7 @@ Four samples are provided for this library. Library for calling functions repeatedly with a certain period. Two examples included. -It is currently not recommended to do blocking IO operations (network, serial, file) from Ticker +It is currently not recommended to do blocking IO operations (network, serial, file) from Ticker callback functions. Instead, set a flag inside the ticker callback and check for that flag inside the loop function. #### EEPROM #### @@ -183,28 +183,62 @@ Allows the sketch to respond to multicast DNS queries for domain names like "foo Currently the library only works on STA interface, AP interface is not supported. See attached example and library README file for details. +#### DNS server (DNSServer library) #### + +Implements a simple DNS server that can be used in both STA and AP modes. The DNS server currently supports only one domain (for all other domains it will reply with NXDOMAIN or custom status code). With it clients can open a web server running on ESP8266 using a domain name, not an IP address. +See attached example for details. + +#### Servo #### + +This library exposes the ability to control RC (hobby) servo motors. It will support upto 24 servos on any available output pin. By defualt the first 12 servos will use Timer0 and currently this will not interfere with any other support. Servo counts above 12 will use Timer1 and features that use it will be effected. +While many RC servo motors will accept the 3.3v IO data pin from a esp8266, most will not be able to run off 3.3v and will require another power source that matches their specifications. Make sure to connect the grounds between the esp8266 and the servo motor power supply. + #### Other libraries (not included with the IDE) Libraries that don't rely on low-level access to AVR registers should work well. Here are a few libraries that were verified to work: +- [arduinoWebSockets](https://github.com/Links2004/arduinoWebSockets) - WebSocket Server and Client compatible with esp8266 (RFC6455) - [aREST](https://github.com/marcoschwartz/aREST) REST API handler library. -- [PubSubClient](https://github.com/Imroy/pubsubclient) MQTT library by @Imroy. -- [DHT11](https://github.com/adafruit/DHT-sensor-library) - initialize DHT as follows: ```DHT dht(DHTPIN, DHTTYPE, 15);``` +- [Blynk](https://github.com/blynkkk/blynk-library) - easy IoT framework for Makers (check out the [Kickstarter page](http://tiny.cc/blynk-kick)). - [DallasTemperature](https://github.com/milesburton/Arduino-Temperature-Control-Library.git) +- [DHT11](https://github.com/adafruit/DHT-sensor-library) - initialize DHT as follows: ```DHT dht(DHTPIN, DHTTYPE, 15);``` - [NeoPixelBus](https://github.com/Makuna/NeoPixelBus) - Arduino NeoPixel library compatible with esp8266. +- [PubSubClient](https://github.com/Imroy/pubsubclient) MQTT library by @Imroy. - [RTC](https://github.com/Makuna/Rtc) - Arduino Library for Ds1307 & Ds3231 compatible with esp8266. -- [Blynk](https://github.com/blynkkk/blynk-library) - easy IoT framework for Makers (check out the [Kickstarter page](http://tiny.cc/blynk-kick)). +- [Souliss, Smart Home](https://github.com/souliss/souliss) - Framework for Smart Home based on Arduino, Android and openHAB. #### Upload via serial port #### Pick the correct serial port. You need to put ESP8266 into bootloader mode before uploading code. +#### Power Supply #### + +For stable use of the ESP8266 a power supply with 3V3 and >= 250mA is required. + +* Note + - using Power from USB to Serial is may unstable, they not deliver enough current. + +#### Serial Adapter #### + +There are many different USB to Serial adapters / boards. + +* Note + - for full upload management you need RTS and DTR + - the chip need to have 3V3 TTL (5V may damage the chip) + - not all board have all pins of the ICs as breakout (check before order) + - CTS and DSR are not useful for upload (they are Inputs) + +* Working ICs + - FT232RL + - CP2102 + - may others (drop a comment) + #### Minimal hardware Setup for Bootloading and usage #### ESPxx Hardware | PIN | Resistor | Serial Adapter | -| ------------- | -------- | -------------- | +| ------------- | -------- | -------------- | | VCC | | VCC (3.3V) | | GND | | GND | | TX or GPIO2* | | RX | @@ -214,32 +248,49 @@ ESPxx Hardware | GPIO15* | PullDown | | | CH_PD | PullUp | | -* Note +* Note - GPIO15 is also named MTDO - Reset is also named RSBT or REST (adding PullUp improves the stability of the Module) - GPIO2 is alternative TX for the boot loader mode - -ESP01 example: -![ESP01 connect](https://raw.githubusercontent.com/Links2004/Arduino/esp8266/docs/ESP01_connect.jpg) +###### esp to Serial +![ESP to Serial](https://raw.githubusercontent.com/Links2004/Arduino/esp8266/docs/ESP_to_serial.png) #### Minimal hardware Setup for Bootloading only #### ESPxx Hardware -| PIN | Resistor | Serial Adapter | -| ------------- | -------- | -------------- | -| VCC | | VCC (3.3V) | -| GND | | GND | -| TX or GPIO2 | | RX | -| RX | | TX | -| GPIO0 | | GND | +| PIN | Resistor | Serial Adapter | +| ------------- | -------- | --------------- | +| VCC | | VCC (3.3V) | +| GND | | GND | +| TX or GPIO2 | | RX | +| RX | | TX | +| GPIO0 | | GND | | Reset | | RTS* | -| GPIO15 | PullDown | | -| CH_PD | PullUp | | +| GPIO15 | PullDown | | +| CH_PD | PullUp | | -* Note +* Note - if no RTS is used a manual power toggle is needed +#### Minimal hardware Setup for running only #### + +ESPxx Hardware + +| PIN | Resistor | Power supply | +| ------------- | -------- | --------------- | +| VCC | | VCC (3.3V) | +| GND | | GND | +| GPIO0 | PullUp | | +| GPIO15 | PullDown | | +| CH_PD | PullUp | | + +###### minimal +![ESP min](https://raw.githubusercontent.com/Links2004/Arduino/esp8266/docs/ESP_min.png) + +###### improved stability +![ESP improved stability](https://raw.githubusercontent.com/Links2004/Arduino/esp8266/docs/ESP_improved_stability.png) + ### Issues and support ### Forum: http://www.esp8266.com/arduino @@ -259,5 +310,3 @@ Esptool written by Christian Klippel is licensed under GPLv2, currently maintain ESP8266 core support, ESP8266WiFi, Ticker, ESP8266WebServer libraries were written by Ivan Grokhotkov, ivan@esp8266.com. [SPI Flash File System (SPIFFS)](https://github.com/pellepl/spiffs) written by Peter Andersson is used in this project. It is distributed under MIT license. - - diff --git a/build/build.xml b/build/build.xml index 20bac52d48..b0d39a9669 100644 --- a/build/build.xml +++ b/build/build.xml @@ -398,13 +398,13 @@ - - - + + + - - + + @@ -673,13 +673,13 @@ - - - + + + - - + + @@ -891,7 +891,7 @@ - + @@ -928,13 +928,13 @@ - - - + + + - - + + diff --git a/build/build_board_manager_package.sh b/build/build_board_manager_package.sh index dbccd99996..4b02fc90b4 100755 --- a/build/build_board_manager_package.sh +++ b/build/build_board_manager_package.sh @@ -1,4 +1,8 @@ #!/bin/bash +# +# for platform in windows linux macosx; do pushd $platform; ls -l esptool-*; shasum -a 256 esptool-*; popd; done; +# +# ver=`git describe --tags` outdir=esp8266-$ver @@ -23,9 +27,14 @@ size=`/bin/ls -l $outdir.zip | awk '{print $5}'` echo Size: $size echo SHA-256: $sha -if [ ! -z "$do_upload" ]; then +if [ "$upload" == "prod" ]; then remote="http://arduino.esp8266.com/" + path="" +elif [ "$upload" == "stag" ]; then + remote="http://arduino.esp8266.com/" + path="staging/" else + upload="" remote="http://localhost:8000/" fi @@ -45,21 +54,34 @@ cat << EOF > package_esp8266com_index.json "architecture":"esp8266", "version":"$ver", "category":"ESP8266", - "url":"$remote/$outdir.zip", + "url":"$remote/$path/$outdir.zip", "archiveFileName":"$outdir.zip", "checksum":"SHA-256:$sha", "size":"$size", "help":{ "online":"http://esp8266.com/" }, - "boards":[ { + "boards":[ + { "name":"Generic ESP8266 Module" + }, + { + "name":"Olimex MOD-WIFI-ESP8266(-DEV)" + }, + { + "name":"NodeMCU 0.9 (ESP-12 Module)" + }, + { + "name":"NodeMCU 1.0 (ESP-12E Module)" + }, + { + "name":"Adafruit HUZZAH ESP8266 (ESP-12)" } ], "toolsDependencies":[ { "packager":"esp8266", "name":"esptool", - "version":"0.4.4" + "version":"0.4.5" }, { "packager":"esp8266", @@ -70,33 +92,33 @@ cat << EOF > package_esp8266com_index.json "tools": [ { "name":"esptool", - "version":"0.4.4", + "version":"0.4.5", "systems": [ { "host":"i686-mingw32", - "url":"https://github.com/igrr/esptool-ck/releases/download/0.4.4/esptool-0.4.4-win32.zip", - "archiveFileName":"esptool-0.4.4-win32.zip", - "checksum":"SHA-256:bc52165c847b194d8f079add982eae1c4b4466784bff8c8494241de602a003b3", - "size":"17262" + "url":"https://github.com/igrr/esptool-ck/releases/download/0.4.5/esptool-0.4.5-win32.zip", + "archiveFileName":"esptool-0.4.5-win32.zip", + "checksum":"SHA-256:1b0a7d254e74942d820a09281aa5dc2af1c8314ae5ee1a5abb0653d0580e531b", + "size":"17408" }, { "host":"x86_64-apple-darwin", - "url":"http://arduino.esp8266.com/esptool-0.4.4-5-g744c44d-osx.tar.gz", - "archiveFileName":"esptool-0.4.4-5-g744c44d-osx.tar.gz", - "checksum":"SHA-256:d8bc920e046fcc668b31cda63ac5553b4c07a6db12bfd0abc9005fc94628afcb", - "size":"12133" + "url":"https://github.com/igrr/esptool-ck/releases/download/0.4.5/esptool-0.4.5-osx.tar.gz", + "archiveFileName":"esptool-0.4.5-osx.tar.gz", + "checksum":"SHA-256:924d31c64f4bb9f748e70806dafbabb15e5eb80afcdde33715f3ec884be1652d", + "size":"11359" }, { "host":"x86_64-pc-linux-gnu", - "url":"https://github.com/igrr/esptool-ck/releases/download/0.4.4/esptool-0.4.4-linux64.tar.gz", - "archiveFileName":"esptool-0.4.4-linux64.tar.gz", - "checksum":"SHA-256:beedf89db0bdce0bf6034232d86edebcfed0966ff1501545aca9cfbba1f92593", - "size":"12513" + "url":"https://github.com/igrr/esptool-ck/releases/download/0.4.5/esptool-0.4.5-linux64.tar.gz", + "archiveFileName":"esptool-0.4.5-linux64.tar.gz", + "checksum":"SHA-256:4ce799e13fbd89f8a8f08a08db77dc3b1362c4486306fe1b3801dee80cfa3203", + "size":"12789" }, { "host":"i686-pc-linux-gnu", - "url":"https://github.com/igrr/esptool-ck/releases/download/0.4.4/esptool-0.4.4-linux32.tar.gz", - "archiveFileName":"esptool-0.4.4-linux32.tar.gz", + "url":"https://github.com/igrr/esptool-ck/releases/download/0.4.5/esptool-0.4.5-linux32.tar.gz", + "archiveFileName":"esptool-0.4.5-linux32.tar.gz", "checksum":"SHA-256:4aa81b97a470641771cf371e5d470ac92d3b177adbe8263c4aae66e607b67755", "size":"12044" } @@ -140,9 +162,9 @@ cat << EOF > package_esp8266com_index.json } EOF -if [ ! -z "$do_upload" ]; then - scp $outdir.zip dl:apps/download_files/download/ - scp package_esp8266com_index.json dl:apps/download_files/download +if [ ! -z "$upload" ]; then + scp $outdir.zip dl:apps/download_files/download/$path + scp package_esp8266com_index.json dl:apps/download_files/download/$path else python -m SimpleHTTPServer fi diff --git a/build/linux/esptool-0.4.4-linux64.tar.gz.sha b/build/linux/esptool-0.4.4-linux64.tar.gz.sha deleted file mode 100644 index 18f5fabdd9..0000000000 --- a/build/linux/esptool-0.4.4-linux64.tar.gz.sha +++ /dev/null @@ -1 +0,0 @@ -65e4b3c4a26e7960536f8f2a19c5d65a13fe8025 diff --git a/build/linux/esptool-0.4.5-linux64.tar.gz.sha b/build/linux/esptool-0.4.5-linux64.tar.gz.sha new file mode 100644 index 0000000000..d380907b57 --- /dev/null +++ b/build/linux/esptool-0.4.5-linux64.tar.gz.sha @@ -0,0 +1 @@ +ef9940f7b690f346739b54e4df46d0fbd37f0e12 diff --git a/build/macosx/esptool-0.4.4-osx.tar.gz.sha b/build/macosx/esptool-0.4.4-osx.tar.gz.sha deleted file mode 100644 index 0cf3a3d4a3..0000000000 --- a/build/macosx/esptool-0.4.4-osx.tar.gz.sha +++ /dev/null @@ -1 +0,0 @@ -26c53e32887b0c41dab861df93a60d1688e7762b diff --git a/build/macosx/esptool-0.4.5-osx.tar.gz.sha b/build/macosx/esptool-0.4.5-osx.tar.gz.sha new file mode 100644 index 0000000000..534ff18d54 --- /dev/null +++ b/build/macosx/esptool-0.4.5-osx.tar.gz.sha @@ -0,0 +1 @@ +702be33406745b31904a40b28cf6ebb87173e4c8 diff --git a/build/windows/esptool-0.4.4-win32.zip.sha b/build/windows/esptool-0.4.4-win32.zip.sha deleted file mode 100644 index 9fea4d2e5f..0000000000 --- a/build/windows/esptool-0.4.4-win32.zip.sha +++ /dev/null @@ -1 +0,0 @@ -2d1beb3fb3af8b16bca15b7cd6f61aec10cc52cb diff --git a/build/windows/esptool-0.4.5-win32.zip.sha b/build/windows/esptool-0.4.5-win32.zip.sha new file mode 100644 index 0000000000..e37cc5b2ac --- /dev/null +++ b/build/windows/esptool-0.4.5-win32.zip.sha @@ -0,0 +1 @@ +7c6b0049e016889a85dc0c7e01282ef0ce36d1f3 diff --git a/docs/ESP_improved_stability.png b/docs/ESP_improved_stability.png new file mode 100644 index 0000000000..74a7e01eeb Binary files /dev/null and b/docs/ESP_improved_stability.png differ diff --git a/docs/ESP_min.png b/docs/ESP_min.png new file mode 100644 index 0000000000..59dc10c15a Binary files /dev/null and b/docs/ESP_min.png differ diff --git a/docs/ESP_to_serial.png b/docs/ESP_to_serial.png new file mode 100644 index 0000000000..9dd116be74 Binary files /dev/null and b/docs/ESP_to_serial.png differ diff --git a/docs/rgisters_dump.txt b/docs/rgisters_dump.txt index 957a9e1305..841d3c1552 100644 --- a/docs/rgisters_dump.txt +++ b/docs/rgisters_dump.txt @@ -5,14 +5,14 @@ 0x3FF00000 | 00000000000000000000000000000000 | 0x00000000 | 0 | | 0x3FF00004 | 00000000000000000000000000000101 | 0x00000005 | 5 | | TEIE 0x3FF00008 | 00000000000000000000100000001111 | 0x0000080F | 2063 | . | -0x3FF0000C | 00000100000000000000000100000010 | 0x04000102 | 67109122 | | +0x3FF0000C | 00000100000000000000000100000010 | 0x04000102 | 67109122 | | SPIRDY 0x3FF00010 | 00000000000000000000000000000000 | 0x00000000 | 0 | | -0x3FF00014 | 00000000000000000000000000000000 | 0x00000000 | 0 | | +0x3FF00014 | 00000000000000000000000000000000 | 0x00000000 | 0 | | CPU2X 0x3FF00018 | 11111111111111110000000011111111 | 0xFFFF00FF | 4294902015 | .. . | 0x3FF0001C | 00000000000000000000000000000000 | 0x00000000 | 0 | | 0x3FF00020 | 00000000000000000000000000010000 | 0x00000010 | 16 | . | SPIIR 0x3FF00024 | 00000000000000000000000000011010 | 0x0000001A | 26 | . | -0x3FF00028 | 00000000000000000000000000000000 | 0x00000000 | 0 | | USWAP +0x3FF00028 | 00000000000000000000000000000000 | 0x00000000 | 0 | | IOSWAP 0x3FF0002C | 00000000000000000000000000000000 | 0x00000000 | 0 | | 0x3FF00030 | 00000000000000000100000001000000 | 0x00004040 | 16448 | @@ | 0x3FF00034 | 00000000000000000000000000000000 | 0x00000000 | 0 | | @@ -22,9 +22,9 @@ 0x3FF00044 | 00000000000000000000000000000000 | 0x00000000 | 0 | | 0x3FF00048 | 00000000000000000000000000000000 | 0x00000000 | 0 | | 0x3FF0004C | 00000000000000000000000000000000 | 0x00000000 | 0 | | -0x3FF00050 | 10011101111011100000000000000000 | 0x9DEE0000 | 2649620480 | .. | -0x3FF00054 | 00000010000000001001110011000010 | 0x02009CC2 | 33594562 | .. | -0x3FF00058 | 00000000000000001010000000000000 | 0x0000A000 | 40960 | . | +0x3FF00050 | 10011101111011100000000000000000 | 0x9DEE0000 | 2649620480 | .. | MAC0 +0x3FF00054 | 00000010000000001001110011000010 | 0x02009CC2 | 33594562 | .. | MAC1 +0x3FF00058 | 00000000000000001010000000000000 | 0x0000A000 | 40960 | . | CHIPID 0x3FF0005C | 00000000000000000000000000000000 | 0x00000000 | 0 | | 0x3FF00060 | 00000000000000000000000000000000 | 0x00000000 | 0 | | 0x3FF00064 | 00000000000000000000000000000000 | 0x00000000 | 0 | | @@ -687,14 +687,13 @@ 0x60000908 | 00000000000000000000000000001011 | 0x0000000B | 11 | | 0x6000090C | 00000000000000111001000001110010 | 0x00039072 | 233586 | r | 0x60000910 | 00000000000000000000000000000000 | 0x00000000 | 0 | | -0x60000914 | 00000000000000000000000000000000 | 0x00000000 | 0 | | WDTRST +0x60000914 | 00000000000000000000000000000000 | 0x00000000 | 0 | | WDTFEED 0x60000918 | 00000000000000000000000000000000 | 0x00000000 | 0 | | 0x6000091C | 00000000000000000000000000000000 | 0x00000000 | 0 | | 0x60000920 | 00000000000000000000000000111001 | 0x00000039 | 57 | 9 | 0x60000924 | 00000000000000000000000000001011 | 0x0000000B | 11 | | 0x60000928 | 00000000000000000000000000001011 | 0x0000000B | 11 | | -0x6000092C | 00000111100111110000110111101010 | 0x079F0DEA | 127864298 |Ÿ -ê| +0x6000092C | 00000111100111110000110111101010 | 0x079F0DEA | 127864298 | Ÿê | 0x60000930 | 00000000000000000000000000000000 | 0x00000000 | 0 | | 0x60000934 | 00000000000000000000000000000000 | 0x00000000 | 0 | | 0x60000938 | 00000000000000000000000000000000 | 0x00000000 | 0 | | diff --git a/hardware/esp8266com/esp8266/boards.txt b/hardware/esp8266com/esp8266/boards.txt index 0177228e00..bfc910a2b0 100644 --- a/hardware/esp8266com/esp8266/boards.txt +++ b/hardware/esp8266com/esp8266/boards.txt @@ -9,7 +9,8 @@ generic.name=Generic ESP8266 Module generic.upload.tool=esptool generic.upload.speed=115200 generic.upload.resetmethod=ck -generic.upload.maximum_size=524288 +generic.upload.maximum_size=434160 +generic.upload.maximum_data_size=81920 generic.upload.wait_for_upload_port=true generic.serial.disableDTR=true generic.serial.disableRTS=true @@ -58,42 +59,55 @@ generic.menu.FlashSize.512K.build.flash_ld=eagle.flash.512k.ld generic.menu.FlashSize.512K.build.spiffs_start=0x6B000 generic.menu.FlashSize.512K.build.spiffs_end=0x7B000 generic.menu.FlashSize.512K.build.spiffs_blocksize=4096 +generic.menu.FlashSize.512K.upload.maximum_size=434160 + generic.menu.FlashSize.1M512=1M (512K SPIFFS) generic.menu.FlashSize.1M512.build.flash_size=1M generic.menu.FlashSize.1M512.build.flash_ld=eagle.flash.1m512.ld -generic.menu.FlashSize.1M512.build.spiffs_start=0x6B000 +generic.menu.FlashSize.1M512.build.spiffs_start=0x7B000 generic.menu.FlashSize.1M512.build.spiffs_end=0xFB000 generic.menu.FlashSize.1M512.build.spiffs_blocksize=8192 +generic.menu.FlashSize.1M512.upload.maximum_size=499696 + generic.menu.FlashSize.1M256=1M (256K SPIFFS) generic.menu.FlashSize.1M256.build.flash_size=1M generic.menu.FlashSize.1M256.build.flash_ld=eagle.flash.1m256.ld -generic.menu.FlashSize.1M256.build.spiffs_start=0xAB000 +generic.menu.FlashSize.1M256.build.spiffs_start=0xBB000 generic.menu.FlashSize.1M256.build.spiffs_end=0xFB000 generic.menu.FlashSize.1M256.build.spiffs_blocksize=4096 +generic.menu.FlashSize.1M256.upload.maximum_size=761840 + generic.menu.FlashSize.1M128=1M (128K SPIFFS) generic.menu.FlashSize.1M128.build.flash_size=1M generic.menu.FlashSize.1M128.build.flash_ld=eagle.flash.1m128.ld -generic.menu.FlashSize.1M128.build.spiffs_start=0xCB000 +generic.menu.FlashSize.1M128.build.spiffs_start=0xDB000 generic.menu.FlashSize.1M128.build.spiffs_end=0xFB000 generic.menu.FlashSize.1M128.build.spiffs_blocksize=4096 +generic.menu.FlashSize.1M128.upload.maximum_size=892912 + generic.menu.FlashSize.1M64=1M (64K SPIFFS) generic.menu.FlashSize.1M64.build.flash_size=1M generic.menu.FlashSize.1M64.build.flash_ld=eagle.flash.1m64.ld generic.menu.FlashSize.1M64.build.spiffs_start=0xEB000 generic.menu.FlashSize.1M64.build.spiffs_end=0xFB000 generic.menu.FlashSize.1M64.build.spiffs_blocksize=4096 +generic.menu.FlashSize.1M64.upload.maximum_size=958448 + generic.menu.FlashSize.2M=2M (1M SPIFFS) generic.menu.FlashSize.2M.build.flash_size=2M generic.menu.FlashSize.2M.build.flash_ld=eagle.flash.2m.ld generic.menu.FlashSize.2M.build.spiffs_start=0x100000 generic.menu.FlashSize.2M.build.spiffs_end=0x1FB000 generic.menu.FlashSize.2M.build.spiffs_blocksize=8192 +generic.menu.FlashSize.2M.upload.maximum_size=1044464 + generic.menu.FlashSize.4M=4M (3M SPIFFS) generic.menu.FlashSize.4M.build.flash_size=4M generic.menu.FlashSize.4M.build.flash_ld=eagle.flash.4m.ld generic.menu.FlashSize.4M.build.spiffs_start=0x100000 generic.menu.FlashSize.4M.build.spiffs_end=0x3FB000 generic.menu.FlashSize.4M.build.spiffs_blocksize=8192 +generic.menu.FlashSize.4M.upload.maximum_size=1044464 # disabled because espressif's bootloader refuses to write above 4M # generic.menu.FlashSize.8M=8M (7M SPIFFS) @@ -120,7 +134,8 @@ modwifi.name=Olimex MOD-WIFI-ESP8266(-DEV) modwifi.upload.tool=esptool modwifi.upload.speed=115200 modwifi.upload.resetmethod=ck -modwifi.upload.maximum_size=2097152 +modwifi.upload.maximum_size=1044464 +modwifi.upload.maximum_data_size=81920 modwifi.upload.wait_for_upload_port=true modwifi.serial.disableDTR=true modwifi.serial.disableRTS=true @@ -166,12 +181,13 @@ modwifi.menu.UploadSpeed.921600=921600 modwifi.menu.UploadSpeed.921600.upload.speed=921600 ############################################################## -nodemcu.name=NodeMCU (ESP8266 ESP-12 Module) +nodemcu.name=NodeMCU 0.9 (ESP-12 Module) nodemcu.upload.tool=esptool nodemcu.upload.speed=115200 nodemcu.upload.resetmethod=ck -nodemcu.upload.maximum_size=4194304 +nodemcu.upload.maximum_size=1044464 +nodemcu.upload.maximum_data_size=81920 nodemcu.upload.wait_for_upload_port=true nodemcu.serial.disableDTR=true nodemcu.serial.disableRTS=true @@ -215,6 +231,99 @@ nodemcu.menu.UploadSpeed.512000.upload.speed=512000 nodemcu.menu.UploadSpeed.921600=921600 nodemcu.menu.UploadSpeed.921600.upload.speed=921600 +############################################################## +nodemcuv2.name=NodeMCU 1.0 (ESP-12E Module) + +nodemcuv2.upload.tool=esptool +nodemcuv2.upload.speed=115200 +nodemcuv2.upload.resetmethod=ck +nodemcuv2.upload.maximum_size=1044464 +nodemcuv2.upload.maximum_data_size=81920 +nodemcuv2.upload.wait_for_upload_port=true +nodemcuv2.serial.disableDTR=true +nodemcuv2.serial.disableRTS=true + +nodemcuv2.build.mcu=esp8266 +nodemcuv2.build.f_cpu=80000000L +nodemcuv2.build.board=ESP8266_ESP12 +nodemcuv2.build.core=esp8266 +nodemcuv2.build.variant=nodemcu +nodemcuv2.build.flash_mode=dio +nodemcuv2.build.flash_size=4M +nodemcuv2.build.flash_freq=40 +nodemcuv2.build.flash_ld=eagle.flash.4m.ld +nodemcuv2.build.spiffs_start=0x100000 +nodemcuv2.build.spiffs_end=0x3FB000 +nodemcuv2.build.spiffs_pagesize=256 +nodemcuv2.build.spiffs_blocksize=8192 + +nodemcuv2.menu.CpuFrequency.80=80 MHz +nodemcuv2.menu.CpuFrequency.80.build.f_cpu=80000000L +nodemcuv2.menu.CpuFrequency.160=160 MHz +nodemcuv2.menu.CpuFrequency.160.build.f_cpu=160000000L + +nodemcuv2.menu.UploadSpeed.115200=115200 +nodemcuv2.menu.UploadSpeed.115200.upload.speed=115200 +nodemcuv2.menu.UploadSpeed.9600=9600 +nodemcuv2.menu.UploadSpeed.9600.upload.speed=9600 +nodemcuv2.menu.UploadSpeed.57600=57600 +nodemcuv2.menu.UploadSpeed.57600.upload.speed=57600 +nodemcuv2.menu.UploadSpeed.256000.windows=256000 +nodemcuv2.menu.UploadSpeed.256000.upload.speed=256000 +nodemcuv2.menu.UploadSpeed.230400.linux=230400 +nodemcuv2.menu.UploadSpeed.230400.macosx=230400 +nodemcuv2.menu.UploadSpeed.230400.macosx=230400 +nodemcuv2.menu.UploadSpeed.230400.upload.speed=230400 +nodemcuv2.menu.UploadSpeed.460800.linux=460800 +nodemcuv2.menu.UploadSpeed.460800.macosx=460800 +nodemcuv2.menu.UploadSpeed.460800.upload.speed=460800 +nodemcuv2.menu.UploadSpeed.512000.windows=512000 +nodemcuv2.menu.UploadSpeed.512000.upload.speed=512000 +nodemcuv2.menu.UploadSpeed.921600=921600 +nodemcuv2.menu.UploadSpeed.921600.upload.speed=921600 + +############################################################## +huzzah.name=Adafruit HUZZAH ESP8266 + +huzzah.upload.tool=esptool +huzzah.upload.speed=115200 +huzzah.upload.resetmethod=ck +huzzah.upload.maximum_size=1044464 +huzzah.upload.maximum_data_size=81920 +huzzah.upload.wait_for_upload_port=true +huzzah.serial.disableDTR=true +huzzah.serial.disableRTS=true + +huzzah.build.mcu=esp8266 +huzzah.build.f_cpu=80000000L +huzzah.build.board=ESP8266_ESP12 +huzzah.build.core=esp8266 +huzzah.build.variant=adafruit +huzzah.build.flash_mode=qio +huzzah.build.flash_size=4M +huzzah.build.flash_freq=40 +huzzah.build.flash_ld=eagle.flash.4m.ld +huzzah.build.spiffs_start=0x100000 +huzzah.build.spiffs_end=0x3FB000 +huzzah.build.spiffs_pagesize=256 +huzzah.build.spiffs_blocksize=8192 + +huzzah.menu.CpuFrequency.80=80 MHz +huzzah.menu.CpuFrequency.80.build.f_cpu=80000000L +huzzah.menu.CpuFrequency.160=160 MHz +huzzah.menu.CpuFrequency.160.build.f_cpu=160000000L + +huzzah.menu.UploadSpeed.115200=115200 +huzzah.menu.UploadSpeed.115200.upload.speed=115200 +huzzah.menu.UploadSpeed.9600=9600 +huzzah.menu.UploadSpeed.9600.upload.speed=9600 +huzzah.menu.UploadSpeed.57600=57600 +huzzah.menu.UploadSpeed.57600.upload.speed=57600 +huzzah.menu.UploadSpeed.256000=256000 +huzzah.menu.UploadSpeed.256000.upload.speed=256000 +huzzah.menu.UploadSpeed.921600=921600 +huzzah.menu.UploadSpeed.921600.upload.speed=921600 + ############################################################## # wifio.name=Wifio # diff --git a/hardware/esp8266com/esp8266/bootloaders/eboot/LICENSE b/hardware/esp8266com/esp8266/bootloaders/eboot/LICENSE new file mode 100644 index 0000000000..d81a07e401 --- /dev/null +++ b/hardware/esp8266com/esp8266/bootloaders/eboot/LICENSE @@ -0,0 +1,26 @@ +Copyright (c) 2015 Ivan Grokhotkov +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. The name of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. + +Authors: Ivan Grokhotkov diff --git a/hardware/esp8266com/esp8266/bootloaders/eboot/Makefile b/hardware/esp8266com/esp8266/bootloaders/eboot/Makefile new file mode 100644 index 0000000000..0872ee35f5 --- /dev/null +++ b/hardware/esp8266com/esp8266/bootloaders/eboot/Makefile @@ -0,0 +1,52 @@ +XTENSA_TOOLCHAIN ?= + +BIN_DIR := ./ +TARGET_DIR := ./ + +TARGET_OBJ_FILES := \ + eboot.o \ + eboot_command.o \ + flash.o \ + +TARGET_OBJ_PATHS := $(addprefix $(TARGET_DIR)/,$(TARGET_OBJ_FILES)) + +CC := $(XTENSA_TOOLCHAIN)xtensa-lx106-elf-gcc +CXX := $(XTENSA_TOOLCHAIN)xtensa-lx106-elf-g++ +AR := $(XTENSA_TOOLCHAIN)xtensa-lx106-elf-ar +LD := $(XTENSA_TOOLCHAIN)xtensa-lx106-elf-gcc +OBJDUMP := $(XTENSA_TOOLCHAIN)xtensa-lx106-elf-objdump + + +CFLAGS += -std=gnu99 + +CFLAGS += -O0 -g -Wpointer-arith -Wno-implicit-function-declaration -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mno-text-section-literals + +LDFLAGS += -nostdlib -Wl,--no-check-sections -umain + +LD_SCRIPT := -Teboot.ld + +APP_OUT:= eboot.elf +APP_AR := eboot.a +APP_FW := eboot.bin + +all: $(APP_FW) + +$(APP_AR): $(TARGET_OBJ_PATHS) + $(AR) cru $@ $^ + + +$(APP_OUT): $(APP_AR) + $(LD) $(LD_SCRIPT) $(LDFLAGS) -Wl,--start-group -Wl,--whole-archive $(APP_AR) -Wl,--end-group -o $@ + +$(APP_FW): $(APP_OUT) + $(ESPTOOL) -vvv -eo $(APP_OUT) -bo $@ -bs .text -bs .data -bs .rodata -bc -ec || true + + +clean: + rm -f *.o + rm -f $(APP_AR) + rm -f $(APP_OUT) + + +.PHONY: all clean default + diff --git a/hardware/esp8266com/esp8266/bootloaders/eboot/eboot.c b/hardware/esp8266com/esp8266/bootloaders/eboot/eboot.c new file mode 100644 index 0000000000..0b74fcdf07 --- /dev/null +++ b/hardware/esp8266com/esp8266/bootloaders/eboot/eboot.c @@ -0,0 +1,153 @@ +/* Copyright (c) 2015 Ivan Grokhotkov. All rights reserved. + * This file is part of eboot bootloader. + * + * Redistribution and use is permitted according to the conditions of the + * 3-clause BSD license to be found in the LICENSE file. + */ + + +#include +#include +#include +#include "flash.h" +#include "eboot_command.h" + +#define SWRST do { (*((volatile uint32_t*) 0x60000700)) |= 0x80000000; } while(0); + + +int load_app_from_flash_raw(const uint32_t flash_addr) +{ + image_header_t image_header; + uint32_t pos = flash_addr + APP_START_OFFSET; + + if (SPIRead(pos, &image_header, sizeof(image_header))) { + return 1; + } + pos += sizeof(image_header); + + + for (uint32_t section_index = 0; + section_index < image_header.num_segments; + ++section_index) + { + section_header_t section_header = {0}; + if (SPIRead(pos, §ion_header, sizeof(section_header))) { + return 2; + } + pos += sizeof(section_header); + + const uint32_t address = section_header.address; + + bool load = false; + + if (address < 0x40000000) { + load = true; + } + + if (address >= 0x40100000 && address < 0x40108000) { + load = true; + } + + if (address >= 0x60000000) { + load = true; + } + + if (!load) { + pos += section_header.size; + continue; + } + + if (SPIRead(pos, (void*)address, section_header.size)) + return 3; + + pos += section_header.size; + } + + register uint32_t sp asm("a1") = 0x3ffffff0; + register uint32_t pc asm("a3") = image_header.entry; + __asm__ __volatile__ ("jx a3"); + + return 0; +} + + + +int copy_raw(const uint32_t src_addr, + const uint32_t dst_addr, + const uint32_t size) +{ + ets_putc('\n'); + ets_putc('c'); + ets_putc('p'); + ets_putc('\n'); + // require regions to be aligned + if (src_addr & 0xfff != 0 || + dst_addr & 0xfff != 0) { + return 1; + } + + if (SPIEraseAreaEx(dst_addr, size)) { + return 2; + } + + const uint32_t buffer_size = 4096; + uint8_t buffer[buffer_size]; + + const uint32_t end = src_addr + size; + uint32_t saddr = src_addr; + uint32_t daddr = dst_addr; + uint32_t left = size; + while (saddr < end) { + uint32_t will_copy = (left < buffer_size) ? left : buffer_size; + if (SPIRead(saddr, buffer, will_copy)) { + return 3; + } + if (SPIWrite(daddr, buffer, will_copy)) { + return 4; + } + saddr += will_copy; + daddr += will_copy; + left -= will_copy; + } + + return 0; +} + + + +void main() +{ + int res = 9; + struct eboot_command cmd; + + if (eboot_command_read(&cmd)) { + cmd.action = ACTION_LOAD_APP; + cmd.args[0] = 0; + ets_putc('e'); + } else { + ets_putc('@'); + } + eboot_command_clear(); + + if (cmd.action == ACTION_COPY_RAW) { + res = copy_raw(cmd.args[0], cmd.args[1], cmd.args[2]); + if (res == 0) { + cmd.action = ACTION_LOAD_APP; + cmd.args[0] = cmd.args[1]; + } + } + + if (cmd.action == ACTION_LOAD_APP) { + res = load_app_from_flash_raw(cmd.args[0]); + } + + if (res) { + ets_putc('\n'); + ets_putc('#'); + ets_putc('0' + res); + ets_putc('\n'); + SWRST; + } + + while(true){} +} diff --git a/hardware/esp8266com/esp8266/bootloaders/eboot/eboot.elf b/hardware/esp8266com/esp8266/bootloaders/eboot/eboot.elf new file mode 100755 index 0000000000..97e25c1461 Binary files /dev/null and b/hardware/esp8266com/esp8266/bootloaders/eboot/eboot.elf differ diff --git a/hardware/esp8266com/esp8266/bootloaders/eboot/eboot.ld b/hardware/esp8266com/esp8266/bootloaders/eboot/eboot.ld new file mode 100644 index 0000000000..303ae8a56c --- /dev/null +++ b/hardware/esp8266com/esp8266/bootloaders/eboot/eboot.ld @@ -0,0 +1,176 @@ +/* This linker script generated from xt-genldscripts.tpp for LSP . */ +/* Linker Script for ld -N */ +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x14000 + iram1_0_seg : org = 0x4010f000, len = 0x1000 + irom0_0_seg : org = 0x40240000, len = 0x32000 +} + +PHDRS +{ + dport0_0_phdr PT_LOAD; + dram0_0_phdr PT_LOAD; + dram0_0_bss_phdr PT_LOAD; + iram1_0_phdr PT_LOAD; + irom0_0_phdr PT_LOAD; +} + + +/* Default entry point: */ +ENTRY(main) +PROVIDE(_memmap_vecbase_reset = 0x40000000); +/* Various memory-map dependent cache attribute settings: */ +_memmap_cacheattr_wb_base = 0x00000110; +_memmap_cacheattr_wt_base = 0x00000110; +_memmap_cacheattr_bp_base = 0x00000220; +_memmap_cacheattr_unused_mask = 0xFFFFF00F; +_memmap_cacheattr_wb_trapnull = 0x2222211F; +_memmap_cacheattr_wba_trapnull = 0x2222211F; +_memmap_cacheattr_wbna_trapnull = 0x2222211F; +_memmap_cacheattr_wt_trapnull = 0x2222211F; +_memmap_cacheattr_bp_trapnull = 0x2222222F; +_memmap_cacheattr_wb_strict = 0xFFFFF11F; +_memmap_cacheattr_wt_strict = 0xFFFFF11F; +_memmap_cacheattr_bp_strict = 0xFFFFF22F; +_memmap_cacheattr_wb_allvalid = 0x22222112; +_memmap_cacheattr_wt_allvalid = 0x22222112; +_memmap_cacheattr_bp_allvalid = 0x22222222; +PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull); + +SECTIONS +{ + + .dport0.rodata : ALIGN(4) + { + _dport0_rodata_start = ABSOLUTE(.); + *(.dport0.rodata) + *(.dport.rodata) + _dport0_rodata_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .dport0.literal : ALIGN(4) + { + _dport0_literal_start = ABSOLUTE(.); + *(.dport0.literal) + *(.dport.literal) + _dport0_literal_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .dport0.data : ALIGN(4) + { + _dport0_data_start = ABSOLUTE(.); + *(.dport0.data) + *(.dport.data) + _dport0_data_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .data : ALIGN(4) + { + _heap_start = ABSOLUTE(.); +/* _stack_sentry = ALIGN(0x8); */ + } >dram0_0_seg :dram0_0_bss_phdr +/* __stack = 0x3ffc8000; */ + + .text : ALIGN(4) + { + _stext = .; + _text_start = ABSOLUTE(.); + *(.entry.text) + *(.init.literal) + *(.init) + *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.fini.literal) + *(.fini) + *(.gnu.version) + _text_end = ABSOLUTE(.); + _etext = .; + . = ALIGN (8); + _data_start = ABSOLUTE(.); + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.data1) + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + *(.jcr) + _data_end = ABSOLUTE(.); + . = ALIGN (8); + _rodata_start = ABSOLUTE(.); + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + *(.rodata1) + __XT_EXCEPTION_TABLE__ = ABSOLUTE(.); + *(.xt_except_table) + *(.gcc_except_table) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + *(.eh_frame) + /* C++ constructor and destructor tables, properly ordered: */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + /* C++ exception handlers table: */ + __XT_EXCEPTION_DESCS__ = ABSOLUTE(.); + *(.xt_except_desc) + *(.gnu.linkonce.h.*) + __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); + *(.xt_except_desc_end) + *(.dynamic) + *(.gnu.version_d) + . = ALIGN(4); /* this table MUST be 4-byte aligned */ + _bss_table_start = ABSOLUTE(.); + LONG(_bss_start) + LONG(_bss_end) + _bss_table_end = ABSOLUTE(.); + _rodata_end = ABSOLUTE(.); + + . = ALIGN (8); + _bss_start = ABSOLUTE(.); + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + *(.dynbss) + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + _bss_end = ABSOLUTE(.); + } >iram1_0_seg :iram1_0_phdr + + .lit4 : ALIGN(4) + { + _lit4_start = ABSOLUTE(.); + *(*.lit4) + *(.lit4.*) + *(.gnu.linkonce.lit4.*) + _lit4_end = ABSOLUTE(.); + } >iram1_0_seg :iram1_0_phdr + + .irom0.text : ALIGN(4) + { + _irom0_text_start = ABSOLUTE(.); + *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text) + _irom0_text_end = ABSOLUTE(.); + } >irom0_0_seg :irom0_0_phdr +} + +/* get ROM code address */ +INCLUDE "rom.ld" diff --git a/hardware/esp8266com/esp8266/bootloaders/eboot/eboot_command.c b/hardware/esp8266com/esp8266/bootloaders/eboot/eboot_command.c new file mode 100644 index 0000000000..648039e48a --- /dev/null +++ b/hardware/esp8266com/esp8266/bootloaders/eboot/eboot_command.c @@ -0,0 +1,65 @@ +#include "eboot_command.h" + +uint32_t crc_update(uint32_t crc, const uint8_t *data, size_t length) +{ + uint32_t i; + bool bit; + uint8_t c; + + while (length--) { + c = *data++; + for (i = 0x80; i > 0; i >>= 1) { + bit = crc & 0x80000000; + if (c & i) { + bit = !bit; + } + crc <<= 1; + if (bit) { + crc ^= 0x04c11db7; + } + } + } + return crc; +} + +uint32_t eboot_command_calculate_crc32(const struct eboot_command* cmd) +{ + return crc_update(0xffffffff, (const uint8_t*) cmd, + offsetof(struct eboot_command, crc32)); +} + +int eboot_command_read(struct eboot_command* cmd) +{ + const uint32_t dw_count = sizeof(struct eboot_command) / sizeof(uint32_t); + uint32_t* dst = (uint32_t *) cmd; + for (uint32_t i = 0; i < dw_count; ++i) { + dst[i] = RTC_MEM[i]; + } + + uint32_t crc32 = eboot_command_calculate_crc32(cmd); + if (cmd->magic & EBOOT_MAGIC_MASK != EBOOT_MAGIC || + cmd->crc32 != crc32) { + return 1; + } + + return 0; +} + +void eboot_command_write(struct eboot_command* cmd) +{ + cmd->magic = EBOOT_MAGIC; + cmd->crc32 = eboot_command_calculate_crc32(cmd); + + const uint32_t dw_count = sizeof(struct eboot_command) / sizeof(uint32_t); + const uint32_t* src = (const uint32_t *) cmd; + for (uint32_t i = 0; i < dw_count; ++i) { + RTC_MEM[i] = src[i]; + } +} + +void eboot_command_clear() +{ + RTC_MEM[offsetof(struct eboot_command, magic) / sizeof(uint32_t)] = 0; + RTC_MEM[offsetof(struct eboot_command, crc32) / sizeof(uint32_t)] = 0; +} + diff --git a/hardware/esp8266com/esp8266/bootloaders/eboot/eboot_command.h b/hardware/esp8266com/esp8266/bootloaders/eboot/eboot_command.h new file mode 100644 index 0000000000..ba9c889a2c --- /dev/null +++ b/hardware/esp8266com/esp8266/bootloaders/eboot/eboot_command.h @@ -0,0 +1,37 @@ +/* Copyright (c) 2015 Ivan Grokhotkov. All rights reserved. + * This file is part of eboot bootloader. + * + * Redistribution and use is permitted according to the conditions of the + * 3-clause BSD license to be found in the LICENSE file. + */ + +#ifndef EBOOT_COMMAND_H +#define EBOOT_COMMAND_H + +#include +#include +#include + +#define RTC_MEM ((volatile uint32_t*)0x60001200) + +enum action_t { + ACTION_COPY_RAW = 0x00000001, + ACTION_LOAD_APP = 0xffffffff +}; + +#define EBOOT_MAGIC 0xeb001000 +#define EBOOT_MAGIC_MASK 0xfffff000 + +struct eboot_command { + uint32_t magic; + enum action_t action; + uint32_t args[29]; + uint32_t crc32; +}; + + +int eboot_command_read(struct eboot_command* cmd); +void eboot_command_write(struct eboot_command* cmd); +void eboot_command_clear(); + +#endif //EBOOT_COMMAND_H diff --git a/hardware/esp8266com/esp8266/bootloaders/eboot/flash.c b/hardware/esp8266com/esp8266/bootloaders/eboot/flash.c new file mode 100644 index 0000000000..f90e25b347 --- /dev/null +++ b/hardware/esp8266com/esp8266/bootloaders/eboot/flash.c @@ -0,0 +1,49 @@ +/* Copyright (c) 2015 Ivan Grokhotkov. All rights reserved. + * This file is part of eboot bootloader. + * + * Redistribution and use is permitted according to the conditions of the + * 3-clause BSD license to be found in the LICENSE file. + */ + +#include +#include +#include +#include "flash.h" + + +int SPIEraseAreaEx(const uint32_t start, const uint32_t size) +{ + if (start & (FLASH_SECTOR_SIZE - 1) != 0) { + return 1; + } + + const uint32_t sectors_per_block = FLASH_BLOCK_SIZE / FLASH_SECTOR_SIZE; + uint32_t current_sector = start / FLASH_SECTOR_SIZE; + uint32_t sector_count = (size + FLASH_SECTOR_SIZE - 1) / FLASH_SECTOR_SIZE; + const uint32_t end = current_sector + sector_count; + + for (; current_sector < end && (current_sector & (sectors_per_block-1)); + ++current_sector, --sector_count) { + if (SPIEraseSector(current_sector)) { + return 2; + } + } + + for (;current_sector + sectors_per_block <= end; + current_sector += sectors_per_block, + sector_count -= sectors_per_block) { + if (SPIEraseBlock(current_sector / sectors_per_block)) { + return 3; + } + } + + for (; current_sector < end; + ++current_sector, --sector_count) { + if (SPIEraseSector(current_sector)) { + return 4; + } + } + + return 0; +} + diff --git a/hardware/esp8266com/esp8266/bootloaders/eboot/flash.h b/hardware/esp8266com/esp8266/bootloaders/eboot/flash.h new file mode 100644 index 0000000000..ea8b65c1fa --- /dev/null +++ b/hardware/esp8266com/esp8266/bootloaders/eboot/flash.h @@ -0,0 +1,43 @@ +/* Copyright (c) 2015 Ivan Grokhotkov. All rights reserved. + * This file is part of eboot bootloader. + * + * Redistribution and use is permitted according to the conditions of the + * 3-clause BSD license to be found in the LICENSE file. + */ + +#ifndef FLASH_H +#define FLASH_H + +int SPIEraseBlock(uint32_t block); +int SPIEraseSector(uint32_t sector); +int SPIRead(uint32_t addr, void *dest, size_t size); +int SPIWrite(uint32_t addr, void *src, size_t size); +int SPIEraseAreaEx(const uint32_t start, const uint32_t size); + +#define FLASH_SECTOR_SIZE 0x1000 +#define FLASH_BLOCK_SIZE 0x10000 +#define APP_START_OFFSET 0x1000 + +typedef struct { + unsigned char magic; + unsigned char num_segments; + + /* SPI Flash Interface (0 = QIO, 1 = QOUT, 2 = DIO, 0x3 = DOUT) */ + unsigned char flash_mode; + + /* High four bits: 0 = 512K, 1 = 256K, 2 = 1M, 3 = 2M, 4 = 4M, + Low four bits: 0 = 40MHz, 1= 26MHz, 2 = 20MHz, 0xf = 80MHz */ + unsigned char flash_size_freq; + + uint32_t entry; +} image_header_t; + + +typedef struct { + uint32_t address; + uint32_t size; +} section_header_t; + + + +#endif //FLASH_H diff --git a/hardware/esp8266com/esp8266/bootloaders/eboot/rom.ld b/hardware/esp8266com/esp8266/bootloaders/eboot/rom.ld new file mode 100755 index 0000000000..c5c1b65223 --- /dev/null +++ b/hardware/esp8266com/esp8266/bootloaders/eboot/rom.ld @@ -0,0 +1,344 @@ +PROVIDE ( Cache_Read_Disable = 0x400047f0 ); +PROVIDE ( Cache_Read_Enable = 0x40004678 ); +PROVIDE ( FilePacketSendReqMsgProc = 0x400035a0 ); +PROVIDE ( FlashDwnLdParamCfgMsgProc = 0x4000368c ); +PROVIDE ( FlashDwnLdStartMsgProc = 0x40003538 ); +PROVIDE ( FlashDwnLdStopReqMsgProc = 0x40003658 ); +PROVIDE ( GetUartDevice = 0x40003f4c ); +PROVIDE ( MD5Final = 0x40009900 ); +PROVIDE ( MD5Init = 0x40009818 ); +PROVIDE ( MD5Update = 0x40009834 ); +PROVIDE ( MemDwnLdStartMsgProc = 0x400036c4 ); +PROVIDE ( MemDwnLdStopReqMsgProc = 0x4000377c ); +PROVIDE ( MemPacketSendReqMsgProc = 0x400036f0 ); +PROVIDE ( RcvMsg = 0x40003eac ); +PROVIDE ( SHA1Final = 0x4000b648 ); +PROVIDE ( SHA1Init = 0x4000b584 ); +PROVIDE ( SHA1Transform = 0x4000a364 ); +PROVIDE ( SHA1Update = 0x4000b5a8 ); +PROVIDE ( Wait_SPI_Idle = 0x4000448c ); +PROVIDE ( SPIEraseArea = 0x40004b44 ); +PROVIDE ( SPIEraseBlock = 0x400049b4 ); +PROVIDE ( SPIEraseChip = 0x40004984 ); +PROVIDE ( SPIEraseSector = 0x40004a00 ); +PROVIDE ( SPILock = 0x400048a8 ); +PROVIDE ( SPIParamCfg = 0x40004c2c ); +PROVIDE ( SPIRead = 0x40004b1c ); +PROVIDE ( SPIReadModeCnfig = 0x400048ec ); +PROVIDE ( SPIUnlock = 0x40004878 ); +PROVIDE ( SPIWrite = 0x40004a4c ); +PROVIDE ( SelectSpiFunction = 0x40003f58 ); +PROVIDE ( SendMsg = 0x40003cf4 ); +PROVIDE ( UartConnCheck = 0x40003230 ); +PROVIDE ( UartConnectProc = 0x400037a0 ); +PROVIDE ( UartDwnLdProc = 0x40003368 ); +PROVIDE ( UartGetCmdLn = 0x40003ef4 ); +PROVIDE ( UartRegReadProc = 0x4000381c ); +PROVIDE ( UartRegWriteProc = 0x400037ac ); +PROVIDE ( UartRxString = 0x40003c30 ); +PROVIDE ( Uart_Init = 0x40003a14 ); +PROVIDE ( _DebugExceptionVector = 0x40000010 ); +PROVIDE ( _DoubleExceptionVector = 0x40000070 ); +PROVIDE ( _KernelExceptionVector = 0x40000030 ); +PROVIDE ( _NMIExceptionVector = 0x40000020 ); +PROVIDE ( _ResetHandler = 0x400000a4 ); +PROVIDE ( _ResetVector = 0x40000080 ); +PROVIDE ( _UserExceptionVector = 0x40000050 ); +PROVIDE ( __adddf3 = 0x4000c538 ); +PROVIDE ( __addsf3 = 0x4000c180 ); +PROVIDE ( __divdf3 = 0x4000cb94 ); +PROVIDE ( __divdi3 = 0x4000ce60 ); +PROVIDE ( __divsi3 = 0x4000dc88 ); +PROVIDE ( __extendsfdf2 = 0x4000cdfc ); +PROVIDE ( __fixdfsi = 0x4000ccb8 ); +PROVIDE ( __fixunsdfsi = 0x4000cd00 ); +PROVIDE ( __fixunssfsi = 0x4000c4c4 ); +PROVIDE ( __floatsidf = 0x4000e2f0 ); +PROVIDE ( __floatsisf = 0x4000e2ac ); +PROVIDE ( __floatunsidf = 0x4000e2e8 ); +PROVIDE ( __floatunsisf = 0x4000e2a4 ); +PROVIDE ( __muldf3 = 0x4000c8f0 ); +PROVIDE ( __muldi3 = 0x40000650 ); +PROVIDE ( __mulsf3 = 0x4000c3dc ); +PROVIDE ( __subdf3 = 0x4000c688 ); +PROVIDE ( __subsf3 = 0x4000c268 ); +PROVIDE ( __truncdfsf2 = 0x4000cd5c ); +PROVIDE ( __udivdi3 = 0x4000d310 ); +PROVIDE ( __udivsi3 = 0x4000e21c ); +PROVIDE ( __umoddi3 = 0x4000d770 ); +PROVIDE ( __umodsi3 = 0x4000e268 ); +PROVIDE ( __umulsidi3 = 0x4000dcf0 ); +PROVIDE ( _rom_store = 0x4000e388 ); +PROVIDE ( _rom_store_table = 0x4000e328 ); +PROVIDE ( _start = 0x4000042c ); +PROVIDE ( _xtos_alloca_handler = 0x4000dbe0 ); +PROVIDE ( _xtos_c_wrapper_handler = 0x40000598 ); +PROVIDE ( _xtos_cause3_handler = 0x40000590 ); +PROVIDE ( _xtos_ints_off = 0x4000bda4 ); +PROVIDE ( _xtos_ints_on = 0x4000bd84 ); +PROVIDE ( _xtos_l1int_handler = 0x4000048c ); +PROVIDE ( _xtos_p_none = 0x4000dbf8 ); +PROVIDE ( _xtos_restore_intlevel = 0x4000056c ); +PROVIDE ( _xtos_return_from_exc = 0x4000dc54 ); +PROVIDE ( _xtos_set_exception_handler = 0x40000454 ); +PROVIDE ( _xtos_set_interrupt_handler = 0x4000bd70 ); +PROVIDE ( _xtos_set_interrupt_handler_arg = 0x4000bd28 ); +PROVIDE ( _xtos_set_intlevel = 0x4000dbfc ); +PROVIDE ( _xtos_set_min_intlevel = 0x4000dc18 ); +PROVIDE ( _xtos_set_vpri = 0x40000574 ); +PROVIDE ( _xtos_syscall_handler = 0x4000dbe4 ); +PROVIDE ( _xtos_unhandled_exception = 0x4000dc44 ); +PROVIDE ( _xtos_unhandled_interrupt = 0x4000dc3c ); +PROVIDE ( aes_decrypt = 0x400092d4 ); +PROVIDE ( aes_decrypt_deinit = 0x400092e4 ); +PROVIDE ( aes_decrypt_init = 0x40008ea4 ); +PROVIDE ( aes_unwrap = 0x40009410 ); +PROVIDE ( base64_decode = 0x40009648 ); +PROVIDE ( base64_encode = 0x400094fc ); +PROVIDE ( bzero = 0x4000de84 ); +PROVIDE ( cmd_parse = 0x40000814 ); +PROVIDE ( conv_str_decimal = 0x40000b24 ); +PROVIDE ( conv_str_hex = 0x40000cb8 ); +PROVIDE ( convert_para_str = 0x40000a60 ); +PROVIDE ( dtm_get_intr_mask = 0x400026d0 ); +PROVIDE ( dtm_params_init = 0x4000269c ); +PROVIDE ( dtm_set_intr_mask = 0x400026c8 ); +PROVIDE ( dtm_set_params = 0x400026dc ); +PROVIDE ( eprintf = 0x40001d14 ); +PROVIDE ( eprintf_init_buf = 0x40001cb8 ); +PROVIDE ( eprintf_to_host = 0x40001d48 ); +PROVIDE ( est_get_printf_buf_remain_len = 0x40002494 ); +PROVIDE ( est_reset_printf_buf_len = 0x4000249c ); +PROVIDE ( ets_bzero = 0x40002ae8 ); +PROVIDE ( ets_char2xdigit = 0x40002b74 ); +PROVIDE ( ets_delay_us = 0x40002ecc ); +PROVIDE ( ets_enter_sleep = 0x400027b8 ); +PROVIDE ( ets_external_printf = 0x40002578 ); +PROVIDE ( ets_get_cpu_frequency = 0x40002f0c ); +PROVIDE ( ets_getc = 0x40002bcc ); +PROVIDE ( ets_install_external_printf = 0x40002450 ); +PROVIDE ( ets_install_putc1 = 0x4000242c ); +PROVIDE ( ets_install_putc2 = 0x4000248c ); +PROVIDE ( ets_install_uart_printf = 0x40002438 ); +PROVIDE ( ets_intr_lock = 0x40000f74 ); +PROVIDE ( ets_intr_unlock = 0x40000f80 ); +PROVIDE ( ets_isr_attach = 0x40000f88 ); +PROVIDE ( ets_isr_mask = 0x40000f98 ); +PROVIDE ( ets_isr_unmask = 0x40000fa8 ); +PROVIDE ( ets_memcmp = 0x400018d4 ); +PROVIDE ( ets_memcpy = 0x400018b4 ); +PROVIDE ( ets_memmove = 0x400018c4 ); +PROVIDE ( ets_memset = 0x400018a4 ); +PROVIDE ( ets_post = 0x40000e24 ); +PROVIDE ( ets_printf = 0x400024cc ); +PROVIDE ( ets_putc = 0x40002be8 ); +PROVIDE ( ets_rtc_int_register = 0x40002a40 ); +PROVIDE ( ets_run = 0x40000e04 ); +PROVIDE ( ets_set_idle_cb = 0x40000dc0 ); +PROVIDE ( ets_set_user_start = 0x40000fbc ); +PROVIDE ( ets_str2macaddr = 0x40002af8 ); +PROVIDE ( ets_strcmp = 0x40002aa8 ); +PROVIDE ( ets_strcpy = 0x40002a88 ); +PROVIDE ( ets_strlen = 0x40002ac8 ); +PROVIDE ( ets_strncmp = 0x40002ab8 ); +PROVIDE ( ets_strncpy = 0x40002a98 ); +PROVIDE ( ets_strstr = 0x40002ad8 ); +PROVIDE ( ets_task = 0x40000dd0 ); +PROVIDE ( ets_timer_arm = 0x40002cc4 ); +PROVIDE ( ets_timer_disarm = 0x40002d40 ); +PROVIDE ( ets_timer_done = 0x40002d80 ); +PROVIDE ( ets_timer_handler_isr = 0x40002da8 ); +PROVIDE ( ets_timer_init = 0x40002e68 ); +PROVIDE ( ets_timer_setfn = 0x40002c48 ); +PROVIDE ( ets_uart_printf = 0x40002544 ); +PROVIDE ( ets_update_cpu_frequency = 0x40002f04 ); +PROVIDE ( ets_vprintf = 0x40001f00 ); +PROVIDE ( ets_wdt_disable = 0x400030f0 ); +PROVIDE ( ets_wdt_enable = 0x40002fa0 ); +PROVIDE ( ets_wdt_get_mode = 0x40002f34 ); +PROVIDE ( ets_wdt_init = 0x40003170 ); +PROVIDE ( ets_wdt_restore = 0x40003158 ); +PROVIDE ( ets_write_char = 0x40001da0 ); +PROVIDE ( get_first_seg = 0x4000091c ); +PROVIDE ( gpio_init = 0x40004c50 ); +PROVIDE ( gpio_input_get = 0x40004cf0 ); +PROVIDE ( gpio_intr_ack = 0x40004dcc ); +PROVIDE ( gpio_intr_handler_register = 0x40004e28 ); +PROVIDE ( gpio_intr_pending = 0x40004d88 ); +PROVIDE ( gpio_intr_test = 0x40004efc ); +PROVIDE ( gpio_output_set = 0x40004cd0 ); +PROVIDE ( gpio_pin_intr_state_set = 0x40004d90 ); +PROVIDE ( gpio_pin_wakeup_disable = 0x40004ed4 ); +PROVIDE ( gpio_pin_wakeup_enable = 0x40004e90 ); +PROVIDE ( gpio_register_get = 0x40004d5c ); +PROVIDE ( gpio_register_set = 0x40004d04 ); +PROVIDE ( hmac_md5 = 0x4000a2cc ); +PROVIDE ( hmac_md5_vector = 0x4000a160 ); +PROVIDE ( hmac_sha1 = 0x4000ba28 ); +PROVIDE ( hmac_sha1_vector = 0x4000b8b4 ); +PROVIDE ( lldesc_build_chain = 0x40004f40 ); +PROVIDE ( lldesc_num2link = 0x40005050 ); +PROVIDE ( lldesc_set_owner = 0x4000507c ); +PROVIDE ( main = 0x40000fec ); +PROVIDE ( md5_vector = 0x400097ac ); +PROVIDE ( mem_calloc = 0x40001c2c ); +PROVIDE ( mem_free = 0x400019e0 ); +PROVIDE ( mem_init = 0x40001998 ); +PROVIDE ( mem_malloc = 0x40001b40 ); +PROVIDE ( mem_realloc = 0x40001c6c ); +PROVIDE ( mem_trim = 0x40001a14 ); +PROVIDE ( mem_zalloc = 0x40001c58 ); +PROVIDE ( memcmp = 0x4000dea8 ); +PROVIDE ( memcpy = 0x4000df48 ); +PROVIDE ( memmove = 0x4000e04c ); +PROVIDE ( memset = 0x4000e190 ); +PROVIDE ( multofup = 0x400031c0 ); +PROVIDE ( pbkdf2_sha1 = 0x4000b840 ); +PROVIDE ( phy_get_romfuncs = 0x40006b08 ); +PROVIDE ( rand = 0x40000600 ); +PROVIDE ( rc4_skip = 0x4000dd68 ); +PROVIDE ( recv_packet = 0x40003d08 ); +PROVIDE ( remove_head_space = 0x40000a04 ); +PROVIDE ( rijndaelKeySetupDec = 0x40008dd0 ); +PROVIDE ( rijndaelKeySetupEnc = 0x40009300 ); +PROVIDE ( rom_abs_temp = 0x400060c0 ); +PROVIDE ( rom_ana_inf_gating_en = 0x40006b10 ); +PROVIDE ( rom_cal_tos_v50 = 0x40007a28 ); +PROVIDE ( rom_chip_50_set_channel = 0x40006f84 ); +PROVIDE ( rom_chip_v5_disable_cca = 0x400060d0 ); +PROVIDE ( rom_chip_v5_enable_cca = 0x400060ec ); +PROVIDE ( rom_chip_v5_rx_init = 0x4000711c ); +PROVIDE ( rom_chip_v5_sense_backoff = 0x4000610c ); +PROVIDE ( rom_chip_v5_tx_init = 0x4000718c ); +PROVIDE ( rom_dc_iq_est = 0x4000615c ); +PROVIDE ( rom_en_pwdet = 0x400061b8 ); +PROVIDE ( rom_get_bb_atten = 0x40006238 ); +PROVIDE ( rom_get_corr_power = 0x40006260 ); +PROVIDE ( rom_get_fm_sar_dout = 0x400062dc ); +PROVIDE ( rom_get_noisefloor = 0x40006394 ); +PROVIDE ( rom_get_power_db = 0x400063b0 ); +PROVIDE ( rom_i2c_readReg = 0x40007268 ); +PROVIDE ( rom_i2c_readReg_Mask = 0x4000729c ); +PROVIDE ( rom_i2c_writeReg = 0x400072d8 ); +PROVIDE ( rom_i2c_writeReg_Mask = 0x4000730c ); +PROVIDE ( rom_iq_est_disable = 0x40006400 ); +PROVIDE ( rom_iq_est_enable = 0x40006430 ); +PROVIDE ( rom_linear_to_db = 0x40006484 ); +PROVIDE ( rom_mhz2ieee = 0x400065a4 ); +PROVIDE ( rom_pbus_dco___SA2 = 0x40007bf0 ); +PROVIDE ( rom_pbus_debugmode = 0x4000737c ); +PROVIDE ( rom_pbus_enter_debugmode = 0x40007410 ); +PROVIDE ( rom_pbus_exit_debugmode = 0x40007448 ); +PROVIDE ( rom_pbus_force_test = 0x4000747c ); +PROVIDE ( rom_pbus_rd = 0x400074d8 ); +PROVIDE ( rom_pbus_set_rxgain = 0x4000754c ); +PROVIDE ( rom_pbus_set_txgain = 0x40007610 ); +PROVIDE ( rom_pbus_workmode = 0x40007648 ); +PROVIDE ( rom_pbus_xpd_rx_off = 0x40007688 ); +PROVIDE ( rom_pbus_xpd_rx_on = 0x400076cc ); +PROVIDE ( rom_pbus_xpd_tx_off = 0x400076fc ); +PROVIDE ( rom_pbus_xpd_tx_on = 0x40007740 ); +PROVIDE ( rom_pbus_xpd_tx_on__low_gain = 0x400077a0 ); +PROVIDE ( rom_phy_reset_req = 0x40007804 ); +PROVIDE ( rom_restart_cal = 0x4000781c ); +PROVIDE ( rom_rfcal_pwrctrl = 0x40007eb4 ); +PROVIDE ( rom_rfcal_rxiq = 0x4000804c ); +PROVIDE ( rom_rfcal_rxiq_set_reg = 0x40008264 ); +PROVIDE ( rom_rfcal_txcap = 0x40008388 ); +PROVIDE ( rom_rfcal_txiq = 0x40008610 ); +PROVIDE ( rom_rfcal_txiq_cover = 0x400088b8 ); +PROVIDE ( rom_rfcal_txiq_set_reg = 0x40008a70 ); +PROVIDE ( rom_rfpll_reset = 0x40007868 ); +PROVIDE ( rom_rfpll_set_freq = 0x40007968 ); +PROVIDE ( rom_rxiq_cover_mg_mp = 0x40008b6c ); +PROVIDE ( rom_rxiq_get_mis = 0x40006628 ); +PROVIDE ( rom_sar_init = 0x40006738 ); +PROVIDE ( rom_set_ana_inf_tx_scale = 0x4000678c ); +PROVIDE ( rom_set_channel_freq = 0x40006c50 ); +PROVIDE ( rom_set_loopback_gain = 0x400067c8 ); +PROVIDE ( rom_set_noise_floor = 0x40006830 ); +PROVIDE ( rom_set_rxclk_en = 0x40006550 ); +PROVIDE ( rom_set_txbb_atten = 0x40008c6c ); +PROVIDE ( rom_set_txclk_en = 0x4000650c ); +PROVIDE ( rom_set_txiq_cal = 0x40008d34 ); +PROVIDE ( rom_start_noisefloor = 0x40006874 ); +PROVIDE ( rom_start_tx_tone = 0x400068b4 ); +PROVIDE ( rom_stop_tx_tone = 0x4000698c ); +PROVIDE ( rom_tx_mac_disable = 0x40006a98 ); +PROVIDE ( rom_tx_mac_enable = 0x40006ad4 ); +PROVIDE ( rom_txtone_linear_pwr = 0x40006a1c ); +PROVIDE ( rom_write_rfpll_sdm = 0x400078dc ); +PROVIDE ( roundup2 = 0x400031b4 ); +PROVIDE ( rtc_enter_sleep = 0x40002870 ); +PROVIDE ( rtc_get_reset_reason = 0x400025e0 ); +PROVIDE ( rtc_intr_handler = 0x400029ec ); +PROVIDE ( rtc_set_sleep_mode = 0x40002668 ); +PROVIDE ( save_rxbcn_mactime = 0x400027a4 ); +PROVIDE ( save_tsf_us = 0x400027ac ); +PROVIDE ( send_packet = 0x40003c80 ); +PROVIDE ( sha1_prf = 0x4000ba48 ); +PROVIDE ( sha1_vector = 0x4000a2ec ); +PROVIDE ( sip_alloc_to_host_evt = 0x40005180 ); +PROVIDE ( sip_get_ptr = 0x400058a8 ); +PROVIDE ( sip_get_state = 0x40005668 ); +PROVIDE ( sip_init_attach = 0x4000567c ); +PROVIDE ( sip_install_rx_ctrl_cb = 0x4000544c ); +PROVIDE ( sip_install_rx_data_cb = 0x4000545c ); +PROVIDE ( sip_post = 0x400050fc ); +PROVIDE ( sip_post_init = 0x400056c4 ); +PROVIDE ( sip_reclaim_from_host_cmd = 0x4000534c ); +PROVIDE ( sip_reclaim_tx_data_pkt = 0x400052c0 ); +PROVIDE ( sip_send = 0x40005808 ); +PROVIDE ( sip_to_host_chain_append = 0x40005864 ); +PROVIDE ( sip_to_host_evt_send_done = 0x40005234 ); +PROVIDE ( slc_add_credits = 0x400060ac ); +PROVIDE ( slc_enable = 0x40005d90 ); +PROVIDE ( slc_from_host_chain_fetch = 0x40005f24 ); +PROVIDE ( slc_from_host_chain_recycle = 0x40005e94 ); +PROVIDE ( slc_init_attach = 0x40005c50 ); +PROVIDE ( slc_init_credit = 0x4000608c ); +PROVIDE ( slc_pause_from_host = 0x40006014 ); +PROVIDE ( slc_reattach = 0x40005c1c ); +PROVIDE ( slc_resume_from_host = 0x4000603c ); +PROVIDE ( slc_select_tohost_gpio = 0x40005dc0 ); +PROVIDE ( slc_select_tohost_gpio_mode = 0x40005db8 ); +PROVIDE ( slc_send_to_host_chain = 0x40005de4 ); +PROVIDE ( slc_set_host_io_max_window = 0x40006068 ); +PROVIDE ( slc_to_host_chain_recycle = 0x40005f10 ); +PROVIDE ( software_reset = 0x4000264c ); +PROVIDE ( spi_flash_attach = 0x40004644 ); +PROVIDE ( srand = 0x400005f0 ); +PROVIDE ( strcmp = 0x4000bdc8 ); +PROVIDE ( strcpy = 0x4000bec8 ); +PROVIDE ( strlen = 0x4000bf4c ); +PROVIDE ( strncmp = 0x4000bfa8 ); +PROVIDE ( strncpy = 0x4000c0a0 ); +PROVIDE ( strstr = 0x4000e1e0 ); +PROVIDE ( timer_insert = 0x40002c64 ); +PROVIDE ( uartAttach = 0x4000383c ); +PROVIDE ( uart_baudrate_detect = 0x40003924 ); +PROVIDE ( uart_buff_switch = 0x400038a4 ); +PROVIDE ( uart_div_modify = 0x400039d8 ); +PROVIDE ( uart_rx_intr_handler = 0x40003bbc ); +PROVIDE ( uart_rx_one_char = 0x40003b8c ); +PROVIDE ( uart_rx_one_char_block = 0x40003b64 ); +PROVIDE ( uart_rx_readbuff = 0x40003ec8 ); +PROVIDE ( uart_tx_one_char = 0x40003b30 ); +PROVIDE ( wepkey_128 = 0x4000bc40 ); +PROVIDE ( wepkey_64 = 0x4000bb3c ); +PROVIDE ( xthal_bcopy = 0x40000688 ); +PROVIDE ( xthal_copy123 = 0x4000074c ); +PROVIDE ( xthal_get_ccompare = 0x4000dd4c ); +PROVIDE ( xthal_get_ccount = 0x4000dd38 ); +PROVIDE ( xthal_get_interrupt = 0x4000dd58 ); +PROVIDE ( xthal_get_intread = 0x4000dd58 ); +PROVIDE ( xthal_memcpy = 0x400006c4 ); +PROVIDE ( xthal_set_ccompare = 0x4000dd40 ); +PROVIDE ( xthal_set_intclear = 0x4000dd60 ); +PROVIDE ( xthal_spill_registers_into_stack_nw = 0x4000e320 ); +PROVIDE ( xthal_window_spill = 0x4000e324 ); +PROVIDE ( xthal_window_spill_nw = 0x4000e320 ); + +PROVIDE ( Te0 = 0x3fffccf0 ); +PROVIDE ( UartDev = 0x3fffde10 ); +PROVIDE ( flashchip = 0x3fffc714); diff --git a/hardware/esp8266com/esp8266/cores/esp8266/Arduino.h b/hardware/esp8266com/esp8266/cores/esp8266/Arduino.h index 89dbff873f..7d34df5a53 100644 --- a/hardware/esp8266com/esp8266/cores/esp8266/Arduino.h +++ b/hardware/esp8266com/esp8266/cores/esp8266/Arduino.h @@ -35,7 +35,6 @@ extern "C" { #include "stdlib_noniso.h" #include "binary.h" -#include "pgmspace.h" #include "esp8266_peri.h" #include "twi.h" @@ -52,6 +51,8 @@ void yield(void); #define INPUT_PULLDOWN 0x04 #define OUTPUT 0x01 #define OUTPUT_OPEN_DRAIN 0x03 +#define WAKEUP_PULLUP 0x05 +#define WAKEUP_PULLDOWN 0x07 #define SPECIAL 0xF8 //defaults to the usable BUSes uart0rx/tx uart1tx and hspi #define FUNCTION_0 0x08 #define FUNCTION_1 0x18 @@ -100,13 +101,29 @@ void yield(void); #define timer1_enabled() ((T1C & (1 << TCTE)) != 0) #define timer1_interrupted() ((T1C & (1 << TCIS)) != 0) +typedef void(*timercallback)(void); + void timer1_isr_init(void); void timer1_enable(uint8_t divider, uint8_t int_type, uint8_t reload); void timer1_disable(void); -void timer1_attachInterrupt(void (*userFunc)(void)); +void timer1_attachInterrupt(timercallback userFunc); void timer1_detachInterrupt(void); void timer1_write(uint32_t ticks); //maximum ticks 8388607 +// timer0 is a special CPU timer that has very high resolution but with +// limited control. +// it uses CCOUNT (ESP.GetCycleCount()) as the non-resetable timer counter +// it does not support divide, type, or reload flags +// it is auto-disabled when the compare value matches CCOUNT +// it is auto-enabled when the compare value changes +#define timer0_interrupted() (ETS_INTR_PENDING() & (_BV(ETS_COMPARE0_INUM))) +#define timer0_read() ((__extension__({uint32_t count;__asm__ __volatile__("esync; rsr %0,ccompare0":"=a" (count));count;}))) +#define timer0_write(count) __asm__ __volatile__("wsr %0,ccompare0; esync"::"a" (count) : "memory") + +void timer0_isr_init(void); +void timer0_attachInterrupt(timercallback userFunc); +void timer0_detachInterrupt(void); + // undefine stdlib's abs if encountered #ifdef abs #undef abs @@ -126,13 +143,13 @@ void ets_intr_unlock(); // level 15 will disable ALL interrupts, // level 0 will disable most software interrupts // -#define xt_disable_interrupts(state, level) __asm__ __volatile__("rsil %0," __STRINGIFY(level) "; esync; isync; dsync" : "=a" (state)) -#define xt_enable_interrupts(state) __asm__ __volatile__("wsr %0,ps; esync" :: "a" (state) : "memory") +#define xt_disable_interrupts(state, level) __asm__ __volatile__("rsil %0," __STRINGIFY(level) : "=a" (state)) +#define xt_enable_interrupts(state) __asm__ __volatile__("wsr %0,ps; isync" :: "a" (state) : "memory") extern uint32_t interruptsState; #define interrupts() xt_enable_interrupts(interruptsState) -#define noInterrupts() __asm__ __volatile__("rsil %0,15; esync; isync; dsync" : "=a" (interruptsState)) +#define noInterrupts() __asm__ __volatile__("rsil %0,15" : "=a" (interruptsState)) #define clockCyclesPerMicrosecond() ( F_CPU / 1000000L ) #define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() ) @@ -171,6 +188,7 @@ int analogRead(uint8_t); void analogReference(uint8_t mode); void analogWrite(uint8_t, int); void analogWriteFreq(uint32_t freq); +void analogWriteRange(uint32_t range); unsigned long millis(void); unsigned long micros(void); @@ -191,6 +209,7 @@ void loop(void); // This comes from the pins_*.c file for the active board configuration. #define digitalPinToPort(pin) (0) #define digitalPinToBitMask(pin) (1UL << (pin)) +#define digitalPinToTimer(pin) (0) #define portOutputRegister(port) ((volatile uint32_t*) GPO) #define portInputRegister(port) ((volatile uint32_t*) GPI) #define portModeRegister(port) ((volatile uint32_t*) GPE) @@ -198,6 +217,7 @@ void loop(void); #define NOT_A_PIN -1 #define NOT_A_PORT -1 #define NOT_AN_INTERRUPT -1 +#define NOT_ON_TIMER 0 #ifdef __cplusplus } // extern "C" @@ -205,6 +225,8 @@ void loop(void); #ifdef __cplusplus +#include "pgmspace.h" + #include "WCharacter.h" #include "WString.h" diff --git a/hardware/esp8266com/esp8266/cores/esp8266/Esp.cpp b/hardware/esp8266com/esp8266/cores/esp8266/Esp.cpp index 67e6a41af5..408487dabd 100644 --- a/hardware/esp8266com/esp8266/cores/esp8266/Esp.cpp +++ b/hardware/esp8266com/esp8266/cores/esp8266/Esp.cpp @@ -19,11 +19,19 @@ */ #include "Arduino.h" +#include "flash_utils.h" +#include "eboot_command.h" +#include extern "C" { #include "user_interface.h" + +extern struct rst_info resetInfo; } + +// #define DEBUG_SERIAL Serial + //extern "C" void ets_wdt_init(uint32_t val); extern "C" void ets_wdt_enable(void); extern "C" void ets_wdt_disable(void); @@ -277,3 +285,157 @@ uint32_t EspClass::getFlashChipSizeByChipId(void) { return 0; } } + +String EspClass::getResetInfo(void) { + if(resetInfo.flag != 0) { + char buff[150]; + sprintf(&buff[0], "Fatal exception:%d flag:%d epc1:0x%08x epc2:0x%08x epc3:0x%08x excvaddr:0x%08x depc:0x%08x", resetInfo.exccause, resetInfo.flag, resetInfo.epc1, resetInfo.epc2, resetInfo.epc3, resetInfo.excvaddr, resetInfo.depc); + return String(buff); + } + return String("flag: 0"); +} + +struct rst_info * EspClass::getResetInfoPtr(void) { + return &resetInfo; +} + +bool EspClass::eraseConfig(void) { + bool ret = true; + size_t cfgAddr = (ESP.getFlashChipSize() - 0x4000); + size_t cfgSize = (8*1024); + + noInterrupts(); + while(cfgSize) { + + if(spi_flash_erase_sector((cfgAddr / SPI_FLASH_SEC_SIZE)) != SPI_FLASH_RESULT_OK) { + ret = false; + } + + cfgSize -= SPI_FLASH_SEC_SIZE; + cfgAddr += SPI_FLASH_SEC_SIZE; + } + interrupts(); + + return ret; +} + +uint32_t EspClass::getSketchSize() { + static uint32_t result = 0; + if (result) + return result; + + image_header_t image_header; + uint32_t pos = APP_START_OFFSET; + if (spi_flash_read(pos, (uint32_t*) &image_header, sizeof(image_header))) { + return 0; + } + pos += sizeof(image_header); +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.printf("num_segments=%u\r\n", image_header.num_segments); +#endif + for (uint32_t section_index = 0; + section_index < image_header.num_segments; + ++section_index) + { + section_header_t section_header = {0}; + if (spi_flash_read(pos, (uint32_t*) §ion_header, sizeof(section_header))) { + return 0; + } + pos += sizeof(section_header); + pos += section_header.size; +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.printf("section=%u size=%u pos=%u\r\n", section_index, section_header.size, pos); +#endif + } + result = pos; + return result; +} + +extern "C" uint32_t _SPIFFS_start; + +uint32_t EspClass::getFreeSketchSpace() { + + uint32_t usedSize = getSketchSize(); + // round one sector up + uint32_t freeSpaceStart = (usedSize + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1)); + uint32_t freeSpaceEnd = (uint32_t)&_SPIFFS_start - 0x40200000; + +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.printf("usedSize=%u freeSpaceStart=%u freeSpaceEnd=%u\r\n", usedSize, freeSpaceStart, freeSpaceEnd); +#endif + return freeSpaceEnd - freeSpaceStart; +} + +bool EspClass::updateSketch(Stream& in, uint32_t size) { + + if (size > getFreeSketchSpace()) + return false; + + uint32_t usedSize = getSketchSize(); + uint32_t freeSpaceStart = (usedSize + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1)); + uint32_t roundedSize = (size + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1)); + +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.printf("erase @0x%x size=0x%x\r\n", freeSpaceStart, roundedSize); +#endif + + noInterrupts(); + int rc = SPIEraseAreaEx(freeSpaceStart, roundedSize); + interrupts(); + if (rc) + return false; + +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.println("erase done"); +#endif + + uint32_t addr = freeSpaceStart; + uint32_t left = size; + + const uint32_t bufferSize = FLASH_SECTOR_SIZE; + std::unique_ptr buffer(new uint8_t[bufferSize]); + +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.println("writing"); +#endif + while (left > 0) { + size_t willRead = (left < bufferSize) ? left : bufferSize; + size_t rd = in.readBytes(buffer.get(), willRead); + if (rd != willRead) { +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.println("stream read failed"); +#endif + return false; + } + + noInterrupts(); + rc = SPIWrite(addr, buffer.get(), willRead); + interrupts(); + if (rc) { +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.println("write failed"); +#endif + return false; + } + + addr += willRead; + left -= willRead; +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.print("."); +#endif + } + +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.println("\r\nrestarting"); +#endif + eboot_command ebcmd; + ebcmd.action = ACTION_COPY_RAW; + ebcmd.args[0] = freeSpaceStart; + ebcmd.args[1] = 0x00000; + ebcmd.args[2] = size; + eboot_command_write(&ebcmd); + + ESP.restart(); + return true; // never happens +} + diff --git a/hardware/esp8266com/esp8266/cores/esp8266/Esp.h b/hardware/esp8266com/esp8266/cores/esp8266/Esp.h index 5e356459e1..5cc75449d0 100644 --- a/hardware/esp8266com/esp8266/cores/esp8266/Esp.h +++ b/hardware/esp8266com/esp8266/cores/esp8266/Esp.h @@ -69,42 +69,51 @@ class EspClass { // note: setting the timeout value is not implemented at the moment void wdtEnable(WDTO_t timeout_ms = WDTO_0MS); - void wdtDisable(void); - void wdtFeed(void); + void wdtDisable(); + void wdtFeed(); void deepSleep(uint32_t time_us, WakeMode mode = WAKE_RF_DEFAULT); - void reset(void); - void restart(void); + void reset(); + void restart(); - uint16_t getVcc(void); - uint32_t getFreeHeap(void); + uint16_t getVcc(); + uint32_t getFreeHeap(); - uint32_t getChipId(void); + uint32_t getChipId(); - const char * getSdkVersion(void); + const char * getSdkVersion(); - uint8_t getBootVersion(void); - uint8_t getBootMode(void); + uint8_t getBootVersion(); + uint8_t getBootMode(); - uint8_t getCpuFreqMHz(void); + uint8_t getCpuFreqMHz(); - uint32_t getFlashChipId(void); + uint32_t getFlashChipId(); //gets the actual chip size based on the flash id - uint32_t getFlashChipRealSize(void); + uint32_t getFlashChipRealSize(); //gets the size of the flash as set by the compiler - uint32_t getFlashChipSize(void); - uint32_t getFlashChipSpeed(void); - FlashMode_t getFlashChipMode(void); - uint32_t getFlashChipSizeByChipId(void); + uint32_t getFlashChipSize(); + uint32_t getFlashChipSpeed(); + FlashMode_t getFlashChipMode(); + uint32_t getFlashChipSizeByChipId(); - inline uint32_t getCycleCount(void); + uint32_t getSketchSize(); + uint32_t getFreeSketchSpace(); + bool updateSketch(Stream& in, uint32_t size); + + String getResetInfo(); + struct rst_info * getResetInfoPtr(); + + bool eraseConfig(); + + inline uint32_t getCycleCount(); }; -uint32_t EspClass::getCycleCount(void) +uint32_t EspClass::getCycleCount() { uint32_t ccount; - __asm__ __volatile__("rsr %0,ccount":"=a" (ccount)); + __asm__ __volatile__("esync; rsr %0,ccount":"=a" (ccount)); return ccount; } diff --git a/hardware/esp8266com/esp8266/cores/esp8266/HardwareSerial.cpp b/hardware/esp8266com/esp8266/cores/esp8266/HardwareSerial.cpp index ac56919ca7..970b16c50a 100644 --- a/hardware/esp8266com/esp8266/cores/esp8266/HardwareSerial.cpp +++ b/hardware/esp8266com/esp8266/cores/esp8266/HardwareSerial.cpp @@ -262,7 +262,7 @@ void uart_set_baudrate(uart_t* uart, int baud_rate) { if(uart == 0) return; uart->baud_rate = baud_rate; - USD(uart->uart_nr) = (80000000UL / uart->baud_rate); + USD(uart->uart_nr) = (ESP8266_CLOCK / uart->baud_rate); } int uart_get_baudrate(uart_t* uart) { @@ -359,7 +359,7 @@ void uart_swap(uart_t* uart) { if(uart->txPin == 1 && uart->rxPin == 3) { pinMode(15, FUNCTION_4); //TX pinMode(13, FUNCTION_4); //RX - USWAP |= (1 << USWAP0); + IOSWAP |= (1 << IOSWAPU0); pinMode(1, INPUT); //TX pinMode(3, INPUT); //RX uart->rxPin = 13; @@ -367,7 +367,7 @@ void uart_swap(uart_t* uart) { } else { pinMode(1, SPECIAL); //TX pinMode(3, SPECIAL); //RX - USWAP &= ~(1 << USWAP0); + IOSWAP &= ~(1 << IOSWAPU0); pinMode(15, INPUT); //TX pinMode(13, INPUT); //RX uart->rxPin = 3; diff --git a/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_eboot_command.c b/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_eboot_command.c new file mode 100644 index 0000000000..60c92bf189 --- /dev/null +++ b/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_eboot_command.c @@ -0,0 +1,88 @@ +/* + core_esp8266_eboot_command.c - interface to the eboot bootloader + + Copyright (c) 2015 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include "eboot_command.h" + +uint32_t crc_update(uint32_t crc, const uint8_t *data, size_t length) +{ + uint32_t i; + bool bit; + uint8_t c; + + while (length--) { + c = *data++; + for (i = 0x80; i > 0; i >>= 1) { + bit = crc & 0x80000000; + if (c & i) { + bit = !bit; + } + crc <<= 1; + if (bit) { + crc ^= 0x04c11db7; + } + } + } + return crc; +} + +uint32_t eboot_command_calculate_crc32(const struct eboot_command* cmd) +{ + return crc_update(0xffffffff, (const uint8_t*) cmd, + offsetof(struct eboot_command, crc32)); +} + +int eboot_command_read(struct eboot_command* cmd) +{ + const uint32_t dw_count = sizeof(struct eboot_command) / sizeof(uint32_t); + uint32_t* dst = (uint32_t *) cmd; + for (uint32_t i = 0; i < dw_count; ++i) { + dst[i] = RTC_MEM[i]; + } + + uint32_t crc32 = eboot_command_calculate_crc32(cmd); + if (cmd->magic & EBOOT_MAGIC_MASK != EBOOT_MAGIC || + cmd->crc32 != crc32) { + return 1; + } + + return 0; +} + +void eboot_command_write(struct eboot_command* cmd) +{ + cmd->magic = EBOOT_MAGIC; + cmd->crc32 = eboot_command_calculate_crc32(cmd); + + const uint32_t dw_count = sizeof(struct eboot_command) / sizeof(uint32_t); + const uint32_t* src = (const uint32_t *) cmd; + for (uint32_t i = 0; i < dw_count; ++i) { + RTC_MEM[i] = src[i]; + } +} + +void eboot_command_clear() +{ + RTC_MEM[offsetof(struct eboot_command, magic) / sizeof(uint32_t)] = 0; + RTC_MEM[offsetof(struct eboot_command, crc32) / sizeof(uint32_t)] = 0; +} + diff --git a/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_flash_utils.c b/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_flash_utils.c new file mode 100644 index 0000000000..6f8a34f41c --- /dev/null +++ b/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_flash_utils.c @@ -0,0 +1,64 @@ +/* + core_esp8266_flash_utils.c - flash and binary image helpers + + Copyright (c) 2015 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include +#include +#include +#include "flash_utils.h" + + +int SPIEraseAreaEx(const uint32_t start, const uint32_t size) +{ + if (start & (FLASH_SECTOR_SIZE - 1) != 0) { + return 1; + } + + const uint32_t sectors_per_block = FLASH_BLOCK_SIZE / FLASH_SECTOR_SIZE; + uint32_t current_sector = start / FLASH_SECTOR_SIZE; + uint32_t sector_count = (size + FLASH_SECTOR_SIZE - 1) / FLASH_SECTOR_SIZE; + const uint32_t end = current_sector + sector_count; + + for (; current_sector < end && (current_sector & (sectors_per_block-1)); + ++current_sector, --sector_count) { + if (SPIEraseSector(current_sector)) { + return 2; + } + } + + for (;current_sector + sectors_per_block <= end; + current_sector += sectors_per_block, + sector_count -= sectors_per_block) { + if (SPIEraseBlock(current_sector / sectors_per_block)) { + return 3; + } + } + + for (; current_sector < end; + ++current_sector, --sector_count) { + if (SPIEraseSector(current_sector)) { + return 4; + } + } + + return 0; +} + diff --git a/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_main.cpp b/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_main.cpp index d45165443c..01e5ed96b4 100644 --- a/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_main.cpp +++ b/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_main.cpp @@ -34,6 +34,8 @@ extern "C" { #define LOOP_TASK_PRIORITY 0 #define LOOP_QUEUE_SIZE 1 +struct rst_info resetInfo; + int atexit(void (*func)()) { return 0; } @@ -118,6 +120,15 @@ void init_done() { extern "C" { void user_init(void) { + uart_div_modify(0, UART_CLK_FREQ / (74480)); + + system_rtc_mem_read(0, &resetInfo, sizeof(struct rst_info)); + if(resetInfo.flag == WDT_RST_FLAG || resetInfo.flag == EXP_RST_FLAG) { + os_printf("Last Reset:\n - flag=%d\n - Fatal exception (%d):\n - epc1=0x%08x,epc2=0x%08x,epc3=0x%08x,excvaddr=0x%08x,depc=0x%08x\n", resetInfo.flag, resetInfo.exccause, resetInfo.epc1, resetInfo.epc2, resetInfo.epc3, resetInfo.excvaddr, resetInfo.depc); + } + struct rst_info info = { 0 }; + system_rtc_mem_write(0, &info, sizeof(struct rst_info)); + uart_div_modify(0, UART_CLK_FREQ / (115200)); init(); diff --git a/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_si2c.c b/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_si2c.c index cff2809d3c..d825c4445b 100644 --- a/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_si2c.c +++ b/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_si2c.c @@ -44,17 +44,19 @@ static unsigned char twi_sda, twi_scl; void twi_setClock(unsigned int freq){ #if F_CPU == FCPU80 - if(freq <= 100000) twi_dcount = 18;//about 100KHz + if(freq <= 100000) twi_dcount = 19;//about 100KHz else if(freq <= 200000) twi_dcount = 8;//about 200KHz - else if(freq <= 300000) twi_dcount = 4;//about 300KHz - else if(freq <= 400000) twi_dcount = 2;//about 370KHz - else twi_dcount = 1;//about 450KHz + else if(freq <= 300000) twi_dcount = 3;//about 300KHz + else if(freq <= 400000) twi_dcount = 1;//about 400KHz + else twi_dcount = 1;//about 400KHz #else if(freq <= 100000) twi_dcount = 32;//about 100KHz - else if(freq <= 200000) twi_dcount = 16;//about 200KHz + else if(freq <= 200000) twi_dcount = 14;//about 200KHz else if(freq <= 300000) twi_dcount = 8;//about 300KHz - else if(freq <= 400000) twi_dcount = 4;//about 370KHz - else twi_dcount = 2;//about 450KHz + else if(freq <= 400000) twi_dcount = 5;//about 400KHz + else if(freq <= 500000) twi_dcount = 3;//about 500KHz + else if(freq <= 600000) twi_dcount = 2;//about 600KHz + else twi_dcount = 1;//about 700KHz #endif } @@ -109,7 +111,7 @@ static bool twi_write_bit(bool bit) { twi_delay(twi_dcount+1); SCL_HIGH(); while (SCL_READ() == 0 && (i++) < TWI_CLOCK_STRETCH);// Clock stretching (up to 100us) - twi_delay(twi_dcount+1); + twi_delay(twi_dcount); return true; } @@ -117,7 +119,7 @@ static bool twi_read_bit(void) { unsigned int i = 0; SCL_LOW(); SDA_HIGH(); - twi_delay(twi_dcount+1); + twi_delay(twi_dcount+2); SCL_HIGH(); while (SCL_READ() == 0 && (i++) < TWI_CLOCK_STRETCH);// Clock stretching (up to 100us) bool bit = SDA_READ(); diff --git a/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_timer.c b/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_timer.c index bfdd3692cf..819c5f9901 100644 --- a/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_timer.c +++ b/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_timer.c @@ -20,21 +20,26 @@ */ #include "wiring_private.h" #include "pins_arduino.h" + #include "c_types.h" +#include "ets_sys.h" + +// ------------------------------------------------------------------ - +// timer 1 -void (*timer1_user_cb)(void); +static volatile timercallback timer1_user_cb = NULL; void timer1_isr_handler(void *para){ - if((T1C & ((1 << TCAR) | (1 << TCIT))) == 0) TEIE &= ~TEIE1;//edge int disable + if ((T1C & ((1 << TCAR) | (1 << TCIT))) == 0) TEIE &= ~TEIE1;//edge int disable T1I = 0; - if(timer1_user_cb) timer1_user_cb(); + if (timer1_user_cb) timer1_user_cb(); } void timer1_isr_init(){ ETS_FRC_TIMER1_INTR_ATTACH(timer1_isr_handler, NULL); } -void timer1_attachInterrupt(void (*userFunc)(void)) { +void timer1_attachInterrupt(timercallback userFunc) { timer1_user_cb = userFunc; ETS_FRC1_INTR_ENABLE(); } @@ -51,11 +56,39 @@ void timer1_enable(uint8_t divider, uint8_t int_type, uint8_t reload){ } void timer1_write(uint32_t ticks){ - T1L = ((ticks) & 0x7FFFFF); - if((T1C & (1 << TCIT)) == 0) TEIE |= TEIE1;//edge int enable + T1L = ((ticks)& 0x7FFFFF); + if ((T1C & (1 << TCIT)) == 0) TEIE |= TEIE1;//edge int enable } void timer1_disable(){ T1C = 0; T1I = 0; } + +//------------------------------------------------------------------- +// timer 0 + +static volatile timercallback timer0_user_cb = NULL; + +void timer0_isr_handler(void* para){ + if (timer0_user_cb) { + timer0_user_cb(); + } +} + +void timer0_isr_init(){ + ETS_CCOMPARE0_INTR_ATTACH(timer0_isr_handler, NULL); +} + +void timer0_attachInterrupt(timercallback userFunc) { + timer0_user_cb = userFunc; + ETS_CCOMPARE0_ENABLE(); +} + +void timer0_detachInterrupt() { + timer0_user_cb = NULL; + ETS_CCOMPARE0_DISABLE(); +} + + + diff --git a/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_wiring_analog.c b/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_wiring_analog.c index 53451b7134..74d5dd5d3e 100644 --- a/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_wiring_analog.c +++ b/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_wiring_analog.c @@ -17,17 +17,18 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + + 18/06/2015 analogRead bugfix by Testato */ + #include "wiring_private.h" #include "pins_arduino.h" -extern uint16_t readvdd33(void); - -void analogReference(uint8_t mode) {} extern int __analogRead(uint8_t pin) { if(pin == 17){ - return readvdd33() >> 2; // readvdd33 is 12 bit + return system_adc_read(); } return digitalRead(pin) * 1023; } diff --git a/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_wiring_digital.c b/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_wiring_digital.c index 54c2b557b1..354f2b9500 100644 --- a/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_wiring_digital.c +++ b/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_wiring_digital.c @@ -51,6 +51,16 @@ extern void __pinMode(uint8_t pin, uint8_t mode) { } else if(mode == INPUT_PULLDOWN) { GPF(pin) |= (1 << GPFPD); // Enable Pulldown } + } else if(mode == WAKEUP_PULLUP || mode == WAKEUP_PULLDOWN){ + GPF(pin) = GPFFS(GPFFS_GPIO(pin));//Set mode to GPIO + GPEC = (1 << pin); //Disable + if(mode == WAKEUP_PULLUP) { + GPF(pin) |= (1 << GPFPU); // Enable Pullup + GPC(pin) = (1 << GPCD) | (4 << GPCI) | (1 << GPCWE); //SOURCE(GPIO) | DRIVER(OPEN_DRAIN) | INT_TYPE(LOW) | WAKEUP_ENABLE(ENABLED) + } else { + GPF(pin) |= (1 << GPFPD); // Enable Pulldown + GPC(pin) = (1 << GPCD) | (5 << GPCI) | (1 << GPCWE); //SOURCE(GPIO) | DRIVER(OPEN_DRAIN) | INT_TYPE(HIGH) | WAKEUP_ENABLE(ENABLED) + } } } else if(pin == 16){ GPF16 = GP16FFS(GPFFS_GPIO(pin));//Set mode to GPIO @@ -111,7 +121,11 @@ void interrupt_handler(void *arg) { while(!(changedbits & (1 << i))) i++; changedbits &= ~(1 << i); interrupt_handler_t *handler = &interrupt_handlers[i]; - if(((handler->mode & 1) == digitalRead(i)) && handler->fn) handler->fn(); + if (handler->fn && + (handler->mode == CHANGE || + (handler->mode & 1) == digitalRead(i))) { + handler->fn(); + } } ETS_GPIO_INTR_ENABLE(); } diff --git a/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_wiring_pwm.c b/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_wiring_pwm.c index b175f6e553..d102f93d65 100644 --- a/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_wiring_pwm.c +++ b/hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_wiring_pwm.c @@ -27,6 +27,7 @@ uint32_t pwm_mask = 0; uint16_t pwm_values[17] = {0,}; uint32_t pwm_freq = 1000; +uint32_t pwm_range = PWMRANGE; uint32_t pwm_multiplier = 0; uint16_t pwm_steps[17]; @@ -71,7 +72,7 @@ void prep_pwm_steps(){ for(i=0; i<17; i++){ if((pwm_mask & (1 << i)) != 0 && pwm_values[i] != 0) pwm_temp_steps[pwm_temp_steps_len++] = pwm_values[i]; } - pwm_temp_steps[pwm_temp_steps_len++] = PWMRANGE; + pwm_temp_steps[pwm_temp_steps_len++] = pwm_range; pwm_temp_steps_len = pwm_sort_array(pwm_temp_steps, pwm_temp_steps_len) - 1; for(i=0; i + +#ifdef __cplusplus +extern "C" { +#endif + +#define RTC_MEM ((volatile uint32_t*)0x60001200) + +enum action_t { + ACTION_COPY_RAW = 0x00000001, + ACTION_LOAD_APP = 0xffffffff +}; + +#define EBOOT_MAGIC 0xeb001000 +#define EBOOT_MAGIC_MASK 0xfffff000 + +struct eboot_command { + uint32_t magic; + enum action_t action; + uint32_t args[29]; + uint32_t crc32; +}; + + +int eboot_command_read(struct eboot_command* cmd); +void eboot_command_write(struct eboot_command* cmd); +void eboot_command_clear(); + +#ifdef __cplusplus +} +#endif + +#endif //EBOOT_COMMAND_H diff --git a/hardware/esp8266com/esp8266/cores/esp8266/esp8266_peri.h b/hardware/esp8266com/esp8266/cores/esp8266/esp8266_peri.h index d3841740b6..c1f4624c9b 100644 --- a/hardware/esp8266com/esp8266/cores/esp8266/esp8266_peri.h +++ b/hardware/esp8266com/esp8266/cores/esp8266/esp8266_peri.h @@ -25,6 +25,15 @@ #define ESP8266_REG(addr) *((volatile uint32_t *)(0x60000000+(addr))) #define ESP8266_DREG(addr) *((volatile uint32_t *)(0x3FF00000+(addr))) +#define ESP8266_CLOCK 80000000UL + +//CPU Register +#define CPU2X ESP8266_DREG(0x14) //when bit 0 is set, F_CPU = 160MHz + +//OTP Registers +#define MAC0 ESP8266_DREG(0x50) +#define MAC1 ESP8266_DREG(0x54) +#define CHIPID ESP8266_DREG(0x58) //GPIO (0-15) Control Registers #define GPO ESP8266_REG(0x300) //GPIO_OUT R/W (Output Level) @@ -149,9 +158,20 @@ static uint8_t esp8266_gpioToFn[16] = {0x34, 0x18, 0x38, 0x14, 0x3C, 0x40, 0x1C, #define TCIT 0 //Interrupt Type 0:edge, 1:level -//UART SWAP Register -#define USWAP ESP8266_DREG(0x28) -#define USWAP0 2 //BIT 2 swaps UART 0 +//IO SWAP Register +#define IOSWAP ESP8266_DREG(0x28) +#define IOSWAPU 0 //Swaps UART +#define IOSWAPS 1 //Swaps SPI +#define IOSWAPU0 2 //Swaps UART 0 pins (u0rxd <-> u0cts), (u0txd <-> u0rts) +#define IOSWAPU1 3 //Swaps UART 1 pins (u1rxd <-> u1cts), (u1txd <-> u1rts) +#define IOSWAPHS 5 //Sets HSPI with higher prio +#define IOSWAP2HS 6 //Sets Two SPI Masters on HSPI +#define IOSWAP2CS 7 //Sets Two SPI Masters on CSPI + +//UART INT Status +#define UIS ESP8266_DREG(0x20020) +#define UIS0 0 +#define UIS1 2 //UART 0 Registers #define U0F ESP8266_REG(0x000) //UART FIFO @@ -216,9 +236,9 @@ static uint8_t esp8266_gpioToFn[16] = {0x34, 0x18, 0x38, 0x14, 0x3C, 0x40, 0x1C, #define UIFF 0 //RX FIFO Full //UART STATUS Registers Bits -#define USTX 31 //TX PIN Level -#define USRTS 30 //RTS PIN Level -#define USDTR 39 //DTR PIN Level +#define USTX 31 //TX PIN Level +#define USRTS 30 //RTS PIN Level +#define USDTR 39 //DTR PIN Level #define USTXC 16 //TX FIFO COUNT (8bit) #define USRXD 15 //RX PIN Level #define USCTS 14 //CTS PIN Level @@ -226,35 +246,39 @@ static uint8_t esp8266_gpioToFn[16] = {0x34, 0x18, 0x38, 0x14, 0x3C, 0x40, 0x1C, #define USRXC 0 //RX FIFO COUNT (8bit) //UART CONF0 Registers Bits -#define UCDTRI 24 //Invert DTR -#define UCRTSI 23 //Invert RTS -#define UCTXI 22 //Invert TX -#define UCDSRI 21 //Invert DSR -#define UCCTSI 20 //Invert CTS -#define UCRXI 19 //Invert RX +#define UCDTRI 24 //Invert DTR +#define UCRTSI 23 //Invert RTS +#define UCTXI 22 //Invert TX +#define UCDSRI 21 //Invert DSR +#define UCCTSI 20 //Invert CTS +#define UCRXI 19 //Invert RX #define UCTXRST 18 //Reset TX FIFO #define UCRXRST 17 //Reset RX FIFO #define UCTXHFE 15 //TX Harware Flow Enable -#define UCLBE 14 //LoopBack Enable -#define UCBRK 8 //Send Break on the TX line +#define UCLBE 14 //LoopBack Enable +#define UCBRK 8 //Send Break on the TX line #define UCSWDTR 7 //Set this bit to assert DTR #define UCSWRTS 6 //Set this bit to assert RTS -#define UCSBN 4 //StopBits Count (2bit) 0:disable, 1:1bit, 2:1.5bit, 3:2bit -#define UCBN 2 //DataBits Count (2bin) 0:5bit, 1:6bit, 2:7bit, 3:8bit -#define UCPAE 1 //Parity Enable -#define UCPA 0 //Parity 0:even, 1:odd +#define UCSBN 4 //StopBits Count (2bit) 0:disable, 1:1bit, 2:1.5bit, 3:2bit +#define UCBN 2 //DataBits Count (2bin) 0:5bit, 1:6bit, 2:7bit, 3:8bit +#define UCPAE 1 //Parity Enable +#define UCPA 0 //Parity 0:even, 1:odd //UART CONF1 Registers Bits -#define UCTOE 31 //RX TimeOut Enable -#define UCTOT 24 //RX TimeOut Treshold (7bit) +#define UCTOE 31 //RX TimeOut Enable +#define UCTOT 24 //RX TimeOut Treshold (7bit) #define UCRXHFE 23 //RX Harware Flow Enable #define UCRXHFT 16 //RX Harware Flow Treshold (7bit) -#define UCFET 8 //TX FIFO Empty Treshold (7bit) -#define UCFFT 0 //RX FIFO Full Treshold (7bit) +#define UCFET 8 //TX FIFO Empty Treshold (7bit) +#define UCFFT 0 //RX FIFO Full Treshold (7bit) + +//WDT Feed (the dog) Register +#define WDTFEED ESP8266_REG(0x914) +#define WDT_FEED() (WDTFEED = 0x73) -//WDT Register used for UART -#define WDTRST ESP8266_REG(0x914) -#define WDT_RESET() (WDTRST = 0x73) +//SPI_READY +#define SPIRDY ESP8266_DREG(0x0C) +#define SPI_BUSY 9 //wait SPI idle //SPI0 Registers (SPI0 is used for the flash) #define SPI0CMD ESP8266_REG(0x200) diff --git a/hardware/esp8266com/esp8266/cores/esp8266/flash_utils.h b/hardware/esp8266com/esp8266/cores/esp8266/flash_utils.h new file mode 100644 index 0000000000..4e5f2120b1 --- /dev/null +++ b/hardware/esp8266com/esp8266/cores/esp8266/flash_utils.h @@ -0,0 +1,63 @@ +/* + flash_utils.h - Flash access function and data structures + Copyright (c) 2015 Ivan Grokhotkov. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef FLASH_UTILS_H +#define FLASH_UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +int SPIEraseBlock(uint32_t block); +int SPIEraseSector(uint32_t sector); +int SPIRead(uint32_t addr, void *dest, size_t size); +int SPIWrite(uint32_t addr, void *src, size_t size); +int SPIEraseAreaEx(const uint32_t start, const uint32_t size); + +#define FLASH_SECTOR_SIZE 0x1000 +#define FLASH_BLOCK_SIZE 0x10000 +#define APP_START_OFFSET 0x1000 + +typedef struct { + unsigned char magic; + unsigned char num_segments; + + /* SPI Flash Interface (0 = QIO, 1 = QOUT, 2 = DIO, 0x3 = DOUT) */ + unsigned char flash_mode; + + /* High four bits: 0 = 512K, 1 = 256K, 2 = 1M, 3 = 2M, 4 = 4M, + Low four bits: 0 = 40MHz, 1= 26MHz, 2 = 20MHz, 0xf = 80MHz */ + unsigned char flash_size_freq; + + uint32_t entry; +} image_header_t; + + +typedef struct { + uint32_t address; + uint32_t size; +} section_header_t; + +#ifdef __cplusplus +} +#endif + + +#endif //FLASH_UTILS_H diff --git a/hardware/esp8266com/esp8266/cores/esp8266/libc_replacements.c b/hardware/esp8266com/esp8266/cores/esp8266/libc_replacements.c index 519ea233ae..39ee925a43 100644 --- a/hardware/esp8266com/esp8266/cores/esp8266/libc_replacements.c +++ b/hardware/esp8266com/esp8266/cores/esp8266/libc_replacements.c @@ -169,60 +169,65 @@ char* ICACHE_FLASH_ATTR strncat(char * dest, const char * src, size_t n) { return dest; } +char* ICACHE_FLASH_ATTR strtok_r(char* s, const char* delim, char** last) { + const char* spanp; + char* tok; + char c; + char sc; + + if (s == NULL && (s = *last) == NULL) { + return (NULL); + } -char* ICACHE_FLASH_ATTR strtok_r(char * str, const char * delimiters, char ** temp) { - static char * ret = NULL; - char * start = NULL; - char * end = NULL; - uint32_t size = 0; - if(str == NULL) { - if(temp == NULL) { - return NULL; + // Skip (span) leading delimiters + // +cont: + c = *s++; + for (spanp = delim; (sc = *spanp++) != 0;) { + if (c == sc) { + goto cont; } - start = *temp; - } else { - start = str; } - if(start == NULL) { - return NULL; + // check for no delimiters left + // + if (c == '\0') { + *last = NULL; + return (NULL); } - if(delimiters == NULL) { - return NULL; - } + tok = s - 1; - end = start; - while(1) { - for(uint16_t i = 0; i < strlen(delimiters); i++) { - if(*end == *(delimiters + i)) { - break; + // Scan token + // Note that delim must have one NUL; we stop if we see that, too. + // + for (;;) { + c = *s++; + spanp = (char *)delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) { + s = NULL; + } + else { + s[-1] = '\0'; + } + *last = s; + return (tok); } - } - end++; - if(*end == 0x00) { - break; - } - } - *temp = end; - - if(ret != NULL) { - free(ret); + } while (sc != 0); } - size = (end - start); - ret = (char *) malloc(size); - strncpy(ret, start, size); - return ret; + // NOTREACHED EVER } -char* ICACHE_FLASH_ATTR strtok(char * str, const char * delimiters) { - static char * ret = NULL; - ret = strtok_r(str, delimiters, &ret); - return ret; +char* ICACHE_FLASH_ATTR strtok(char* s, const char* delim) { + static char* last; + + return (strtok_r(s, delim, &last)); } int ICACHE_FLASH_ATTR strcasecmp(const char * str1, const char * str2) { diff --git a/hardware/esp8266com/esp8266/cores/esp8266/pgmspace.cpp b/hardware/esp8266com/esp8266/cores/esp8266/pgmspace.cpp index 84af6264b3..c2b5781f1f 100644 --- a/hardware/esp8266com/esp8266/cores/esp8266/pgmspace.cpp +++ b/hardware/esp8266com/esp8266/cores/esp8266/pgmspace.cpp @@ -1,32 +1,32 @@ /* -pgmspace.cpp - string functions that support PROGMEM -Copyright (c) 2015 Michael C. Miller. All right reserved. + pgmspace.cpp - string functions that support PROGMEM + Copyright (c) 2015 Michael C. Miller. All right reserved. -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. -This library 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 -Lesser General Public License for more details. + This library 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 + Lesser General Public License for more details. -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ #include #include "pgmspace.h" -size_t ICACHE_FLASH_ATTR strnlen_P(const char* s, size_t size) { +size_t strnlen_P(const char* s, size_t size) { const char* cp; for (cp = s; size != 0 && pgm_read_byte(cp) != '\0'; cp++, size--); - return (size_t)(cp - s); + return (size_t) (cp - s); } -void* ICACHE_FLASH_ATTR memcpy_P(void* dest, const void* src, size_t count) { +void* memcpy_P(void* dest, const void* src, size_t count) { const uint8_t* read = reinterpret_cast(src); uint8_t* write = reinterpret_cast(dest); @@ -39,7 +39,7 @@ void* ICACHE_FLASH_ATTR memcpy_P(void* dest, const void* src, size_t count) { return dest; } -char* ICACHE_FLASH_ATTR strncpy_P(char* dest, const char* src, size_t size) { +char* strncpy_P(char* dest, const char* src, size_t size) { const char* read = src; char* write = dest; char ch = '.'; @@ -48,19 +48,19 @@ char* ICACHE_FLASH_ATTR strncpy_P(char* dest, const char* src, size_t size) { ch = pgm_read_byte(read++); *write++ = ch; size--; - } + } return dest; } -char* ICACHE_FLASH_ATTR strncat_P(char* dest, const char* src, size_t size) { +char* strncat_P(char* dest, const char* src, size_t size) { char* write = dest; while (*write != '\0') { write++; } - + const char* read = src; char ch = '.'; @@ -80,7 +80,7 @@ char* ICACHE_FLASH_ATTR strncat_P(char* dest, const char* src, size_t size) { return dest; } -int ICACHE_FLASH_ATTR strncmp_P(const char* str1, const char* str2P, size_t size) { +int strncmp_P(const char* str1, const char* str2P, size_t size) { int result = 0; while (size > 0) @@ -99,7 +99,7 @@ int ICACHE_FLASH_ATTR strncmp_P(const char* str1, const char* str2P, size_t size return result; } -int ICACHE_FLASH_ATTR strncasecmp_P(const char* str1, const char* str2P, size_t size) { +int strncasecmp_P(const char* str1, const char* str2P, size_t size) { int result = 0; while (size > 0) @@ -118,7 +118,7 @@ int ICACHE_FLASH_ATTR strncasecmp_P(const char* str1, const char* str2P, size_t return result; } -int ICACHE_FLASH_ATTR printf_P(const char* formatP, ...) { +int printf_P(const char* formatP, ...) { int ret; va_list arglist; va_start(arglist, formatP); @@ -129,13 +129,13 @@ int ICACHE_FLASH_ATTR printf_P(const char* formatP, ...) { ret = os_printf(format, arglist); - delete [] format; + delete[] format; va_end(arglist); return ret; } -int ICACHE_FLASH_ATTR snprintf_P(char* str, size_t strSize, const char* formatP, ...) { +int snprintf_P(char* str, size_t strSize, const char* formatP, ...) { int ret; va_list arglist; va_start(arglist, formatP); @@ -146,7 +146,7 @@ int ICACHE_FLASH_ATTR snprintf_P(char* str, size_t strSize, const char* formatP, return ret; } -int ICACHE_FLASH_ATTR vsnprintf_P(char* str, size_t strSize, const char* formatP, va_list ap) { +int vsnprintf_P(char* str, size_t strSize, const char* formatP, va_list ap) { int ret; size_t fmtLen = strlen_P(formatP); @@ -155,7 +155,7 @@ int ICACHE_FLASH_ATTR vsnprintf_P(char* str, size_t strSize, const char* formatP ret = ets_vsnprintf(str, strSize, format, ap); - delete [] format; + delete[] format; return ret; -} \ No newline at end of file +} diff --git a/hardware/esp8266com/esp8266/cores/esp8266/pgmspace.h b/hardware/esp8266com/esp8266/cores/esp8266/pgmspace.h index 695f2a50b9..e6db10fbda 100644 --- a/hardware/esp8266com/esp8266/cores/esp8266/pgmspace.h +++ b/hardware/esp8266com/esp8266/cores/esp8266/pgmspace.h @@ -32,26 +32,26 @@ typedef uint32_t prog_uint32_t; #define SIZE_IRRELEVANT 0x7fffffff -extern void* memcpy_P(void* dest, const void* src, size_t count); +void* memcpy_P(void* dest, const void* src, size_t count); -extern char* strncpy_P(char* dest, const char* src, size_t size); +char* strncpy_P(char* dest, const char* src, size_t size); #define strcpy_P(dest, src) strncpy_P((dest), (src), SIZE_IRRELEVANT) -extern char* strncat_P(char* dest, const char* src, size_t size); +char* strncat_P(char* dest, const char* src, size_t size); #define strcat_P(dest, src) strncat_P((dest), (src), SIZE_IRRELEVANT) -extern int strncmp_P(const char* str1, const char* str2P, size_t size); +int strncmp_P(const char* str1, const char* str2P, size_t size); #define strcmp_P(str1, str2P) strncmp_P((str1), (str2P), SIZE_IRRELEVANT) -extern int strncasecmp_P(const char* str1, const char* str2P, size_t size); +int strncasecmp_P(const char* str1, const char* str2P, size_t size); #define strcasecmp_P(str1, str2P) strncasecmp_P((str1), (str2P), SIZE_IRRELEVANT) -extern size_t strnlen_P(const char *s, size_t size); +size_t strnlen_P(const char *s, size_t size); #define strlen_P(strP) strnlen_P((strP), SIZE_IRRELEVANT) -extern int printf_P(const char *formatP, ...); -extern int snprintf_P(char *str, size_t strSize, const char *formatP, ...); -extern int vsnprintf_P(char *str, size_t strSize, const char *formatP, va_list ap); +int printf_P(const char *formatP, ...) __attribute__ ((format (printf, 1, 2))); +int snprintf_P(char *str, size_t strSize, const char *formatP, ...) __attribute__ ((format (printf, 3, 4))); +int vsnprintf_P(char *str, size_t strSize, const char *formatP, va_list ap) __attribute__ ((format (printf, 3, 0))); // flash memory must be read using 32 bit aligned addresses else a processor // exception will be triggered diff --git a/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs.h b/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs.h index 7df7ae0496..3765604365 100644 --- a/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs.h +++ b/hardware/esp8266com/esp8266/cores/esp8266/spiffs/spiffs.h @@ -511,7 +511,6 @@ u32_t SPIFFS_buffer_bytes_for_cache(spiffs *fs, u32_t num_pages); #endif #endif -#include "spiffs_esp8266.h" #ifdef __cplusplus } diff --git a/hardware/esp8266com/esp8266/libraries/DNSServer/examples/CaptivePortal/CaptivePortal.ino b/hardware/esp8266com/esp8266/libraries/DNSServer/examples/CaptivePortal/CaptivePortal.ino new file mode 100644 index 0000000000..eb22782205 --- /dev/null +++ b/hardware/esp8266com/esp8266/libraries/DNSServer/examples/CaptivePortal/CaptivePortal.ino @@ -0,0 +1,34 @@ +#include +#include +#include + +const byte DNS_PORT = 53; +IPAddress apIP(192, 168, 1, 1); +DNSServer dnsServer; +ESP8266WebServer webServer(80); + +String responseHTML = "" + "CaptivePortal" + "

Hello World!

This is a captive portal example. All requests will " + "be redirected here.

"; + +void setup() { + WiFi.mode(WIFI_AP); + WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); + WiFi.softAP("DNSServer CaptivePortal example"); + + // if DNSServer is started with "*" for domain name, it will reply with + // provided IP to all DNS request + dnsServer.start(DNS_PORT, "*", apIP); + + // replay to all requests with same HTML + webServer.onNotFound([]() { + webServer.send(200, "text/html", responseHTML); + }); + webServer.begin(); +} + +void loop() { + dnsServer.processNextRequest(); + webServer.handleClient(); +} diff --git a/hardware/esp8266com/esp8266/libraries/DNSServer/examples/DNSServer/DNSServer.ino b/hardware/esp8266com/esp8266/libraries/DNSServer/examples/DNSServer/DNSServer.ino new file mode 100644 index 0000000000..2916d5ab3c --- /dev/null +++ b/hardware/esp8266com/esp8266/libraries/DNSServer/examples/DNSServer/DNSServer.ino @@ -0,0 +1,41 @@ +#include +#include +#include + +const byte DNS_PORT = 53; +IPAddress apIP(192, 168, 1, 1); +DNSServer dnsServer; +ESP8266WebServer webServer(80); + +void setup() { + WiFi.mode(WIFI_AP); + WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); + WiFi.softAP("DNSServer example"); + + // modify TTL associated with the domain name (in seconds) + // default is 60 seconds + dnsServer.setTTL(300); + // set which return code will be used for all other domains (e.g. sending + // ServerFailure instead of NonExistentDomain will reduce number of queries + // sent by clients) + // default is DNSReplyCode::NonExistentDomain + dnsServer.setErrorReplyCode(DNSReplyCode::ServerFailure); + + // start DNS server for a specific domain name + dnsServer.start(DNS_PORT, "www.example.com", apIP); + + // simple HTTP server to see that DNS server is working + webServer.onNotFound([]() { + String message = "Hello World!\n\n"; + message += "URI: "; + message += webServer.uri(); + + webServer.send(200, "text/plain", message); + }); + webServer.begin(); +} + +void loop() { + dnsServer.processNextRequest(); + webServer.handleClient(); +} diff --git a/hardware/esp8266com/esp8266/libraries/DNSServer/library.properties b/hardware/esp8266com/esp8266/libraries/DNSServer/library.properties new file mode 100644 index 0000000000..71f0ae5440 --- /dev/null +++ b/hardware/esp8266com/esp8266/libraries/DNSServer/library.properties @@ -0,0 +1,9 @@ +name=DNSServer +version=1.1.0 +author=Kristijan Novoselić +maintainer=Kristijan Novoselić, +sentence=A simple DNS server for ESP8266. +paragraph=This library implements a simple DNS server. +category=Communication +url= +architectures=esp8266 diff --git a/hardware/esp8266com/esp8266/libraries/DNSServer/src/DNSServer.cpp b/hardware/esp8266com/esp8266/libraries/DNSServer/src/DNSServer.cpp new file mode 100644 index 0000000000..10fc81d4a9 --- /dev/null +++ b/hardware/esp8266com/esp8266/libraries/DNSServer/src/DNSServer.cpp @@ -0,0 +1,134 @@ +#include "DNSServer.h" +#include +#include + +DNSServer::DNSServer() +{ + _ttl = htonl(60); + _errorReplyCode = DNSReplyCode::NonExistentDomain; +} + +bool DNSServer::start(const uint16_t &port, const String &domainName, + const IPAddress &resolvedIP) +{ + _port = port; + _domainName = domainName; + _resolvedIP[0] = resolvedIP[0]; + _resolvedIP[1] = resolvedIP[1]; + _resolvedIP[2] = resolvedIP[2]; + _resolvedIP[3] = resolvedIP[3]; + downcaseAndRemoveWwwPrefix(_domainName); + return _udp.begin(_port) == 1; +} + +void DNSServer::setErrorReplyCode(const DNSReplyCode &replyCode) +{ + _errorReplyCode = replyCode; +} + +void DNSServer::setTTL(const uint32_t &ttl) +{ + _ttl = htonl(ttl); +} + +void DNSServer::stop() +{ + _udp.stop(); +} + +void DNSServer::downcaseAndRemoveWwwPrefix(String &domainName) +{ + domainName.toLowerCase(); + domainName.replace("www.", ""); +} + +void DNSServer::processNextRequest() +{ + _currentPacketSize = _udp.parsePacket(); + if (_currentPacketSize) + { + _buffer = (unsigned char*)malloc(_currentPacketSize * sizeof(char)); + _udp.read(_buffer, _currentPacketSize); + _dnsHeader = (DNSHeader*) _buffer; + + if (_dnsHeader->QR == DNS_QR_QUERY && + _dnsHeader->OPCode == DNS_OPCODE_QUERY && + requestIncludesOnlyOneQuestion() && + (_domainName == "*" || getDomainNameWithoutWwwPrefix() == _domainName) + ) + { + replyWithIP(); + } + else if (_dnsHeader->QR == DNS_QR_QUERY) + { + replyWithCustomCode(); + } + + free(_buffer); + } +} + +bool DNSServer::requestIncludesOnlyOneQuestion() +{ + return ntohs(_dnsHeader->QDCount) == 1 && + _dnsHeader->ANCount == 0 && + _dnsHeader->NSCount == 0 && + _dnsHeader->ARCount == 0; +} + +String DNSServer::getDomainNameWithoutWwwPrefix() +{ + String parsedDomainName = ""; + unsigned char *start = _buffer + 12; + if (*start == 0) + { + return parsedDomainName; + } + int pos = 0; + while(true) + { + unsigned char labelLength = *(start + pos); + for(int i = 0; i < labelLength; i++) + { + pos++; + parsedDomainName += (char)*(start + pos); + } + pos++; + if (*(start + pos) == 0) + { + downcaseAndRemoveWwwPrefix(parsedDomainName); + return parsedDomainName; + } + else + { + parsedDomainName += "."; + } + } +} + +void DNSServer::replyWithIP() +{ + _dnsHeader->QR = DNS_QR_RESPONSE; + _dnsHeader->ANCount = _dnsHeader->QDCount; + _dnsHeader->QDCount = 0; + + _udp.beginPacket(_udp.remoteIP(), _udp.remotePort()); + _udp.write(_buffer, _currentPacketSize); + _udp.write((unsigned char*)&_ttl, 4); + // Length of RData is 4 bytes (because, in this case, RData is IPv4) + _udp.write((uint8_t)0); + _udp.write((uint8_t)4); + _udp.write(_resolvedIP, sizeof(_resolvedIP)); + _udp.endPacket(); +} + +void DNSServer::replyWithCustomCode() +{ + _dnsHeader->QR = DNS_QR_RESPONSE; + _dnsHeader->RCode = (unsigned char)_errorReplyCode; + _dnsHeader->QDCount = 0; + + _udp.beginPacket(_udp.remoteIP(), _udp.remotePort()); + _udp.write(_buffer, sizeof(DNSHeader)); + _udp.endPacket(); +} diff --git a/hardware/esp8266com/esp8266/libraries/DNSServer/src/DNSServer.h b/hardware/esp8266com/esp8266/libraries/DNSServer/src/DNSServer.h new file mode 100644 index 0000000000..d58efbbdd3 --- /dev/null +++ b/hardware/esp8266com/esp8266/libraries/DNSServer/src/DNSServer.h @@ -0,0 +1,71 @@ +#ifndef DNSServer_h +#define DNSServer_h +#include + +#define DNS_QR_QUERY 0 +#define DNS_QR_RESPONSE 1 +#define DNS_OPCODE_QUERY 0 + +enum class DNSReplyCode +{ + NoError = 0, + FormError = 1, + ServerFailure = 2, + NonExistentDomain = 3, + NotImplemented = 4, + Refused = 5, + YXDomain = 6, + YXRRSet = 7, + NXRRSet = 8 +}; + +struct DNSHeader +{ + uint16_t ID; // identification number + unsigned char RD : 1; // recursion desired + unsigned char TC : 1; // truncated message + unsigned char AA : 1; // authoritive answer + unsigned char OPCode : 4; // message_type + unsigned char QR : 1; // query/response flag + unsigned char RCode : 4; // response code + unsigned char Z : 3; // its z! reserved + unsigned char RA : 1; // recursion available + uint16_t QDCount; // number of question entries + uint16_t ANCount; // number of answer entries + uint16_t NSCount; // number of authority entries + uint16_t ARCount; // number of resource entries +}; + +class DNSServer +{ + public: + DNSServer(); + void processNextRequest(); + void setErrorReplyCode(const DNSReplyCode &replyCode); + void setTTL(const uint32_t &ttl); + + // Returns true if successful, false if there are no sockets available + bool start(const uint16_t &port, + const String &domainName, + const IPAddress &resolvedIP); + // stops the DNS server + void stop(); + + private: + WiFiUDP _udp; + uint16_t _port; + String _domainName; + unsigned char _resolvedIP[4]; + int _currentPacketSize; + unsigned char* _buffer; + DNSHeader* _dnsHeader; + uint32_t _ttl; + DNSReplyCode _errorReplyCode; + + void downcaseAndRemoveWwwPrefix(String &domainName); + String getDomainNameWithoutWwwPrefix(); + bool requestIncludesOnlyOneQuestion(); + void replyWithIP(); + void replyWithCustomCode(); +}; +#endif diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino b/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino index 4e63f68e51..88a2093a58 100644 --- a/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino @@ -183,16 +183,15 @@ void printDirectory() { server.setContentLength(CONTENT_LENGTH_UNKNOWN); server.send(200, "text/json", ""); WiFiClient client = server.client(); - + + server.sendContent("["); for (int cnt = 0; true; ++cnt) { File entry = dir.openNextFile(); if (!entry) break; String output; - if (cnt == 0) - output = '['; - else + if (cnt > 0) output = ','; output += "{\"type\":\""; diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/examples/SDWebServer/SdRoot/edit/index.htm b/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/examples/SDWebServer/SdRoot/edit/index.htm index f555770e16..5b8432a696 100644 --- a/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/examples/SDWebServer/SdRoot/edit/index.htm +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/examples/SDWebServer/SdRoot/edit/index.htm @@ -377,7 +377,7 @@ var leaf = document.createElement("li"); leaf.id = (((path == "/")?"":path)+"/"+name).toLowerCase(); var label = document.createElement("span"); - label.innerText = name.toLowerCase(); + label.textContent = name.toLowerCase(); leaf.appendChild(label); leaf.onclick = function(e){ if(isTextFile(leaf.id)){ @@ -403,7 +403,7 @@ leaf.appendChild(check); var label = document.createElement("label"); label.for = check.id; - label.innerText = name.toLowerCase(); + label.textContent = name.toLowerCase(); leaf.appendChild(label); check.onchange = function(e){ if(check.checked){ diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp b/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp index 5c94ee8181..df067f0c9d 100644 --- a/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp @@ -140,11 +140,10 @@ void ESP8266WebServer::send(int code, const char* content_type, String content) content_type = "text/html"; sendHeader("Content-Type", content_type, true); - if (_contentLength != CONTENT_LENGTH_UNKNOWN) { - size_t length = (_contentLength == CONTENT_LENGTH_NOT_SET) ? - content.length() : _contentLength; - String lengthStr(length); - sendHeader("Content-Length", lengthStr.c_str()); + if (_contentLength != CONTENT_LENGTH_UNKNOWN && _contentLength != CONTENT_LENGTH_NOT_SET) { + sendHeader("Content-Length", String(_contentLength).c_str()); + } else if(content.length() > 0){ + sendHeader("Content-Length", String(content.length()).c_str()); } sendHeader("Connection", "close"); sendHeader("Access-Control-Allow-Origin", "*"); diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/examples/NTPClient/NTPClient.ino b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/examples/NTPClient/NTPClient.ino index 4a9771b5fd..4176c511b2 100644 --- a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/examples/NTPClient/NTPClient.ino +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/examples/NTPClient/NTPClient.ino @@ -27,7 +27,11 @@ char pass[] = "********"; // your network password unsigned int localPort = 2390; // local port to listen for UDP packets -IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server +/* Don't hardwire the IP address or we won't get the benefits of the pool. + * Lookup the IP address for the host name instead */ +//IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server +IPAddress timeServerIP; // time.nist.gov NTP server address +const char* ntpServerName = "time.nist.gov"; const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message @@ -65,7 +69,10 @@ void setup() void loop() { - sendNTPpacket(timeServer); // send an NTP packet to a time server + //get a random server from the pool + WiFi.hostByName(ntpServerName, timeServerIP); + + sendNTPpacket(timeServerIP); // send an NTP packet to a time server // wait to see if a reply is available delay(1000); diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/examples/WiFiAccessPoint/WiFiAccessPoint.ino b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/examples/WiFiAccessPoint/WiFiAccessPoint.ino index 9bd390064c..1a1130747e 100644 --- a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/examples/WiFiAccessPoint/WiFiAccessPoint.ino +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/examples/WiFiAccessPoint/WiFiAccessPoint.ino @@ -55,9 +55,6 @@ void setup() { /* You can remove the password parameter if you want the AP to be open. */ WiFi.softAP(ssid, password); - while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } - - Serial.println("done"); IPAddress myIP = WiFi.softAPIP(); Serial.print("AP IP address: "); Serial.println(myIP); diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp index 5a3db61432..61cb74630b 100644 --- a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp @@ -33,6 +33,8 @@ extern "C" { #include "lwip/dns.h" } +#include "WiFiClient.h" +#include "WiFiUdp.h" extern "C" void esp_schedule(); extern "C" void esp_yield(); @@ -40,11 +42,16 @@ extern "C" void esp_yield(); ESP8266WiFiClass::ESP8266WiFiClass() : _useApMode(false) , _useClientMode(false) +, _useStaticIp(false) { + wifi_set_event_handler_cb((wifi_event_handler_cb_t)&ESP8266WiFiClass::_eventCallback); } void ESP8266WiFiClass::mode(WiFiMode m) { + if(wifi_get_opmode() == (uint8)m) { + return; + } ETS_UART_INTR_DISABLE(); wifi_set_opmode(m); ETS_UART_INTR_ENABLE(); @@ -100,7 +107,8 @@ int ESP8266WiFiClass::begin(const char* ssid, const char *passphrase, int32_t ch wifi_set_channel(channel); } - wifi_station_dhcpc_start(); + if(!_useStaticIp) + wifi_station_dhcpc_start(); return status(); } @@ -112,6 +120,8 @@ uint8_t ESP8266WiFiClass::waitForConnectResult(){ return status(); } + +// You will have to set the DNS-Server manually later since this will not enable DHCP void ESP8266WiFiClass::config(IPAddress local_ip, IPAddress gateway, IPAddress subnet) { struct ip_info info; @@ -121,6 +131,26 @@ void ESP8266WiFiClass::config(IPAddress local_ip, IPAddress gateway, IPAddress s wifi_station_dhcpc_stop(); wifi_set_ip_info(STATION_IF, &info); + + _useStaticIp = true; +} + +void ESP8266WiFiClass::config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns) +{ + struct ip_info info; + info.ip.addr = static_cast(local_ip); + info.gw.addr = static_cast(gateway); + info.netmask.addr = static_cast(subnet); + + wifi_station_dhcpc_stop(); + wifi_set_ip_info(STATION_IF, &info); + + // Set DNS-Server + ip_addr_t d; + d.addr = static_cast(dns); + dns_setserver(0,&d); + + _useStaticIp = true; } int ESP8266WiFiClass::disconnect() @@ -203,12 +233,32 @@ uint8_t* ESP8266WiFiClass::macAddress(uint8_t* mac) return mac; } +String ESP8266WiFiClass::macAddress(void) +{ + uint8_t mac[6]; + char macStr[18] = {0}; + wifi_get_macaddr(STATION_IF, mac); + + sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + return String(macStr); +} + uint8_t* ESP8266WiFiClass::softAPmacAddress(uint8_t* mac) { wifi_get_macaddr(SOFTAP_IF, mac); return mac; } +String ESP8266WiFiClass::softAPmacAddress(void) +{ + uint8_t mac[6]; + char macStr[18] = {0}; + wifi_get_macaddr(SOFTAP_IF, mac); + + sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + return String(macStr); +} + IPAddress ESP8266WiFiClass::localIP() { struct ip_info ip; @@ -251,6 +301,16 @@ uint8_t* ESP8266WiFiClass::BSSID(void) return reinterpret_cast(conf.bssid); } +String ESP8266WiFiClass::BSSIDstr(void) +{ + static struct station_config conf; + char mac[18] = {0}; + wifi_station_get_config(&conf); + sprintf(mac,"%02X:%02X:%02X:%02X:%02X:%02X", conf.bssid[0], conf.bssid[1], conf.bssid[2], conf.bssid[3], conf.bssid[4], conf.bssid[5]); + return String(mac); +} + + int32_t ESP8266WiFiClass::channel(void) { return wifi_get_channel(); } @@ -298,10 +358,14 @@ void ESP8266WiFiClass::_scanDone(void* result, int status) int8_t ESP8266WiFiClass::scanNetworks() { - if ((wifi_get_opmode() & 1) == 0)//1 and 3 have STA enabled - { + if(_useApMode) { + // turn on AP+STA mode mode(WIFI_AP_STA); + } else { + // turn on STA mode + mode(WIFI_STA); } + int status = wifi_station_get_connect_status(); if (status != STATION_GOT_IP && status != STATION_IDLE) { @@ -353,6 +417,17 @@ uint8_t * ESP8266WiFiClass::BSSID(uint8_t i) return it->bssid; } +String ESP8266WiFiClass::BSSIDstr(uint8_t i) +{ + char mac[18] = {0}; + struct bss_info* it = reinterpret_cast(_getScanInfoByIndex(i)); + if (!it) + return String(""); + + sprintf(mac,"%02X:%02X:%02X:%02X:%02X:%02X", it->bssid[0], it->bssid[1], it->bssid[2], it->bssid[3], it->bssid[4], it->bssid[5]); + return String(mac); +} + int32_t ESP8266WiFiClass::channel(uint8_t i) { struct bss_info* it = reinterpret_cast(_getScanInfoByIndex(i)); @@ -462,9 +537,12 @@ void ESP8266WiFiClass::beginSmartConfig() if (_smartConfigStarted) return; - if ((wifi_get_opmode() & 1) == 0)//1 and 3 have STA enabled - { + if(_useApMode) { + // turn on AP+STA mode mode(WIFI_AP_STA); + } else { + // turn on STA mode + mode(WIFI_STA); } _smartConfigStarted = true; @@ -498,6 +576,17 @@ void ESP8266WiFiClass::_smartConfigDone(void* result) wifi_station_connect(); } +void ESP8266WiFiClass::_eventCallback(void* arg) +{ + System_Event_t* event = reinterpret_cast(arg); + DEBUGV("wifi evt: %d\r\n", event->event); + + if (event->event == EVENT_STAMODE_DISCONNECTED) { + WiFiClient::stopAll(); + WiFiUDP::stopAll(); + } +} + void ESP8266WiFiClass::printDiag(Print& p) { diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFi.h b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFi.h index 1a3a7b3668..7234399054 100644 --- a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFi.h +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFi.h @@ -75,7 +75,6 @@ class ESP8266WiFiClass */ void softAP(const char* ssid, const char* passphrase, int channel = 1); - /* Change Ip configuration settings disabling the dhcp client * * param local_ip: Static ip configuration @@ -84,6 +83,15 @@ class ESP8266WiFiClass */ void config(IPAddress local_ip, IPAddress gateway, IPAddress subnet); + /* Change Ip configuration settings disabling the dhcp client + * + * param local_ip: Static ip configuration + * param gateway: Static gateway configuration + * param subnet: Static Subnet mask + * param dns: Defined DNS + */ + void config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns); + /* Configure access point * * param local_ip: access point IP @@ -103,15 +111,19 @@ class ESP8266WiFiClass * Get the station interface MAC address. * * return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH + * return: String */ uint8_t* macAddress(uint8_t* mac); + String macAddress(void); /* * Get the softAP interface MAC address. * * return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH + * return: String */ uint8_t* softAPmacAddress(uint8_t* mac); + String softAPmacAddress(void); /* * Get the station interface IP address. @@ -151,10 +163,17 @@ class ESP8266WiFiClass /* * Return the current bssid / mac associated with the network if configured * - * return: bssid string + * return: bssid uint8_t * */ uint8_t * BSSID(void); + /* + * Return the current bssid / mac associated with the network if configured + * + * return: bssid string + */ + String BSSIDstr(void); + /* * Return the current channel associated with the network * @@ -209,10 +228,17 @@ class ESP8266WiFiClass /** * return MAC / BSSID of scanned wifi * @param networkItem specify from which network item want to get the information - * @return uint8_t * to MAC / BSSID of scanned wifi + * @return uint8_t * MAC / BSSID of scanned wifi */ uint8_t * BSSID(uint8_t networkItem); + /** + * return MAC / BSSID of scanned wifi + * @param networkItem specify from which network item want to get the information + * @return String MAC / BSSID of scanned wifi + */ + String BSSIDstr(uint8_t networkItem); + /** * return channel of scanned wifi * @param networkItem specify from which network item want to get the information @@ -288,11 +314,13 @@ class ESP8266WiFiClass static void _scanDone(void* result, int status); void * _getScanInfoByIndex(int i); static void _smartConfigDone(void* result); + static void _eventCallback(void *event); bool _smartConfigStarted = false; bool _useApMode; bool _useClientMode; - + bool _useStaticIp; + static size_t _scanCount; static void* _scanResult; diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp index e0a7ddeb22..47f201f4da 100644 --- a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp @@ -47,6 +47,10 @@ wl_status_t ESP8266WiFiMulti::run(void) { uint8 bestBSSID[6]; int32_t bestChannel; + DEBUG_WIFI_MULTI("[WIFI] delete old wifi config...\n"); + WiFi.disconnect(); + + DEBUG_WIFI_MULTI("[WIFI] start scan\n"); // WiFi.scanNetworks will return the number of networks found int8_t n = WiFi.scanNetworks(); @@ -68,7 +72,6 @@ wl_status_t ESP8266WiFiMulti::run(void) { WiFi.getNetworkInfo(i, ssid_scan, sec_scan, rssi_scan, BSSID_scan, chan_scan, hidden_scan); - bool known = false; for(uint32_t x = 0; x < APlist.size(); x++) { WifiAPlist_t entry = APlist[x]; @@ -148,7 +151,17 @@ bool ESP8266WiFiMulti::APlistAdd(const char* ssid, const char *passphrase) { WifiAPlist_t newAP; - newAP.ssid = (char*) malloc(strlen(ssid)); + if(!ssid || strlen(ssid) > 31) { + // fail SSID to long or missing! + return false; + } + + if(passphrase && strlen(passphrase) > 63) { + // fail passphrase to long! + return false; + } + + newAP.ssid = (char*) malloc((strlen(ssid) + 1)); if(!newAP.ssid) { return false; @@ -157,16 +170,14 @@ bool ESP8266WiFiMulti::APlistAdd(const char* ssid, const char *passphrase) { strcpy(newAP.ssid, ssid); if(passphrase && *passphrase != 0x00) { - newAP.passphrase = (char*) malloc(strlen(passphrase)); - } - - if(!newAP.passphrase) { - free(newAP.ssid); - return false; + newAP.passphrase = (char*) malloc((strlen(passphrase) + 1)); + if(!newAP.passphrase) { + free(newAP.ssid); + return false; + } + strcpy(newAP.passphrase, passphrase); } - strcpy(newAP.passphrase, passphrase); - APlist.push_back(newAP); return true; } diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiClient.cpp b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiClient.cpp index 534c7fa895..9117a41923 100644 --- a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiClient.cpp +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiClient.cpp @@ -34,36 +34,48 @@ extern "C" #include "WiFiClient.h" #include "WiFiServer.h" #include "lwip/opt.h" +#include "lwip/ip.h" #include "lwip/tcp.h" #include "lwip/inet.h" +#include "lwip/netif.h" #include "cbuf.h" #include "include/ClientContext.h" #include "c_types.h" -ICACHE_FLASH_ATTR WiFiClient::WiFiClient() +uint16_t WiFiClient::_localPort = 0; + +template<> +WiFiClient* SList::_s_first = 0; + + +WiFiClient::WiFiClient() : _client(0) { + WiFiClient::_add(this); } -ICACHE_FLASH_ATTR WiFiClient::WiFiClient(ClientContext* client) : _client(client) +WiFiClient::WiFiClient(ClientContext* client) : _client(client) { _client->ref(); + WiFiClient::_add(this); } -ICACHE_FLASH_ATTR WiFiClient::~WiFiClient() +WiFiClient::~WiFiClient() { + WiFiClient::_remove(this); if (_client) _client->unref(); } -ICACHE_FLASH_ATTR WiFiClient::WiFiClient(const WiFiClient& other) +WiFiClient::WiFiClient(const WiFiClient& other) { _client = other._client; if (_client) _client->ref(); + WiFiClient::_add(this); } -WiFiClient& ICACHE_FLASH_ATTR WiFiClient::operator=(const WiFiClient& other) +WiFiClient& WiFiClient::operator=(const WiFiClient& other) { if (_client) _client->unref(); @@ -74,7 +86,7 @@ WiFiClient& ICACHE_FLASH_ATTR WiFiClient::operator=(const WiFiClient& other) } -int ICACHE_FLASH_ATTR WiFiClient::connect(const char* host, uint16_t port) +int WiFiClient::connect(const char* host, uint16_t port) { IPAddress remote_addr; if (WiFi.hostByName(host, remote_addr)) @@ -84,17 +96,31 @@ int ICACHE_FLASH_ATTR WiFiClient::connect(const char* host, uint16_t port) return 0; } -int ICACHE_FLASH_ATTR WiFiClient::connect(IPAddress ip, uint16_t port) +int WiFiClient::connect(IPAddress ip, uint16_t port) { + ip_addr_t addr; + addr.addr = ip; + if (_client) stop(); + // if the default interface is down, tcp_connect exits early without + // ever calling tcp_err + // http://lists.gnu.org/archive/html/lwip-devel/2010-05/msg00001.html + netif* interface = ip_route(&addr); + if (!interface) { + DEBUGV("no route to host\r\n"); + return 1; + } + tcp_pcb* pcb = tcp_new(); if (!pcb) return 0; - ip_addr_t addr; - addr.addr = ip; + if (_localPort > 0) { + pcb->local_port = _localPort++; + } + tcp_arg(pcb, this); tcp_err(pcb, &WiFiClient::_s_err); tcp_connect(pcb, &addr, port, reinterpret_cast(&WiFiClient::_s_connected)); @@ -108,7 +134,7 @@ int ICACHE_FLASH_ATTR WiFiClient::connect(IPAddress ip, uint16_t port) return 0; } -int8_t ICACHE_FLASH_ATTR WiFiClient::_connected(void* pcb, int8_t err) +int8_t WiFiClient::_connected(void* pcb, int8_t err) { tcp_pcb* tpcb = reinterpret_cast(pcb); _client = new ClientContext(tpcb, 0, 0); @@ -117,31 +143,31 @@ int8_t ICACHE_FLASH_ATTR WiFiClient::_connected(void* pcb, int8_t err) return ERR_OK; } -void ICACHE_FLASH_ATTR WiFiClient::_err(int8_t err) +void WiFiClient::_err(int8_t err) { DEBUGV(":err %d\r\n", err); esp_schedule(); } -void ICACHE_FLASH_ATTR WiFiClient::setNoDelay(bool nodelay) { +void WiFiClient::setNoDelay(bool nodelay) { if (!_client) return; _client->setNoDelay(nodelay); } -bool ICACHE_FLASH_ATTR WiFiClient::getNoDelay() { +bool WiFiClient::getNoDelay() { if (!_client) return false; return _client->getNoDelay(); } -size_t ICACHE_FLASH_ATTR WiFiClient::write(uint8_t b) +size_t WiFiClient::write(uint8_t b) { return write(&b, 1); } -size_t ICACHE_FLASH_ATTR WiFiClient::write(const uint8_t *buf, size_t size) +size_t WiFiClient::write(const uint8_t *buf, size_t size) { if (!_client || !size) { @@ -153,7 +179,7 @@ size_t ICACHE_FLASH_ATTR WiFiClient::write(const uint8_t *buf, size_t size) extern "C" uint32_t esp_micros_at_task_start(); -int ICACHE_FLASH_ATTR WiFiClient::available() +int WiFiClient::available() { static uint32_t lastPollTime = 0; if (!_client) @@ -168,7 +194,7 @@ int ICACHE_FLASH_ATTR WiFiClient::available() return result; } -int ICACHE_FLASH_ATTR WiFiClient::read() +int WiFiClient::read() { if (!available()) return -1; @@ -177,12 +203,12 @@ int ICACHE_FLASH_ATTR WiFiClient::read() } -int ICACHE_FLASH_ATTR WiFiClient::read(uint8_t* buf, size_t size) +int WiFiClient::read(uint8_t* buf, size_t size) { return (int) _client->read(reinterpret_cast(buf), size); } -int ICACHE_FLASH_ATTR WiFiClient::peek() +int WiFiClient::peek() { if (!available()) return -1; @@ -190,13 +216,13 @@ int ICACHE_FLASH_ATTR WiFiClient::peek() return _client->peek(); } -void ICACHE_FLASH_ATTR WiFiClient::flush() +void WiFiClient::flush() { if (_client) _client->flush(); } -void ICACHE_FLASH_ATTR WiFiClient::stop() +void WiFiClient::stop() { if (!_client) return; @@ -205,7 +231,7 @@ void ICACHE_FLASH_ATTR WiFiClient::stop() _client = 0; } -uint8_t ICACHE_FLASH_ATTR WiFiClient::connected() +uint8_t WiFiClient::connected() { if (!_client) return 0; @@ -213,14 +239,14 @@ uint8_t ICACHE_FLASH_ATTR WiFiClient::connected() return _client->state() == ESTABLISHED || available(); } -uint8_t ICACHE_FLASH_ATTR WiFiClient::status() +uint8_t WiFiClient::status() { if (!_client) return CLOSED; return _client->state(); } -ICACHE_FLASH_ATTR WiFiClient::operator bool() + WiFiClient::operator bool() { return _client != 0; } @@ -241,13 +267,24 @@ uint16_t WiFiClient::remotePort() return _client->getRemotePort(); } -int8_t ICACHE_FLASH_ATTR WiFiClient::_s_connected(void* arg, void* tpcb, int8_t err) +int8_t WiFiClient::_s_connected(void* arg, void* tpcb, int8_t err) { return reinterpret_cast(arg)->_connected(tpcb, err); } -void ICACHE_FLASH_ATTR WiFiClient::_s_err(void* arg, int8_t err) +void WiFiClient::_s_err(void* arg, int8_t err) { reinterpret_cast(arg)->_err(err); } +void WiFiClient::stopAll() +{ + for (WiFiClient* it = _s_first; it; it = it->_next) { + ClientContext* c = it->_client; + if (c) { + c->abort(); + c->unref(); + it->_client = 0; + } + } +} diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiClient.h b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiClient.h index f4063cbbaf..161ca0be1c 100644 --- a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiClient.h +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiClient.h @@ -26,11 +26,12 @@ #include "Client.h" #include "IPAddress.h" #include +#include "include/slist.h" class ClientContext; class WiFiServer; -class WiFiClient : public Client { +class WiFiClient : public Client, public SList { protected: WiFiClient(ClientContext* client); @@ -61,6 +62,7 @@ class WiFiClient : public Client { uint16_t remotePort(); bool getNoDelay(); void setNoDelay(bool nodelay); + static void setLocalPortStart(uint16_t port) { _localPort = port; } template size_t write(T &src){ uint8_t obuf[1460]; @@ -88,6 +90,8 @@ class WiFiClient : public Client { using Print::write; + static void stopAll(); + private: static int8_t _s_connected(void* arg, void* tpcb, int8_t err); @@ -97,7 +101,7 @@ class WiFiClient : public Client { void _err(int8_t err); ClientContext* _client; - + static uint16_t _localPort; }; diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiUdp.cpp b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiUdp.cpp index 7696d747b7..8e304abbb2 100644 --- a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiUdp.cpp +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiUdp.cpp @@ -40,14 +40,22 @@ extern "C" #include "lwip/mem.h" #include "include/UdpContext.h" + +template<> +WiFiUDP* SList::_s_first = 0; + /* Constructor */ -WiFiUDP::WiFiUDP() : _ctx(0) {} +WiFiUDP::WiFiUDP() : _ctx(0) +{ + WiFiUDP::_add(this); +} WiFiUDP::WiFiUDP(const WiFiUDP& other) { _ctx = other._ctx; if (_ctx) _ctx->ref(); + WiFiUDP::_add(this); } WiFiUDP& WiFiUDP::operator=(const WiFiUDP& rhs) @@ -60,6 +68,7 @@ WiFiUDP& WiFiUDP::operator=(const WiFiUDP& rhs) WiFiUDP::~WiFiUDP() { + WiFiUDP::_remove(this); if (_ctx) _ctx->unref(); } @@ -258,3 +267,11 @@ uint16_t WiFiUDP::localPort() return _ctx->getLocalPort(); } + +void WiFiUDP::stopAll() +{ + for (WiFiUDP* it = _s_first; it; it = it->_next) { + it->stop(); + } +} + diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiUdp.h b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiUdp.h index f8d76cd057..16aa0a3be9 100644 --- a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiUdp.h +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiUdp.h @@ -23,12 +23,13 @@ #define WIFIUDP_H #include +#include #define UDP_TX_PACKET_MAX_SIZE 8192 class UdpContext; -class WiFiUDP : public UDP { +class WiFiUDP : public UDP, public SList { private: UdpContext* _ctx; @@ -103,6 +104,8 @@ class WiFiUDP : public UDP { // Return the local port for outgoing packets uint16_t localPort(); + static void stopAll(); + }; #endif //WIFIUDP_H diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/include/ClientContext.h b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/include/ClientContext.h index 79c68127f9..d1f728eefe 100644 --- a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/include/ClientContext.h +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/include/ClientContext.h @@ -261,8 +261,17 @@ class ClientContext { } void _error(err_t err) { - DEBUGV(":er %d\r\n", err); - close(); + DEBUGV(":er %d %d %d\r\n", err, _size_sent, _send_waiting); + if (err != ERR_ABRT) { + abort(); + } + else { + tcp_arg(_pcb, NULL); + tcp_sent(_pcb, NULL); + tcp_recv(_pcb, NULL); + tcp_err(_pcb, NULL); + _pcb = NULL; + } if(_size_sent && _send_waiting) { esp_schedule(); } diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/include/slist.h b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/include/slist.h new file mode 100644 index 0000000000..4ce42de6cc --- /dev/null +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/include/slist.h @@ -0,0 +1,38 @@ +#ifndef SLIST_H +#define SLIST_H + +template +class SList { +public: + SList() : _next(0) { } + +protected: + + static void _add(T* self) { + T* tmp = _s_first; + _s_first = self; + self->_next = tmp; + } + + static void _remove(T* self) { + if (_s_first == self) { + _s_first = self->_next; + self->_next = 0; + return; + } + + for (T* prev = _s_first; prev->_next; _s_first = _s_first->_next) { + if (prev->_next == self) { + prev->_next = self->_next; + self->_next = 0; + return; + } + } + } + + static T* _s_first; + T* _next; +}; + + +#endif //SLIST_H diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino b/hardware/esp8266com/esp8266/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino new file mode 100644 index 0000000000..0423c20cfb --- /dev/null +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino @@ -0,0 +1,44 @@ +#include +#include + +/* Create the mesh node object */ +ESP8266WiFiMesh mesh_node = ESP8266WiFiMesh(ESP.getChipId(), manageRequest); + +/** + * Callback for when other nodes send you data + * + * @request The string received from another node in the mesh + * @returns The string to send back to the other node + */ +String manageRequest(String request) +{ + /* Print out received message */ + Serial.print("received: "); + Serial.println(request); + + /* return a string to send back */ + return String("Hello world response."); +} + +void setup() +{ + Serial.begin(115200); + delay(10); + + Serial.println(); + Serial.println(); + Serial.println("Setting up mesh node..."); + + /* Initialise the mesh node */ + mesh_node.begin(); +} + +void loop() +{ + /* Accept any incoming connections */ + mesh_node.acceptRequest(); + + /* Scan for other nodes and send them a message */ + mesh_node.attemptScan("Hello world request."); + delay(1000); +} diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WiFiMesh/keywords.txt b/hardware/esp8266com/esp8266/libraries/ESP8266WiFiMesh/keywords.txt new file mode 100644 index 0000000000..14657d805c --- /dev/null +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WiFiMesh/keywords.txt @@ -0,0 +1,23 @@ +####################################### +# Syntax Coloring Map For ESP8266WiFiMesh +####################################### + +####################################### +# Library (KEYWORD3) +####################################### + +ESP8266WiFiMesh KEYWORD3 + +####################################### +# Datatypes (KEYWORD1) +####################################### + +ESP8266WiFiMesh KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +attemptScan KEYWORD2 +acceptRequest KEYWORD2 diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WiFiMesh/library.properties b/hardware/esp8266com/esp8266/libraries/ESP8266WiFiMesh/library.properties new file mode 100644 index 0000000000..dc6ba9a4da --- /dev/null +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WiFiMesh/library.properties @@ -0,0 +1,9 @@ +name=ESP8266WiFiMesh +version=1.0 +author=Julian Fell +maintainer= +sentence=Mesh network library +paragraph=The library sets up a Mesh Node which acts as a router, creating a Mesh Network with other nodes. +category=Communication +url= +architectures=esp8266 diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp b/hardware/esp8266com/esp8266/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp new file mode 100644 index 0000000000..6d3e544d7c --- /dev/null +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.cpp @@ -0,0 +1,168 @@ +/* + ESP8266WiFiMesh.cpp - Mesh network node + Sets up a Mesh Node which acts as a router, creating a Mesh Network with other nodes. All information + is passed in both directions, but it is up to the user what the data sent is and how it is dealt with. + + Copyright (c) 2015 Julian Fell. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + This library 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 + Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include + +#include "ESP8266WiFiMesh.h" + +#define SSID_PREFIX "Mesh_Node" +#define SERVER_IP_ADDR "192.168.4.1" +#define SERVER_PORT 4011 + +ESP8266WiFiMesh::ESP8266WiFiMesh(uint32_t chip_id, std::function handler) +: _server(SERVER_PORT) +{ + _chip_id = chip_id; + _ssid = String( String( SSID_PREFIX ) + String( _chip_id ) ); + _ssid_prefix = String( SSID_PREFIX ); + _handler = handler; +} + +void ESP8266WiFiMesh::begin() +{ + WiFi.mode(WIFI_AP_STA); + WiFi.softAP( _ssid.c_str() ); + _server.begin(); +} + +/** + * Wait for a WiFiClient to connect + * + * @returns: True if the client is ready, false otherwise. + * + */ +bool ESP8266WiFiMesh::waitForClient(WiFiClient curr_client, int max_wait) +{ + int wait = max_wait; + while(curr_client.connected() && !curr_client.available() && wait--) + delay(3); + + /* Return false if the client isn't ready to communicate */ + if (WiFi.status() == WL_DISCONNECTED || !curr_client.connected()) + return false; + + return true; +} + +/** + * Send the supplied message then read back the other node's response + * and pass that to the user-supplied handler. + * + * @target_ssid The name of the AP the other node has set up. + * @message The string to send to the node. + * @returns: True if the exchange was a succes, false otherwise. + * + */ +bool ESP8266WiFiMesh::exchangeInfo(String message, WiFiClient curr_client) +{ + curr_client.println( message.c_str() ); + + if (!waitForClient(curr_client, 1000)) + return false; + + String response = curr_client.readStringUntil('\r'); + curr_client.readStringUntil('\n'); + + if (response.length() <= 2) + return false; + + /* Pass data to user callback */ + _handler(response); + return true; +} + +/** + * Connect to the AP at ssid, send them a message then disconnect. + * + * @target_ssid The name of the AP the other node has set up. + * @message The string to send to the node. + * + */ +void ESP8266WiFiMesh::connectToNode(String target_ssid, String message) +{ + WiFiClient curr_client; + WiFi.begin( target_ssid.c_str() ); + + int wait = 1500; + while((WiFi.status() == WL_DISCONNECTED) && wait--) + delay(3); + + /* If the connection timed out */ + if (WiFi.status() != 3) + return; + + /* Connect to the node's server */ + if (!curr_client.connect(SERVER_IP_ADDR, SERVER_PORT)) + return; + + if (!exchangeInfo(message, curr_client)) + return; + + curr_client.stop(); + WiFi.disconnect(); +} + +void ESP8266WiFiMesh::attemptScan(String message) +{ + /* Scan for APs */ + int n = WiFi.scanNetworks(); + + for (int i = 0; i < n; ++i) { + String current_ssid = WiFi.SSID(i); + int index = current_ssid.indexOf( _ssid_prefix ); + uint32_t target_chip_id = (current_ssid.substring(index + _ssid_prefix.length())).toInt(); + + /* Connect to any _suitable_ APs which contain _ssid_prefix */ + if (index >= 0 && (target_chip_id < _chip_id)) { + + WiFi.mode(WIFI_STA); + delay(100); + connectToNode(current_ssid, message); + WiFi.mode(WIFI_AP_STA); + delay(100); + } + } +} + +void ESP8266WiFiMesh::acceptRequest() +{ + while (true) { + _client = _server.available(); + if (!_client) + break; + + if (!waitForClient(_client, 1500)) { + continue; + } + + /* Read in request and pass it to the supplied handler */ + String request = _client.readStringUntil('\r'); + _client.readStringUntil('\n'); + + String response = _handler(request); + + /* Send the response back to the client */ + if (_client.connected()) + _client.println(response); + } +} diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h b/hardware/esp8266com/esp8266/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h new file mode 100644 index 0000000000..dd959731bb --- /dev/null +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WiFiMesh/src/ESP8266WiFiMesh.h @@ -0,0 +1,75 @@ +/* + ESP8266WiFiMesh.h - Mesh network node + Sets up a Mesh Node which acts as a router, creating a Mesh Network with other nodes. All information + is passed in both directions, but it is up to the user what the data sent is and how it is dealt with. + + Copyright (c) 2015 Julian Fell. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + This library 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 + Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __WIFIMESH_H__ +#define __WIFIMESH_H__ + +#include +#include +#include + +class ESP8266WiFiMesh { + +private: + String _ssid; + String _ssid_prefix; + uint32_t _chip_id; + + std::function _handler; + + WiFiServer _server; + WiFiClient _client; + + void connectToNode(String target_ssid, String message); + bool exchangeInfo(String message, WiFiClient curr_client); + bool waitForClient(WiFiClient curr_client, int max_wait); + +public: + + /** + * WiFiMesh Constructor method. Creates a WiFi Mesh Node, ready to be initialised. + * + * @chip_id A unique identifier number for the node. + * @handler The callback handler for dealing with received messages. Takes a string as an argument which + * is the string received from another node and returns the string to send back. + * + */ + ESP8266WiFiMesh(uint32_t chip_id, std::function handler); + + /** + * Initialises the node. + */ + void begin(); + + /** + * Scan for other nodes, and exchange the chosen message with any that are found. + * + * @message The message to send to all other nodes. + * + */ + void attemptScan(String message); + + /** + * If any clients are connected, accept their requests and call the hander function for each one. + */ + void acceptRequest(); +}; + +#endif diff --git a/hardware/esp8266com/esp8266/libraries/SPI/SPI.cpp b/hardware/esp8266com/esp8266/libraries/SPI/SPI.cpp index 7d52528ef1..4e73021220 100644 --- a/hardware/esp8266com/esp8266/libraries/SPI/SPI.cpp +++ b/hardware/esp8266com/esp8266/libraries/SPI/SPI.cpp @@ -121,14 +121,14 @@ void SPIClass::setBitOrder(uint8_t bitOrder) { * @return */ static uint32_t ClkRegToFreq(spiClk_t * reg) { - return (SPI_MAX_SPEED / ((reg->regPre + 1) * (reg->regN + 1))); + return (ESP8266_CLOCK / ((reg->regPre + 1) * (reg->regN + 1))); } void SPIClass::setFrequency(uint32_t freq) { static uint32_t lastSetFrequency = 0; static uint32_t lastSetRegister = 0; - if(freq >= SPI_MAX_SPEED) { + if(freq >= ESP8266_CLOCK) { setClockDivider(0x80000000); return; } @@ -164,7 +164,7 @@ void SPIClass::setFrequency(uint32_t freq) { reg.regN = calN; while(calPreVari++ <= 1) { // test different variants for Pre (we calculate in int so we miss the decimals, testing is the easyest and fastest way) - calPre = (((SPI_MAX_SPEED / (reg.regN + 1)) / freq) - 1) + calPreVari; + calPre = (((ESP8266_CLOCK / (reg.regN + 1)) / freq) - 1) + calPreVari; if(calPre > 0x1FFF) { reg.regPre = 0x1FFF; // 8191 } else if(calPre <= 0) { diff --git a/hardware/esp8266com/esp8266/libraries/SPI/SPI.h b/hardware/esp8266com/esp8266/libraries/SPI/SPI.h index 68d2a3dc6c..141f30ef4b 100644 --- a/hardware/esp8266com/esp8266/libraries/SPI/SPI.h +++ b/hardware/esp8266com/esp8266/libraries/SPI/SPI.h @@ -28,7 +28,6 @@ // This defines are not representing the real Divider of the ESP8266 // the Defines match to an AVR Arduino on 16MHz for better compatibility -#if F_CPU == 80000000L #define SPI_CLOCK_DIV2 0x00101001 //8 MHz #define SPI_CLOCK_DIV4 0x00241001 //4 MHz #define SPI_CLOCK_DIV8 0x004c1001 //2 MHz @@ -36,16 +35,6 @@ #define SPI_CLOCK_DIV32 0x013c1001 //500 KHz #define SPI_CLOCK_DIV64 0x027c1001 //250 KHz #define SPI_CLOCK_DIV128 0x04fc1001 //125 KHz -#else -#define SPI_CLOCK_DIV2 0x00241001 //8 MHz -#define SPI_CLOCK_DIV4 0x004c1001 //4 MHz -#define SPI_CLOCK_DIV8 0x009c1001 //2 MHz -#define SPI_CLOCK_DIV16 0x013c1001 //1 MHz -#define SPI_CLOCK_DIV32 0x027c1001 //500 KHz -#define SPI_CLOCK_DIV64 0x04fc1001 //250 KHz -#endif - -#define SPI_MAX_SPEED (80000000L) const uint8_t SPI_MODE0 = 0x00; ///< CPOL: 0 CPHA: 0 const uint8_t SPI_MODE1 = 0x01; ///< CPOL: 0 CPHA: 1 diff --git a/hardware/esp8266com/esp8266/libraries/Servo/examples/Sweep/Sweep.ino b/hardware/esp8266com/esp8266/libraries/Servo/examples/Sweep/Sweep.ino new file mode 100644 index 0000000000..fe4e343cef --- /dev/null +++ b/hardware/esp8266com/esp8266/libraries/Servo/examples/Sweep/Sweep.ino @@ -0,0 +1,39 @@ +/* Sweep + by BARRAGAN + This example code is in the public domain. + + modified 28 May 2015 + by Michael C. Miller + modified 8 Nov 2013 + by Scott Fitzgerald + + http://arduino.cc/en/Tutorial/Sweep +*/ + +#include + +Servo myservo; // create servo object to control a servo + // twelve servo objects can be created on most boards + + +void setup() +{ + myservo.attach(2); // attaches the servo on GIO2 to the servo object +} + +void loop() +{ + int pos; + + for(pos = 0; pos <= 180; pos += 1) // goes from 0 degrees to 180 degrees + { // in steps of 1 degree + myservo.write(pos); // tell servo to go to position in variable 'pos' + delay(15); // waits 15ms for the servo to reach the position + } + for(pos = 180; pos>=0; pos-=1) // goes from 180 degrees to 0 degrees + { + myservo.write(pos); // tell servo to go to position in variable 'pos' + delay(15); // waits 15ms for the servo to reach the position + } +} + diff --git a/hardware/esp8266com/esp8266/libraries/Servo/keywords.txt b/hardware/esp8266com/esp8266/libraries/Servo/keywords.txt new file mode 100644 index 0000000000..0a7ca1e3d8 --- /dev/null +++ b/hardware/esp8266com/esp8266/libraries/Servo/keywords.txt @@ -0,0 +1,24 @@ +####################################### +# Syntax Coloring Map Servo +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +Servo KEYWORD1 Servo + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +attach KEYWORD2 +detach KEYWORD2 +write KEYWORD2 +read KEYWORD2 +attached KEYWORD2 +writeMicroseconds KEYWORD2 +readMicroseconds KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/hardware/esp8266com/esp8266/libraries/Servo/library.properties b/hardware/esp8266com/esp8266/libraries/Servo/library.properties new file mode 100644 index 0000000000..28b1eedf71 --- /dev/null +++ b/hardware/esp8266com/esp8266/libraries/Servo/library.properties @@ -0,0 +1,9 @@ +name=Servo +version=1.0.2 +author=Michael C. Miller +maintainer=GitHub/esp8266/arduino +sentence=Allows Esp8266 boards to control a variety of servo motors. +paragraph=This library can control a great number of servos.
It makes careful use of timers: the library can control 12 servos using only 1 timer.
+category=Device Control +url=http://arduino.cc/en/Reference/Servo +architectures=esp8266 diff --git a/hardware/esp8266com/esp8266/libraries/Servo/src/Servo.h b/hardware/esp8266com/esp8266/libraries/Servo/src/Servo.h new file mode 100644 index 0000000000..10cfd32835 --- /dev/null +++ b/hardware/esp8266com/esp8266/libraries/Servo/src/Servo.h @@ -0,0 +1,93 @@ +/* + Servo.h - Interrupt driven Servo library for Esp8266 using timers + Copyright (c) 2015 Michael C. Miller. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +// A servo is activated by creating an instance of the Servo class passing +// the desired pin to the attach() method. +// The servos are pulsed in the background using the value most recently +// written using the write() method. +// +// This library uses time0 and timer1. +// Note that timer0 may be repurposed when the first servo is attached. +// +// Timers are seized as needed in groups of 12 servos - 24 servos use two +// timers, there are only two timers for the esp8266 so the support stops here +// The sequence used to sieze timers is defined in timers.h +// +// The methods are: +// +// Servo - Class for manipulating servo motors connected to Arduino pins. +// +// attach(pin ) - Attaches a servo motor to an i/o pin. +// attach(pin, min, max ) - Attaches to a pin setting min and max values in microseconds +// default min is 544, max is 2400 +// +// write() - Sets the servo angle in degrees. (invalid angle that is valid as pulse in microseconds is treated as microseconds) +// writeMicroseconds() - Sets the servo pulse width in microseconds +// read() - Gets the last written servo pulse width as an angle between 0 and 180. +// readMicroseconds() - Gets the last written servo pulse width in microseconds. (was read_us() in first release) +// attached() - Returns true if there is a servo attached. +// detach() - Stops an attached servos from pulsing its i/o pin. + + +#ifndef Servo_h +#define Servo_h + +#include + +// the following are in us (microseconds) +// +#define MIN_PULSE_WIDTH 544 // the shortest pulse sent to a servo +#define MAX_PULSE_WIDTH 2400 // the longest pulse sent to a servo +#define DEFAULT_PULSE_WIDTH 1500 // default pulse width when servo is attached +#define REFRESH_INTERVAL 20000 // minumim time to refresh servos in microseconds + +// NOTE: to maintain a strict refresh interval the user needs to not exceede 8 servos +#define SERVOS_PER_TIMER 12 // the maximum number of servos controlled by one timer +#define MAX_SERVOS (ServoTimerSequence_COUNT * SERVOS_PER_TIMER) + +#if defined(ESP8266) + +#include "esp8266/ServoTimers.h" + +#else + +#error "This library only supports esp8266 boards." + +#endif + +class Servo +{ +public: + Servo(); + uint8_t attach(int pin); // attach the given pin to the next free channel, sets pinMode, returns channel number or 0 if failure + uint8_t attach(int pin, int min, int max); // as above but also sets min and max values for writes. + void detach(); + void write(int value); // if value is < 200 its treated as an angle, otherwise as pulse width in microseconds + void writeMicroseconds(int value); // Write pulse width in microseconds + int read(); // returns current pulse width as an angle between 0 and 180 degrees + int readMicroseconds(); // returns current pulse width in microseconds for this servo (was read_us() in first release) + bool attached(); // return true if this servo is attached, otherwise false +private: + uint8_t _servoIndex; // index into the channel data for this servo + uint16_t _minUs; + uint16_t _maxUs; +}; + +#endif diff --git a/hardware/esp8266com/esp8266/libraries/Servo/src/esp8266/Servo.cpp b/hardware/esp8266com/esp8266/libraries/Servo/src/esp8266/Servo.cpp new file mode 100644 index 0000000000..bbc7bb26ff --- /dev/null +++ b/hardware/esp8266com/esp8266/libraries/Servo/src/esp8266/Servo.cpp @@ -0,0 +1,249 @@ +/* + Copyright (c) 2015 Michael C. Miller. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if defined(ESP8266) + +#include +#include + + +#define INVALID_SERVO 255 // flag indicating an invalid servo index + +const uint32_t c_CycleCompensation = 4; // compensation us to trim adjust for digitalWrite delays + +struct ServoInfo { + uint8_t pin : 6; // a pin number from 0 to 63 + uint8_t isActive : 1; // true if this channel is enabled, pin not pulsed if false +}; + +struct ServoState { + ServoInfo info; + volatile uint16_t usPulse; +}; + +#if !defined (SERVO_EXCLUDE_TIMER0) +ServoTimer0 s_servoTimer0; +#endif + +#if !defined (SERVO_EXCLUDE_TIMER1) +ServoTimer1 s_servoTimer1; +#endif + +static ServoState s_servos[MAX_SERVOS]; // static array of servo structures + +static uint8_t s_servoCount = 0; // the total number of attached s_servos + + +// inconvenience macros +#define SERVO_INDEX_TO_TIMER(servoIndex) ((ServoTimerSequence)(servoIndex / SERVOS_PER_TIMER)) // returns the timer controlling this servo +#define SERVO_INDEX(timerId, channel) ((timerId * SERVOS_PER_TIMER) + channel) // macro to access servo index by timer and channel + +//------------------------------------------------------------------------------ +// Interrupt handler template method that takes a class that implements +// a standard set of methods for the timer abstraction +//------------------------------------------------------------------------------ +template void Servo_Handler(T* timer) +{ + noInterrupts(); + + uint8_t servoIndex; + + // clear interrupt + timer->ResetInterrupt(); + + if (timer->isEndOfCycle()) { + timer->StartCycle(); + } + else { + servoIndex = SERVO_INDEX(timer->timerId(), timer->getCurrentChannel()); + if (servoIndex < s_servoCount && s_servos[servoIndex].info.isActive) { + // pulse this channel low if activated + digitalWrite(s_servos[servoIndex].info.pin, LOW); + } + timer->nextChannel(); + } + + servoIndex = SERVO_INDEX(timer->timerId(), timer->getCurrentChannel()); + + if (servoIndex < s_servoCount && timer->getCurrentChannel() < SERVOS_PER_TIMER) { + timer->SetPulseCompare(timer->usToTicks(s_servos[servoIndex].usPulse) - c_CycleCompensation); + + if (s_servos[servoIndex].info.isActive) { // check if activated + digitalWrite(s_servos[servoIndex].info.pin, HIGH); // its an active channel so pulse it high + } + } + else { + // finished all channels so wait for the refresh period to expire before starting over + // allow a few ticks to ensure the next match is not missed + uint32_t refreshCompare = timer->usToTicks(REFRESH_INTERVAL); + if ((timer->GetCycleCount() + c_CycleCompensation * 2) < refreshCompare) { + timer->SetCycleCompare(refreshCompare - c_CycleCompensation); + } + else { + // at least REFRESH_INTERVAL has elapsed + timer->SetCycleCompare(timer->GetCycleCount() + c_CycleCompensation * 2); + } + + timer->setEndOfCycle(); + } + + interrupts(); +} + +static void initISR(ServoTimerSequence timerId) +{ +#if !defined (SERVO_EXCLUDE_TIMER0) + if (timerId == ServoTimerSequence_Timer0) + s_servoTimer0.InitInterrupt([]() {Servo_Handler(&s_servoTimer0); }); +#endif +#if !defined (SERVO_EXCLUDE_TIMER1) + if (timerId == ServoTimerSequence_Timer1) + s_servoTimer1.InitInterrupt([]() {Servo_Handler(&s_servoTimer1); }); +#endif +} + +static void finISR(ServoTimerSequence timerId) +{ +#if !defined (SERVO_EXCLUDE_TIMER0) + if (timerId == ServoTimerSequence_Timer0) + s_servoTimer0.StopInterrupt(); +#endif +#if !defined (SERVO_EXCLUDE_TIMER1) + if (timerId == ServoTimerSequence_Timer1) + s_servoTimer1.StopInterrupt(); +#endif +} + +// returns true if any servo is active on this timer +static boolean isTimerActive(ServoTimerSequence timerId) +{ + for (uint8_t channel = 0; channel < SERVOS_PER_TIMER; channel++) { + if (s_servos[SERVO_INDEX(timerId, channel)].info.isActive) { + return true; + } + } + return false; +} + +//------------------------------------------------------------------- +// Servo class methods + +Servo::Servo() +{ + if (s_servoCount < MAX_SERVOS) { + // assign a servo index to this instance + _servoIndex = s_servoCount++; + // store default values + s_servos[_servoIndex].usPulse = DEFAULT_PULSE_WIDTH; + } + else { + _servoIndex = INVALID_SERVO; // too many servos + } +} + +uint8_t Servo::attach(int pin) +{ + return attach(pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH); +} + +uint8_t Servo::attach(int pin, int minUs, int maxUs) +{ + ServoTimerSequence timerId; + + Serial.print("_servoIndex "); + Serial.println(_servoIndex); + + if (_servoIndex < MAX_SERVOS) { + pinMode(pin, OUTPUT); // set servo pin to output + digitalWrite(pin, LOW); + s_servos[_servoIndex].info.pin = pin; + + // keep the min and max within 200-3000 us, these are extreme + // ranges and should support extreme servos while maintaining + // reasonable ranges + _maxUs = max(250, min(3000, maxUs)); + _minUs = max(200, min(_maxUs, minUs)); + + // initialize the timerId if it has not already been initialized + timerId = SERVO_INDEX_TO_TIMER(_servoIndex); + if (!isTimerActive(timerId)) { + initISR(timerId); + } + s_servos[_servoIndex].info.isActive = true; // this must be set after the check for isTimerActive + } + return _servoIndex; +} + +void Servo::detach() +{ + ServoTimerSequence timerId; + + s_servos[_servoIndex].info.isActive = false; + timerId = SERVO_INDEX_TO_TIMER(_servoIndex); + if (!isTimerActive(timerId)) { + finISR(timerId); + } +} + +void Servo::write(int value) +{ + // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds) + if (value < MIN_PULSE_WIDTH) { + // assumed to be 0-180 degrees servo + value = max(0, min(180, value)); + value = map(value, 0, 180, _minUs, _maxUs); + } + writeMicroseconds(value); +} + +void Servo::writeMicroseconds(int value) +{ + // ensure channel is valid + if ((_servoIndex < MAX_SERVOS)) { + // ensure pulse width is valid + value = max(_minUs, min(_maxUs, value)); + + s_servos[_servoIndex].usPulse = value; + } +} + +int Servo::read() // return the value as degrees +{ + return map(readMicroseconds(), _minUs, _maxUs, 0, 180); +} + +int Servo::readMicroseconds() +{ + unsigned int pulsewidth; + if (_servoIndex != INVALID_SERVO) { + pulsewidth = s_servos[_servoIndex].usPulse; + } + else { + pulsewidth = 0; + } + + return pulsewidth; +} + +bool Servo::attached() +{ + return s_servos[_servoIndex].info.isActive; +} + +#endif + diff --git a/hardware/esp8266com/esp8266/libraries/Servo/src/esp8266/ServoTimers.h b/hardware/esp8266com/esp8266/libraries/Servo/src/esp8266/ServoTimers.h new file mode 100644 index 0000000000..56ee18671b --- /dev/null +++ b/hardware/esp8266com/esp8266/libraries/Servo/src/esp8266/ServoTimers.h @@ -0,0 +1,227 @@ +/* + Copyright (c) 2015 Michael C. Miller. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +// +// Defines for timer abstractions used with Servo library +// +// ServoTimerSequence enumerates the sequence that the timers should be allocated +// ServoTimerSequence_COUNT indicates how many timers are available. +// +enum ServoTimerSequence { + +#if !defined (SERVO_EXCLUDE_TIMER0) + ServoTimerSequence_Timer0, +#endif + +#if !defined (SERVO_EXCLUDE_TIMER1) + ServoTimerSequence_Timer1, +#endif + + ServoTimerSequence_COUNT +}; + + +#if !defined (SERVO_EXCLUDE_TIMER0) + +struct ServoTimer0 +{ +public: + ServoTimer0() + { + setEndOfCycle(); + } + + + uint32_t usToTicks(uint32_t us) const + { + return (clockCyclesPerMicrosecond() * us); // converts microseconds to tick + } + uint32_t ticksToUs(uint32_t ticks) const + { + return (ticks / clockCyclesPerMicrosecond()); // converts from ticks back to microseconds + } + + void InitInterrupt(timercallback handler) + { + timer0_isr_init(); + timer0_attachInterrupt(handler); + } + + void ResetInterrupt() {}; // timer0 doesn't have a clear interrupt + + void StopInterrupt() + { + timer0_detachInterrupt(); + } + + void SetPulseCompare(uint32_t value) + { + timer0_write(ESP.getCycleCount() + value); + } + + void SetCycleCompare(uint32_t value) + { + timer0_write(_cycleStart + value); + } + + uint32_t GetCycleCount() const + { + return ESP.getCycleCount() - _cycleStart; + } + + + void StartCycle() + { + _cycleStart = ESP.getCycleCount(); + _currentChannel = 0; + } + + int8_t getCurrentChannel() const + { + return _currentChannel; + } + + void nextChannel() + { + _currentChannel++; + } + + void setEndOfCycle() + { + _currentChannel = -1; + } + + bool isEndOfCycle() const + { + return (_currentChannel == -1); + } + + ServoTimerSequence timerId() const + { + return ServoTimerSequence_Timer0; + } + +private: + volatile uint32_t _cycleStart; + volatile int8_t _currentChannel; +}; + +#endif + + +#if !defined (SERVO_EXCLUDE_TIMER1) + +struct ServoTimer1 +{ +public: + ServoTimer1() + { + setEndOfCycle(); + } + + + uint32_t usToTicks(uint32_t us) const + { + return (clockCyclesPerMicrosecond() / 16 * us); // converts microseconds to tick + } + uint32_t ticksToUs(uint32_t ticks) const + { + return (ticks / clockCyclesPerMicrosecond() * 16); // converts from ticks back to microseconds + } + + void InitInterrupt(timercallback handler) + { + timer1_isr_init(); + timer1_attachInterrupt(handler); + timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE); + timer1_write(usToTicks(REFRESH_INTERVAL)); + } + + void ResetInterrupt() {}; // timer1 doesn't have a clear interrupt + + void StopInterrupt() + { + timer1_detachInterrupt(); + } + + void SetPulseCompare(uint32_t value) + { + _cycleTicks += value; + timer1_write(value); + } + + void SetCycleCompare(uint32_t value) + { + if (value <= _cycleTicks) + { + value = 1; + } + else + { + value -= _cycleTicks; + } + timer1_write(value); + } + + uint32_t GetCycleCount() const + { + return _cycleTicks; + } + + + void StartCycle() + { + _cycleTicks = 0; + _currentChannel = 0; + } + + int8_t getCurrentChannel() const + { + return _currentChannel; + } + + void nextChannel() + { + _currentChannel++; + } + + void setEndOfCycle() + { + _currentChannel = -1; + } + + bool isEndOfCycle() const + { + return (_currentChannel == -1); + } + + ServoTimerSequence timerId() const + { + return ServoTimerSequence_Timer1; + } + +private: + volatile uint32_t _cycleTicks; + volatile int8_t _currentChannel; +}; + +#endif + + + + diff --git a/hardware/esp8266com/esp8266/libraries/TFT_Touch_Shield_V2/TFTv2.cpp b/hardware/esp8266com/esp8266/libraries/TFT_Touch_Shield_V2/TFTv2.cpp index a8ba79f832..48f1c910c8 100644 --- a/hardware/esp8266com/esp8266/libraries/TFT_Touch_Shield_V2/TFTv2.cpp +++ b/hardware/esp8266com/esp8266/libraries/TFT_Touch_Shield_V2/TFTv2.cpp @@ -30,7 +30,7 @@ void TFT::TFTinit (void) pinMode(4, OUTPUT); pinMode(15, OUTPUT); SPI.begin(); - SPI.setClockDivider(2); + SPI.setClockDivider(SPI_CLOCK_DIV2); TFT_CS_HIGH; TFT_DC_HIGH; @@ -570,4 +570,4 @@ INT8U TFT::drawFloat(float floatNumber,INT16U poX, INT16U poY,INT16U size,INT16U TFT Tft=TFT(); /********************************************************************************************************* END FILE -*********************************************************************************************************/ \ No newline at end of file +*********************************************************************************************************/ diff --git a/hardware/esp8266com/esp8266/libraries/esp8266/examples/Blink/Blink.ino b/hardware/esp8266com/esp8266/libraries/esp8266/examples/Blink/Blink.ino new file mode 100644 index 0000000000..578f368864 --- /dev/null +++ b/hardware/esp8266com/esp8266/libraries/esp8266/examples/Blink/Blink.ino @@ -0,0 +1,24 @@ +/* + ESP8266 Blink by Simon Peter + Blink the blue LED on the ESP-01 module + This example code is in the public domain + + The blue LED on the ESP-01 module is connected to GPIO1 + (which is also the TXD pin; so we cannot use Serial.print() at the same time) + + Note that this sketch uses BUILTIN_LED to find the pin with the internal LED +*/ + +void setup() { + pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output +} + +// the loop function runs over and over again forever +void loop() { + digitalWrite(BUILTIN_LED, LOW); // Turn the LED on (Note that LOW is the voltage level + // but actually the LED is on; this is because + // it is acive low on the ESP-01) + delay(1000); // Wait for a second + digitalWrite(BUILTIN_LED, HIGH); // Turn the LED off by making the voltage HIGH + delay(2000); // Wait for two seconds (to demonstrate the active low LED) +} diff --git a/hardware/esp8266com/esp8266/libraries/esp8266/examples/BlinkWithoutDelay/BlinkWithoutDelay.ino b/hardware/esp8266com/esp8266/libraries/esp8266/examples/BlinkWithoutDelay/BlinkWithoutDelay.ino new file mode 100644 index 0000000000..740211d6d1 --- /dev/null +++ b/hardware/esp8266com/esp8266/libraries/esp8266/examples/BlinkWithoutDelay/BlinkWithoutDelay.ino @@ -0,0 +1,33 @@ +/* + ESP8266 BlinkWithoutDelay by Simon Peter + Blink the blue LED on the ESP-01 module + Based on the Arduino Blink without Delay example + This example code is in the public domain + + The blue LED on the ESP-01 module is connected to GPIO1 + (which is also the TXD pin; so we cannot use Serial.print() at the same time) + + Note that this sketch uses BUILTIN_LED to find the pin with the internal LED +*/ + +int ledState = LOW; + +unsigned long previousMillis = 0; +const long interval = 1000; + +void setup() { + pinMode(BUILTIN_LED, OUTPUT); +} + +void loop() +{ + unsigned long currentMillis = millis(); + if(currentMillis - previousMillis >= interval) { + previousMillis = currentMillis; + if (ledState == LOW) + ledState = HIGH; // Note that this switches the LED *off* + else + ledState = LOW; // Note that this switches the LED *on* + digitalWrite(BUILTIN_LED, ledState); + } +} diff --git a/hardware/esp8266com/esp8266/platform.txt b/hardware/esp8266com/esp8266/platform.txt index c2cfa053e5..2695115c28 100644 --- a/hardware/esp8266com/esp8266/platform.txt +++ b/hardware/esp8266com/esp8266/platform.txt @@ -74,12 +74,12 @@ recipe.objcopy.eep.pattern= ## Create hex #recipe.objcopy.hex.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.hex" -recipe.objcopy.hex.pattern="{runtime.tools.esptool.path}/{compiler.esptool.cmd}" -eo "{build.path}/{build.project_name}.elf" -bo "{build.path}/{build.project_name}_00000.bin" -bm {build.flash_mode} -bf {build.flash_freq} -bz {build.flash_size} -bs .text -bs .data -bs .rodata -bc -ec -eo "{build.path}/{build.project_name}.elf" -es .irom0.text "{build.path}/{build.project_name}_10000.bin" -ec +recipe.objcopy.hex.pattern="{runtime.tools.esptool.path}/{compiler.esptool.cmd}" -eo "{runtime.platform.path}/bootloaders/eboot/eboot.elf" -bo "{build.path}/{build.project_name}.bin" -bm {build.flash_mode} -bf {build.flash_freq} -bz {build.flash_size} -bs .text -bp 4096 -ec -eo "{build.path}/{build.project_name}.elf" -bs .irom0.text -bs .text -bs .data -bs .rodata -bc -ec ## Compute size recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf" -recipe.size.regex=^(?:\.text|\.data|\.rodata|\.irom0\.text|)\s+([0-9]+).* -#recipe.size.regex.data=^(?:\.data|\.bss|\.noinit)\s+([0-9]+).* +recipe.size.regex=^(?:\.irom0\.text|\.text|\.data|\.rodata|)\s+([0-9]+).* +recipe.size.regex.data=^(?:\.data|\.rodata|\.bss)\s+([0-9]+).* #recipe.size.regex.eeprom=^(?:\.eeprom)\s+([0-9]+).* # ------------------------------ @@ -91,4 +91,4 @@ tools.esptool.path={runtime.platform.path}/tools tools.esptool.upload.protocol=esp tools.esptool.upload.params.verbose=-vv tools.esptool.upload.params.quiet= -tools.esptool.upload.pattern="{path}/{cmd}" {upload.verbose} -cd {upload.resetmethod} -cb {upload.speed} -cp "{serial.port}" -ca 0x00000 -cf "{build.path}/{build.project_name}_00000.bin" -ca 0x10000 -cf "{build.path}/{build.project_name}_10000.bin" +tools.esptool.upload.pattern="{path}/{cmd}" {upload.verbose} -cd {upload.resetmethod} -cb {upload.speed} -cp "{serial.port}" -ca 0x00000 -cf "{build.path}/{build.project_name}.bin" diff --git a/hardware/esp8266com/esp8266/tools/sdk/include/ets_sys.h b/hardware/esp8266com/esp8266/tools/sdk/include/ets_sys.h index 7908699bb5..2aaa3321a2 100644 --- a/hardware/esp8266com/esp8266/tools/sdk/include/ets_sys.h +++ b/hardware/esp8266com/esp8266/tools/sdk/include/ets_sys.h @@ -39,10 +39,14 @@ typedef struct _ETSTIMER_ { typedef void (*int_handler_t)(void*); -#define ETS_SPI_INUM 2 +#define ETS_SLC_INUM 1 +#define ETS_SPI_INUM 2 #define ETS_GPIO_INUM 4 #define ETS_UART_INUM 5 #define ETS_UART1_INUM 5 +#define ETS_CCOMPARE0_INUM 6 +#define ETS_SOFT_INUM 7 +#define ETS_WDT_INUM 8 #define ETS_FRC_TIMER1_INUM 9 /* use edge*/ #define ETS_INTR_LOCK() \ @@ -51,26 +55,61 @@ typedef void (*int_handler_t)(void*); #define ETS_INTR_UNLOCK() \ ets_intr_unlock() +#define ETS_INTR_ENABLE(inum) \ + ets_isr_unmask((1< 0)?NOT_A_PIN:0) +#define digitalPinToInterrupt(p) (((p) < EXTERNAL_NUM_INTERRUPTS)?p:NOT_A_PIN) +#define digitalPinHasPWM(p) (((p) < NUM_DIGITAL_PINS)?p:NOT_A_PIN) + +static const uint8_t SDA = 4; +static const uint8_t SCL = 5; + +static const uint8_t SS = 15; +static const uint8_t MOSI = 13; +static const uint8_t MISO = 12; +static const uint8_t SCK = 14; + +static const uint8_t BUILTIN_LED = 0; + +static const uint8_t A0 = 17; + +// These serial port names are intended to allow libraries and architecture-neutral +// sketches to automatically default to the correct port name for a particular type +// of use. For example, a GPS module would normally connect to SERIAL_PORT_HARDWARE_OPEN, +// the first hardware serial port whose RX/TX pins are not dedicated to another use. +// +// SERIAL_PORT_MONITOR Port which normally prints to the Arduino Serial Monitor +// +// SERIAL_PORT_USBVIRTUAL Port which is USB virtual serial +// +// SERIAL_PORT_LINUXBRIDGE Port which connects to a Linux system via Bridge library +// +// SERIAL_PORT_HARDWARE Hardware serial port, physical RX & TX pins. +// +// SERIAL_PORT_HARDWARE_OPEN Hardware serial ports which are open for use. Their RX & TX +// pins are NOT connected to anything by default. +#define SERIAL_PORT_MONITOR Serial +#define SERIAL_PORT_USBVIRTUAL Serial +#define SERIAL_PORT_HARDWARE Serial +#define SERIAL_PORT_HARDWARE_OPEN Serial + +#endif /* Pins_Arduino_h */ + diff --git a/libraries/Adafruit_ILI9341/Adafruit_ILI9341.cpp b/libraries/Adafruit_ILI9341/Adafruit_ILI9341.cpp index 05d376aed9..2af27e83e6 100644 --- a/libraries/Adafruit_ILI9341/Adafruit_ILI9341.cpp +++ b/libraries/Adafruit_ILI9341/Adafruit_ILI9341.cpp @@ -264,7 +264,7 @@ uint16_t Adafruit_ILI9341::getWidth(void){ #ifdef SPI_HAS_TRANSACTION #ifdef ESP8266 -SPISettings spiSettings = SPISettings(SPI_MAX_SPEED, MSBFIRST, SPI_MODE0); +SPISettings spiSettings = SPISettings(ESP8266_CLOCK, MSBFIRST, SPI_MODE0); #else SPISettings spiSettings = SPISettings(8000000, MSBFIRST, SPI_MODE0); #endif