Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
wolfgangr opened this issue Jan 14, 2017 · 21 comments
Closed

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

wolfgangr opened this issue Jan 14, 2017 · 21 comments

Comments

@wolfgangr
Copy link

wolfgangr commented Jan 14, 2017

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
Copy link
Author

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:

  • The ENC28J80 handles OSI layer 2 (and by that access to physical layer1, of course). It does not deal with IP adresses or even higher protocol levels.
  • Neither the "UPIP" nor the "Cicero" drivers follow a clean separation of OSI layers, but follow a more hands-on approach of getting the job done, mixing up the OSI layers.
  • NodeMCU utilizes the lwIP framework http://savannah.nongnu.org/projects/lwip/ as TCP/IP stack implementation, which provides all layer 3 and above services and a clean interface to layer 2 implementations. Seems to be a widely used standard on embedded systems.

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
Copy link
Author

... 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
Copy link
Author

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
Copy link
Author

wolfgangr commented Jan 17, 2017

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
Copy link
Author

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:

  • /app/modules/spi.c provides the LUA-Binding
  • /app/platform/platform.h appears to provide an layer of abstracted platform agnostic calls, correct?
  • driver/spi.c provides platform specific calls into the SDK low level library.

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
Copy link
Member

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
Copy link
Member

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
Copy link
Author

regarding Interface =(2)= system helpers

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

  • a 12 µs delay loop up_udelay(12)
  • some polling loops with a timeout given by #define ENC_POLLTIMEOUT 50 . The value refers to "system ticks". By dissecting the delay calibration routine, I think we can trace them back to equal 1 ms duration. So we talk about polling until up to 50 ms timeout.

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

  • enable interrupt
  • delay loop
  • disable interrupt
  • do what's to be done
    This does neither fit into the complexity of nowaday concurrent systems requirement nor does it meet the power saving to really sleep the CPU when there is notihing to do.

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

@wolfgangr
Copy link
Author

@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
Copy link
Author

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
Copy link
Author

@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
Copy link

devyte commented Jan 18, 2017

@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
Copy link
Author

@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
Copy link
Author

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
Copy link
Author

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
Copy link

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

@jmattsson
Copy link
Member

@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
Copy link
Member

<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
Copy link

stale bot commented Jun 7, 2019

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 stale bot added stale and removed stale labels Jun 7, 2019
@stale
Copy link

stale bot commented Jun 4, 2020

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 stale bot added the stale label Jun 4, 2020
@stale stale bot closed this as completed Jun 18, 2020
@wilhelmy
Copy link

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants