Skip to content

esp8266: esp_wifi netdev driver#10792

Merged
smlng merged 26 commits intoRIOT-OS:masterfrom
gschorcht:esp8266_esp_wifi_netdev
Jan 24, 2019
Merged

esp8266: esp_wifi netdev driver#10792
smlng merged 26 commits intoRIOT-OS:masterfrom
gschorcht:esp8266_esp_wifi_netdev

Conversation

@gschorcht
Copy link
Copy Markdown
Contributor

@gschorcht gschorcht commented Jan 16, 2019

Contribution description

This PR adds a netdev driver for infrastructure mode WiFi for ESP8266 using the built-in WiFi module. Using this netdev driver, ESP8266 can use an existing WiFi network to get connectivity. The netdev driver supports WPA authentication only.

The Wifi network interface (module esp_wifi) and the ESP-NOW network interface (module esp_now #9917)
can be used simultaneously, for example, to realize a border router for a mesh network which uses ESP-NOW.

Testing procedure

  • Compile and flash example/gnrc_networking to at least one ESP8266 node using your AP configuration, e.g.,
    CFLAGS='-DESP_WIFI_SSID=\"<your SSID>\" -DESP_WIFI_PASS=\"your passphrase\"' USEMODULE="esp_wifi" make BOARD=esp8266-esp-12x -C examples/gnrc_networking flash
    
  • Once the application is flashed connect the ESP32 node with any terminal programm with a default baudrate of 115.200 bps.
  • Use ifconfig command to check the existence of the network interface. You should be able to observe an output as follows:
    Iface  7  HWaddr: 5C:CF:7F:80:3F:08  Link: up 
           MTU:1500  HL:64  RTR  
           RTR_ADV  
           Source address length: 6
           Link type: wireless
           inet6 addr: fe80::5ecf:7fff:fe80:3f08  scope: local  VAL
           inet6 group: ff02::2
           inet6 group: ff02::1
           inet6 group: ff02::1:ff80:3f08
           inet6 group: ff02::1a
           
           Statistics for Layer 2
             RX packets 12  bytes 2698
             TX packets 1 (Multicast: 1)  bytes 0
             TX succeeded 0 errors 0
           Statistics for IPv6
             RX packets 0  bytes 0
             TX packets 1 (Multicast: 1)  bytes 64
             TX succeeded 1 errors 0
    
  • Ping any host in LAN.
  • If the router provides a global routing prefix, check with ifconfig that the prefix is set.
    Iface  7  HWaddr: 5C:CF:7F:80:3F:08  Link: up 
           MTU:1440  HL:255  RTR  
           RTR_ADV  
           Source address length: 6
           Link type: wireless
           inet6 addr: fe80::5ecf:7fff:fe80:3f08  scope: local  VAL
           inet6 addr: 2003:c1:e72f:6c40:5ecf:7fff:fe80:3f08  scope: global  VAL
           ...
    
  • Stress testing from LAN with sudo ping6 fe80::<ESP_IID> -Ieth0 -s1392 -i 0.0001 should be stable over hours.
  • It should also be possible to ping simultaneously
    • the ESP8266 node from the LAN with sudo ping6 fe80::<ESP_IID> -Ieth0 -s1392 -i 0.0001
    • the node in the LAN swith ping6 1000 fe80::<LAN_IID> 1392 0 .

Issues/PRs references

This PR depends on PRs #10656 and #10766 and is related to PR #9917.

@gschorcht gschorcht added Area: network Area: Networking Type: new feature The issue requests / The PR implemements a new feature for RIOT Area: drivers Area: Device drivers Platform: ESP Platform: This PR/issue effects ESP-based platforms Area: cpu Area: CPU/MCU ports labels Jan 16, 2019
@smlng
Copy link
Copy Markdown
Member

smlng commented Jan 17, 2019

I think this needs a rebase, as the runtime config stuff is merged now.

@gschorcht
Copy link
Copy Markdown
Contributor Author

gschorcht commented Jan 17, 2019

I think this needs a rebase, as the runtime config stuff is merged now.

Yes, but we could do this later after reviewing it. Travis doesn't fail with doccheck.

@smlng
Copy link
Copy Markdown
Member

smlng commented Jan 18, 2019

get a compile error, something lwip related, maybe need to add the package as a dependency? I tried that but ran in further problems. Here the error when just adding USEMODULE=esp_wifi

esp8266/vendor/espressif/user_interface.h:31:26: fatal error: lwip/ip_addr.h: No such file or directory
 #include "lwip/ip_addr.h"

@gschorcht
Copy link
Copy Markdown
Contributor Author

Hm, this PR depends on PR #10656. My local working branch bases on the branch of this PR. Since the esp_wifi netdev driver will not work without this PR, we should try to get PR #10656 merged first.

@smlng
Copy link
Copy Markdown
Member

smlng commented Jan 18, 2019

Hm, this PR depends on PR #10656. My local working branch bases on the branch of this PR. Since the esp_wifi netdev driver will not work without this PR, we should try to get PR #10656 merged first.

damn, oversaw the deps completely, will try ... sorry for the noise 😞

@gschorcht
Copy link
Copy Markdown
Contributor Author

@smlng I have investigated your compilation problem a bit more. It seems that lwIP header files are not in the toolchain as installed in riotdocker. It's not really clear why at the moment. I'm using a local installation of the toolchain. Therefore, I didn't realize that problem.

@kaspar030 If I can fix it in the toolchain, do you see any chance to get it in riotdocker and murdock in short term? Otherwise, I would have to provide lwIP header files as vendor files for esp8266.

@miri64
Copy link
Copy Markdown
Member

miri64 commented Jan 19, 2019

@smlng I have investigated your compilation problem a bit more. It seems that lwIP header files are not in the toolchain as installed in riotdocker. It's not really clear why at the moment. I'm using a local installation of the toolchain. Therefore, I didn't realize that problem.

@kaspar030 If I can fix it in the toolchain, do you see any chance to get it in riotdocker and murdock in short term? Otherwise, I would have to provide lwIP header files as vendor files for esp8266.

Can we find another solution? I did not try, but I expect issues when someone tries to use esp8266 with the lwip pkg, especially since lwIP's ip_addr.h had always been a hellscape of #ifdefs when porting the newest lwIP release.

@miri64
Copy link
Copy Markdown
Member

miri64 commented Jan 19, 2019

Maybe adding an #ifndef RIOT_VERSION around the #include (or since we imported the files anyways just remove them) would help?

@gschorcht
Copy link
Copy Markdown
Contributor Author

gschorcht commented Jan 19, 2019

Can we find another solution? I did not try, but I expect issues when someone tries to use esp8266 with the lwip pkg, especially since lwIP's ip_addr.h had always been a hellscape of #ifdefs when porting the newest lwIP release.

There will be no chance to use esp8266 with RIOT's lwip package (version 2.1.2) at all since any WiFi based communication (modules esp_now and esp_wifi) requires to use the proprietary libraries from Espressif's SDK which in turn depends on their own port of lwIP version 1.4.1.

Maybe adding an #ifndef RIOT_VERSION around the #include (or since we imported the files anyways just remove them) would help?

Where would you suggest to use this?

@gschorcht
Copy link
Copy Markdown
Contributor Author

gschorcht commented Jan 19, 2019

Maybe, I give some more implementation details to understand why esp8266 WiFi cannot be used without the vendor lwIP.

Unfortunatly, esp8266 WiFi interface is a deep black bock, absolutely no API and no documentation. Even though there are some experiments from reverse enginieering to access the WiFi interface, there is no successful approach. Therefore, the WiFi interface can only be used with Espressif's SDK.

However, this SDK only provides only a high level API for WiFi access on top of the TCP/IP protocol stack which they realized with lwIP version 1.4. Their lwIP port realize the WiFi netif access. That's why their SDK completely depends on their lwIP port.

That is, there is no chance to use the WiFi interface (neither module esp_wifi nor module esp_now) without using Espressif's SDK including their lwIP port which is incompatible with RIOT's lwIP package.

One further implementation detail. Since there are no low level API functions to send a frame or to receive a frame, the only chance to get module esp_wifi working was the trick to override the lwIP's ethernet_intput function to catch incoming frames from the WiFi interface.

/** override lwIP ethernet_intput to get ethernet frames */
extern err_t __real_ethernet_input(struct pbuf *pb, struct netif* netif);

err_t __wrap_ethernet_input(struct pbuf *pb, struct netif* netif)
{
    ESP_WIFI_DEBUG("%p %p", pb, netif);
    _esp_wifi_recv_cb(pb, netif);
    return ERR_OK;
}
LINKFLAGS += -Wl,-wrap=ethernet_input

So what are the options:

  1. We use the vendor scrap for esp8266 to be able to use the WiFi interface to get connectivity with the limitation that RIOT's lwIP package can't be used.

  2. We keep the esp8266 implementation clean from the vendor scrap to avoid conflicts with RIOT's lwIP package but have no WiFi communication. But, using RIOT's lwIP package without network access has not worth.

IMHO, option 1 is much better than option 2.

BTW, even though ESP-NOW uses IEEE802.11 vendor action frames, Espressif's implementation depends also on the SDK and thus on their lwIP port 😟

@gschorcht
Copy link
Copy Markdown
Contributor Author

@smlng I could fix the compilation problem without touching the toolchain.

@gschorcht gschorcht force-pushed the esp8266_esp_wifi_netdev branch from 85198d3 to b34c4d1 Compare January 20, 2019 10:01
@MrKevinWeiss
Copy link
Copy Markdown
Contributor

I think +1 to option 1, I talked to quite a few people that chose other platforms because esp8266 wifi wasn't supported on RIOT. I think something is better than nothing assuming it doesn't corrupt anything else.

@MichelRottleuthner
Copy link
Copy Markdown
Contributor

IMHO, option 1 is much better than option 2.

I'm also voting for option 1. If at some point in the future there will be a cleaner way for getting wifi support on the 8266 we can still improve it.

@kaspar030
Copy link
Copy Markdown
Contributor

I think +1 to option 1

+1 here, too. The esp8266's main reason to exist is providing simple wifi access.

Copy link
Copy Markdown
Member

@smlng smlng left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does work nicely but requires #10656 merged before

@smlng smlng added the State: waiting for other PR State: The PR requires another PR to be merged first label Jan 21, 2019
@MichelRottleuthner
Copy link
Copy Markdown
Contributor

For stress testing the following command is written above:
sudo ping6 fe80::<ESP_IID> -Ieth0 -s1392 -i 0.0001 .
Where does that number actually come from? With an MTU of 1500 bytes shouldn't it be possible to use values up to -s1452 (1500 - 40 - 8)?
I only tested that on an ESP32 but it didn't work. The maximum value that still worked for me was 1437. Adding the 40 bytes for IPv6 and 8 Bytes for ICMP6 there still seem to be 15 bytes missing.
Could there be some mixup of ETHERNET_DATA_LEN and ETHERNET_FRAME_LEN somewhere or am I messing something up here? ;)

@smlng
Copy link
Copy Markdown
Member

smlng commented Jan 21, 2019

maximum I could ping was with 1446B payload including ICMP, i.e.

 ping6 fe80::5a6d:8fff:fe38:2471 1438

where the IP is of the AP I used for testing, with 1439 is didn't work anymore

@smlng
Copy link
Copy Markdown
Member

smlng commented Jan 21, 2019

ping from my desktop node (iMac) to that node only worked up to 1280 bytes (incl. ICMP), but I guess that's somehow expectable for IPv6.

@gschorcht
Copy link
Copy Markdown
Contributor Author

gschorcht commented Jan 21, 2019

Partially good news. With the new ESP8266 RTOS SDK 3.x, Espressif started in September last year to publish a SDK which is quite similar to the ESP-IDF (the ESP32 SDK that was also used for the RIOT port to ESP32).

Initially, the RIOT port for ESP8266 was realized using the ESP8266 NONOS SDK since the ESP8266 RTOS SDK up to version 2.x was also closed source like the NONOS SDK, but additionally bases on FreeRTOS.

I was already thinking about to try a port for the new ESP8266 RTOS SDK 3.x.

Cons:

  • Parts of the ESP8266 port have to be rewritten from scratch to use this new SDK.
  • Some parts of the ESP8266 RTOS SDK depend on FreeRTOS so that an adoption layer has to be written as for the ESP32 port.
  • Some parts are still available only as proprietary binary blobs.

Pros:

  • Even though there are still some proprietary binary blobs, important parts of the SDK become available in source code with version 3.x of the ESP8266 RTOS SDK.
  • All parts that are not required in RIOT can be dropped, including the lwIP.
  • ESP8266 RTOS SDK is very similar to the ESP-IDF so that at least some parts of the code can be reused from the ESP32 port, e.g., the FreeRTOS adoption layer.
  • There is a clear APIs for using the WiFi interface.
  • The current port uses some tricky hacks to get the WiFi interface working.

It's already on my ToDo to take a try, but at moment it seems to be more reasonable to get the existing port working with the WiFi interface.

@gschorcht
Copy link
Copy Markdown
Contributor Author

Even though the MTU for Ethernet is 1.500, my Linux box starts to fragment from 1.440 bytes. That's the reason why I suggested to use -s1392.

Could there be some mixup of ETHERNET_DATA_LEN and ETHERNET_FRAME_LEN somewhere or am I messing something up here? ;)

Good point. There might be a problem, I didn't realize since my frames including MAC header and FCS were never greater than the MTU in tests.

Although only the station interface is needed, the WiFi interface has to be used in SoftAP + Station mode. Otherwise the send function blocks sporadically. Since the SoftAP interface is not used, it is configured with a hidden SSID and a long beacon interval. Connections from other stations are not allowed.
@gschorcht gschorcht added CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR and removed CI: needs squashing Commits in this PR need to be squashed; If set, CI systems will mark this PR as unmergable labels Jan 24, 2019
@gschorcht
Copy link
Copy Markdown
Contributor Author

@sming @MichelRottleuthner Thank you for your review and your patience. Squashed. Let's the what Murdock says.

@gschorcht gschorcht force-pushed the esp8266_esp_wifi_netdev branch from 61af527 to 0920bbb Compare January 24, 2019 08:30
Receiption of a frame in _esp_wifi_recv_cb while sending has no effect and should be possible to increases the performance.
@gschorcht gschorcht force-pushed the esp8266_esp_wifi_netdev branch from b6ecbe8 to 88c65af Compare January 24, 2019 08:40
When the size of a received frame is checked, always the total length should be used instead of the length of the first lwIP pbuf in the pbuf chain. Otherwise, the check that the length does not exceed ETHERNET_MAX_LEN will always be true since the maximum size of one lwIP pbuf in a pbuf chain is 512 bytes.
@gschorcht
Copy link
Copy Markdown
Contributor Author

Of course, esp8266 boards have to be blacklisted.

Copy link
Copy Markdown
Contributor

@MichelRottleuthner MichelRottleuthner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When testing with USEMODULE="esp_wifi" BOARD=esp8266-esp-12x make all flash term everything works as expected.
Though, by mistake I found a small obstacle: when compiling gnrc_networking without providing USEMODULE="esp_wifi" this results in a kernel panic shortly after boot (maybe the watchdog?).
I wouldn't expect this and probably that will pop up quite often as the general usage for gnrc_networking is "just compile without parameters and use". IMHO without esp_wifi there should be just no network interface available, but it should not crash. Is there a way to fix this?

@smlng
Copy link
Copy Markdown
Member

smlng commented Jan 24, 2019

When testing with USEMODULE="esp_wifi" BOARD=esp8266-esp-12x make all flash term everything works as expected.
Though, by mistake I found a small obstacle: when compiling gnrc_networking without providing USEMODULE="esp_wifi" this results in a kernel panic shortly after boot (maybe the watchdog?).
I wouldn't expect this and probably that will pop up quite often as the general usage for gnrc_networking is "just compile without parameters and use". IMHO without esp_wifi there should be just no network interface available, but it should not crash. Is there a way to fix this?

I found that, too - but I think its some other layer/function in GNRC. Because removing all rpl and netstat modules, fixes that and there is no panic anymore. At least for me, it worked when I misspelled esp_wifi to esp-wifi.

@gschorcht
Copy link
Copy Markdown
Contributor Author

gschorcht commented Jan 24, 2019

Indeed, it is a pitfall and I'm not sure how we should handle it.

The reason for this kernel panic is an assert(netif != NULL) in sys/net/gnrc/routing/rpl/gnrc_rpl_auto_init.c since there is no netif if module esp_wifi is not enabled explicitly. esp_wifi is not used as netdev_default by intention due to the following reasons:

  • Module esp_wifi requires to use Espressif SDK which is disabled by default for the reasons documented here.
  • Due to symbol conflicts in vendor library libwpa.so which is required by module esp_wifi with RIOT's crypto and hash modules, esp_wifi cannot be used for applications that use these modules. Therefore, module esp_wifi is not enabled automatically when module netdev_default is used. Instead, if necessary, the application has to add the module esp_wifi in the Makefile. This is documented.

Sure, we could enable module esp_wifi by default when module netdev_default is used, but if you want to use other network devices, for example MRF24J40, you do not need the whole hell of the Espressif SDK. To be honest, whenever possible, we should avoid using the Espressif SDK. A deep black box, eating 50 kbytes of RAM, slowing down the execution and competes with the scheduling of RIOT.

@gschorcht gschorcht added the State: WIP State: The PR is still work-in-progress and its code is not in its final presentable form yet label Jan 24, 2019
@MichelRottleuthner
Copy link
Copy Markdown
Contributor

Whenever possible, I would avoid using the Espressif SDK.

I absolutely agree.
The line in the rpl code is perfectly fine I think.
The actual problem comes form the Makefile.include that sets GNRC_NETIF_NUMOF to 1 by default - which doesn't make sense to me. But I'm currently not sure about the implications on changing this to 0, and as it turns out this is currently the same for all other boards that don't provide a radio. So lets move on here ;)

@miri64
Copy link
Copy Markdown
Member

miri64 commented Jan 24, 2019

To be honest, whenever possible, we should avoid using the Espressif SDK. A deep black box, eating 50 kbytes of RAM, slowing down the execution and competes with the scheduling of RIOT.

So just a usual Friday when using vendor SDKs ;-) (see e.g. #10122).

@smlng
Copy link
Copy Markdown
Member

smlng commented Jan 24, 2019

I hit the green button NOW!

@smlng smlng merged commit 907b761 into RIOT-OS:master Jan 24, 2019
@smlng
Copy link
Copy Markdown
Member

smlng commented Jan 24, 2019

🎉 cheap WiFi in RIOT 🎉 finally 🎉

@MichelRottleuthner
Copy link
Copy Markdown
Contributor

Lets remove the WIP label then :P

@smlng smlng added PR-award-nominee and removed State: WIP State: The PR is still work-in-progress and its code is not in its final presentable form yet labels Jan 24, 2019
@gschorcht
Copy link
Copy Markdown
Contributor Author

gschorcht commented Jan 24, 2019

😟 I added WIP label again by intention since I though it avoids merging. I found one further complete blocking case. I planned to fix it before the merge. Too late for the moment.

@gschorcht
Copy link
Copy Markdown
Contributor Author

Thank you all for your support.

@gschorcht gschorcht deleted the esp8266_esp_wifi_netdev branch January 24, 2019 13:39
@aabadie aabadie added this to the Release 2019.01 milestone Jan 25, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: cpu Area: CPU/MCU ports Area: drivers Area: Device drivers Area: network Area: Networking CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Platform: ESP Platform: This PR/issue effects ESP-based platforms Reviewed: 1-fundamentals The fundamentals of the PR were reviewed according to the maintainer guidelines Reviewed: 2-code-design The code design of the PR was reviewed according to the maintainer guidelines Reviewed: 3-testing The PR was tested according to the maintainer guidelines Reviewed: 4-code-style The adherence to coding conventions by the PR were reviewed according to the maintainer guidelines Reviewed: 5-documentation The documentation details of the PR were reviewed according to the maintainer guidelines Type: new feature The issue requests / The PR implemements a new feature for RIOT

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants