nodemcu / nodemcu-firmware

Lua based interactive firmware for ESP8266, ESP8285 and ESP32
https://nodemcu.readthedocs.io
MIT License
7.64k stars 3.12k forks source link

Wired Ethernet module, using ENC28J60 , W5100 or similiar Hardware #1725

Closed wolfgangr closed 4 years ago

wolfgangr commented 7 years ago

Missing feature

Wired ethernet connectivity.

Justification

IoT in harsh environments and/or demanding reliability and/or low power may be better of with wired ethernet. I'd like to put some modules on my heater, my farm, my tractors, my machinery...

Workarounds

May use CAN, serial communication, I2C, SPI on short distance or relay WIFI over openWRT AP or Raspi in AP mode.

Road to solution

The ENC28J60 is easily available as a breakout module from asian sources < 3 EUR for Arduinos etc.

There are already existing libraries for the ENC28J60 on ESP8266, e.g. https://github.com/Cicero-MF/esp_enc28j60 https://github.com/UIPEthernet/UIPEthernet They do not yet fit into the framwork of the nodeMCU LUA architecture, but I hope they may be adopted.

My possible contributions: I have no clue where to look for the hooks. But I'm sure there are some in the existing WIFI IP stack. My C coding knowledge is limited, but with some assistance from the community, I could try my best.

wolfgangr commented 7 years ago

For the loose end, I started a thread at the forum http://www.esp8266.com/viewtopic.php?f=24&t=13342 I'll keep consolidated info here.

Preliminary conclusions after a first scrutiny of datasheet, NodeMCU and the mentioned libs:

I conclude, instead of dismanteling hands-on mixed-layered libraries, it may be better to use existing layer 2 implementations (aka drivers ) for the enc28j60 on lwIP, even if they were written for other platforms.

From googled results, I selected two candidates for a closer look:

wolfgangr commented 7 years ago

... still diving in manuals ... ESP8266EX SDK Programming Guide , Chapter 3.8 "Network APIs": I see there is a whole Network API already integrated in the SDK. Would be great if we could use it. But I'm afraid, we can't dismantle it from the WIFI, due to the opaque nature of the SDK, or can we? Why had NoceMCU architects integrated lwIP if we could, right? Would be glad if sbdy could teach me the opposite ...

wolfgangr commented 7 years ago

Things getting shape now. For further reference, I'll propose some preliminary sketch of the architecture:

OSI     Implementation

7      User Progs        
:         +-payload app protocols (http , mqtt , mail)
:         +---Helper app protocols  ( DHCP, DNS ... )
:         +----- Layer 4 Tools (TCP / UDP Admin, ICMP (ping....)
:         +------- IP Admin (IP addresses, routes, ...)
5         |
        ===========(6)==========      
       +-------------------------+
3+4    |         lw IP           +
       +-------------------------+      LUA admin and test interface
        ===========(5)===========   ========(4)=======
       +----------------------------------------------+
2u     |             enc 28j60 DRIVER                 |
       +----------------------------------------------+
        ========(1)=======         ========(2)=========
       +--------------------+      +------------------+
(--)   |  Module SPI-libs   |      |  Module timing   |
       +--------------------+      +------------------+
        ========(3)=========
       +-----------------------+
2l     |  ENC 28 J 60 Hardware |
1u     |                       |
       +-----------------------+
1l      ====== ETHERNET =======

=(1)= SPI calls =(2)= System helper calls =(3)= SPI physical connectivity =(4)= driver admin and test interface =(5)= network operation and data interface =(6)= anything above OSI layer 2 is hopefully not our business

wolfgangr commented 7 years ago

regarding the upside interfaces, I hope that lwIP will do most of the job. So getting ==(5)== right , ==(6)== and may be even ==(4)== to some extent is expected to be provided by lwIP - which remains to be checked.

wolfgangr commented 7 years ago

regarding Interface =(1)= SPI lib

I start with my favourate driver template: The SPI interface is defined thy these prototypes in https://github.com/wolfgangr/enc28j60/blob/master/enc28j60.h

* Implement SPI Slave selection and deselection.
void ENC_SPI_Select(bool select);

* Implement SPI single byte send and receive.
uint8_t ENC_SPI_SendWithoutSelection(uint8_t command);

* Implement SPI single byte send and receive. 
uint8_t ENC_SPI_Send(uint8_t command);

 * Implement SPI buffer send and receive.
void ENC_SPI_SendBuf(uint8_t *master2slave, uint8_t *slave2master, uint16_t bufferSize);

For the other edge, let's dissect the nodemcu-firmware SPI stack from User to metal:

According to the Espressif IoT SDK Documentation, the SPI provided by the SDK only refer to flash memory interface. I found no documented SPI functions in the SDK for interfacing the outside world.

We don't want to reinvent the wheel and double maintenance load. So I think the best place to hook in the system abstracted platform.h layer.

devsaurus commented 7 years ago

I agree with your findings, the SPI platform layer is the right choice.

A recommendation regarding SPI setup: let the user configure the SPI module from Lua land with spi.setup() and don't assume/hardcode the config internally. Same for the SS / CS pin - make it a parameter to the enc driver somehow. This would allow a suitable degree of freedom for system integration.

SS / CS pin should be controlled by the platform_gpio_* functions of course.

devsaurus commented 7 years ago

I'd expect that new functionality for managing the routing tables will be needed. So far we had a trivial setup with just one interface. Adding another phy will probably require to set up default routes etc. from Lua land. Would something like a net.route submodule be the right place for this?

wolfgangr commented 7 years ago

regarding Interface =(2)= system helpers

A survey of https://github.com/wolfgangr/enc28j60/blob/master/enc28j60.c yields two timing requirements:

Let's compare them with the nodemcu coding guide: https://nodemcu.readthedocs.io/en/master/en/lua-developer-faq/#when-and-why-should-i-avoid-using-tmrdelay The 12 µs delay can easily implemented by a C-equivalent tmr.delay() , which in https://github.com/wolfgangr/nodemcu-firmware/blob/dev/app/modules/tmr.c is implemented by os_delay_us(us)

The 50 ms timeout is far above the sound 8ms limit of the NodeMCU Documentation. Do we have to rewrite the polling to something like this?

function do_poll (start-time, some params) 
   poll once
   if (success) return (polled result)
   if (current-time - start-time > ENC_POLLTIMEOUT) return ("polling TIMOUT failure")
   set timer (polling interval)
end

register (timer, do_poll)
call (timer, very-short)

hm.... while this looks simple in the LUA docu, how does it look like in C? And how does fit into the lwIP framework? Even if we implement our driver in this way, the calling lwIP still may run until the polling timeout is reached. Or does lwIP follow an event driven model as well - but then our driver template would not fit. Or does it not matter to hang conceptually in a C wait, as long as we allow interrupts that keep the rest of the sytem going?

Can we then even stay with the loops as they are? Isn't there any interruptable wait code laying around? Some kind of interruptable wait/sleep... µs ? Can we borrow from the pthread mimics found in the driver template?

In good old hex coding times on 6502 bare metal, we wrote

I don't think I have to reinvent the wheel, have I ?

wolfgangr commented 7 years ago

@devsaurus write

I'd expect that new functionality for managing the routing tables will be needed. So far we had a trivial setup with just one interface. Adding another phy will probably require to set up default routes etc. from Lua land. Would something like a net.route submodule be the right place for this?

I'd hope that lwIP might provide some of this functionality. Is there a LUA interface for lwIP

But don't we overload the ESP platform with routing?

From my own point of need, I would not require routing. Recently I bought a module for 25 bucks from Olimex wiht openWRT on it, including Wlan, 2 ethernet ports broken out (another 3 available at some pins). Available for 15 €/$ as a bare module. This is the stuff to make embedded routers of.

I am looking for a single sensor/actor interface platform where I can connect the same type of sensor either by LAN or by WLAN, presumaply using MQTT. So I would simply switch of the WLAN when I am on Ethernet.

But of course I see that others might have different Ideas. I even remeber having read of "enabling IP forwarding" in ESP context. I mean you can have more than one IP on the same interface anyway. Just think of elaborated WLAN relaying.

And yes, there is the issue of level 7 relaying. Receiving a mqqt message on one foot, sending an email, for example, on the other. Binding differnt sockets to different interfaces.

I'll keep an eye on it, not to break it, if it is possible without too much effort. I see that lwIP ist the next candidate for dissection.

wolfgangr commented 7 years ago

Maybe I found an Answer to my question above

Can we borrow from the pthread mimics found in the driver template?

"Protothreads" is invented by Adam Dunkels, the creator of the lwIP library. http://dunkels.com/adam/pt/

Protothreads are extremely lightweight stackless threads designed for severely memory constrained systems, such as small embedded systems or wireless sensor network nodes. Protothreads provide linear code execution for event-driven systems implemented in C. Protothreads can be used with or without an underlying operating system to provide blocking event-handlers. Protothreads provide sequential flow of control without complex state machines or full multi-threading.

And the manual states

Using protothreads in a project is easy: simply copy the files pt.h, lc.h and lc-switch.h into the include files directory of the project, and #include "pt.h" in all files that should use protothreads.

This is exactly what the driver does.

However, grepping through the nodeMCU tree does not yield any use of protothreads yet. Would be great to learn wheter there is a deeper reason against its use.

wolfgangr commented 7 years ago

@devsaurus wrote

I'd expect that new functionality for managing the routing tables will be needed.....

As I expected, lwIP should provide this functionality - start looking here: http://lwip.wikia.com/wiki/Network_interfaces_management I hope that the lwIP implementation in NodeMCU firmware ist not too much tweaked or cut down.

Unfortunately, only a small part of the lwIP API is wrapped in Lua callers yet. Both Lua and lwIP are said to be at home in embedded IoT-like sensor systems. So I hope there are chances that they have found each other already, and somebody else has engaged in this job ;-)

Would something like a net.route submodule be the right place for this?

I'd propose net.netif or netif or net.if, resembling the lwIP nomenclature. There is no full fledged routing table management available in lwIP. Only one IP per Interface, one network mask and one gateway. And one overall default gateway. You can however assign multiple IP adresses to the same interfaces, as far as I could figure out right now. I'ts an IoT device, not a router.

For the development stage, it would really be great to interacitvely inspect and call arbitrary C-code from Lua-Land. Is this possible? Would be great to have pointer to start...

devyte commented 7 years ago

@wolfgangr I think your undertaking is just awesome. Please know that this would be a great addition to the ESP.

About routing, you probably already realized this, but the ESP already has two interfaces: the station and the ap. Currently, they don't really talk to each other, unless you compile lwip with some special defines*, but I think a formal routing api would fix that. An ethernet interface would add a third interface. In addition, having a routing api could be a precursor to meshing with ESPs. Espressif published a mesh demo a some point, and I remember thinking that it probably used lwip routing under the hood somewhere, but I didn't look into it due to life getting in the way. Anyways, I thought all this could be of interest to you.

*I tried this. I used the ESP as a makeshift wifi range extender, where the ESP was between the wlan router and my laptop. It works, I was even able to stream netflix through the ESP without issues, but it required routing rules in the wlan router, which is troublesome and inflexible.

wolfgangr commented 7 years ago

@devyte

but I didn't look into it due to life getting in the way.

This i a nice way to tell. Hope there is no (C) on it ;-)

having a routing api could be a precursor to meshing with ESPs.

I knew that people are out there with Ideas beyond mine :-O

Started a tutorial last night of lua <-> lib surfacing http://blog.mclemon.io/esp8266-contributing-to-the-nodemcu-ecosystem

Maybe the netif gear would be a valuable second lesson to try it. Would give us roughly an equivalent of ifconfig known from linux.

Albeit I haven't yet found a routine to list all available interfaces. This would have easily told everybody that AP and station are implmented as two interfaces on top of the same PHY. I hope the internet will know more.

But first, live gets into the way ;-)

wolfgangr commented 7 years ago

Head bangs metal :-( How can I debug boot loops? How do linker mapfile adresses match objdump adresses? Details here: http://www.esp8266.com/viewtopic.php?f=24&t=13342&p=61117#p61117" Any help appreciated!

wolfgangr commented 7 years ago

After some training loopings in the nodemcu ecosystem, (somewhat successful in terms of learning, but not yet so much in usable outcome) I'm reconsidering my plans right now. I've learned that the ESP8266 has quite some quirks regarding hardware constraints, timing strategies and programming model.

As I can estimate at the moment, these problems (referring to interface layers =(1)= and =(2)= in above sketch outweight the complexity of interface =(5)= of connection to the lwIP machinery.

These induces me to rate down the idea of adapting lwIP drivers to nodeMCU and rate up existing drivers for the ESP SDK and fix the lwIP interface instead. From the links in the top post, I see that UIPEthernet is written in C++ . This adds another layer of complexity, since I do not yet find such in nodeMCU firmware, and I'm by no way an experienced C / C++ specialist.

For the moment, this leaves the Cicero-MF driver at the top of my ranking

I just cross-check the lwIP requirements (Chapter 7 of 'THE Dunkles Paper', struct netif in ./app/include/lwip/netif.h). In essence, this boils down to

  /** This function is called by the network device driver
   *  to pass a packet up the TCP/IP stack. ... */
  netif_input_fn input;
  /** This function is called by the IP module when it wants
   *  to send a packet on the interface. This function typically
   *  first resolves the hardware address, then sends the packet. .... */
  netif_output_fn output;

plus some houskeeping addons (init, raw packets for ARP, state change callbacks, ...)

I think I can find those hooks in the Cicero-MF driver. And all the timing, SPIinterfacing etc is ready for the esp-SDK (at least so I hope...). I think I need basically the driver functions . Anything else I hope to leave to lwIP.

So, Cicero-MF-driver will be my first candidate to test.

Cicero-MF commented 7 years ago

I don't mind helping out where I can if needed. I'm just not versed with Lua at all.

jmattsson commented 7 years ago

@wolfgangr Not meaning to hi-jack the issue, but your how-to post was great - would love to see that linked from our docs. PR perhaps? What do you think @marcelstoer?

marcelstoer commented 7 years ago

\<hi-jack> Are you talking about the "How can I debug boot loops?" chapter? I agree it might be helpful but I'm not sure about the linking. I'd much rather see a new FAQ entry, nicely polished and tuned to our style'n structure. Maybe add a new issue so we can re-focus here? \</hi-jack>

stale[bot] commented 5 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] commented 4 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

wilhelmy commented 3 years ago

@wolfgangr Are you still working on this? I've been wondering today whether or not it would be possible to wire esp8266's together using ethernet.