Skip to content

extmod: Add generic network.PPP to work with lwIP #14461

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

Merged
merged 10 commits into from
Aug 29, 2024

Conversation

dpgeorge
Copy link
Member

This PR adds a new network.PPP interface which works on any port that has bare-metal lwIP, eg rp2, stm32, mimxrt.

It has been tested on stm32. A board needs to enable MICROPY_PY_NETWORK_PPP_LWIP and then it can use it as follows:

import network

ppp = network.PPP(uart)
ppp.connect()

while not ppp.isconnected():
    pass

# use `socket` module as usual, etc

ppp.disconnect()

Notes:

  • lwIP has been updated to the latest stable version as part of this PR.
  • Usually the application must first configure the cellular/etc UART link to get it connected and in to PPP mode first (eg ATD*99#), before handing over control to network.PPP.
  • The PPP interface automatically configures the UART IRQ callback to call PPP.poll() on incoming data.

@dpgeorge dpgeorge added the extmod Relates to extmod/ directory in source label May 10, 2024
Copy link

codecov bot commented May 10, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 98.43%. Comparing base (09d070a) to head (35b6a66).
Report is 10 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master   #14461   +/-   ##
=======================================
  Coverage   98.43%   98.43%           
=======================================
  Files         163      163           
  Lines       21295    21295           
=======================================
  Hits        20961    20961           
  Misses        334      334           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link

github-actions bot commented May 10, 2024

Code size report:

   bare-arm:    +0 +0.000% 
minimal x86:    +0 +0.000% 
   unix x64:    +0 +0.000% standard
      stm32:   +68 +0.017% PYBV10
     mimxrt:    +0 +0.000% TEENSY40
        rp2: +8008 +0.884% RPI_PICO_W[incl +980(bss)]
       samd:    +0 +0.000% ADAFRUIT_ITSYBITSY_M4_EXPRESS

@robert-hh
Copy link
Contributor

That PR looks good, supporting the use of e.g. LTE modems or AT-Type WiFi interfaces.
Just a note: As you know RP2 and MIMXRT do not have yet the uart.irq method. That's done in PR #14041.

@dpgeorge dpgeorge added this to the release-1.24.0 milestone May 17, 2024
@dpgeorge
Copy link
Member Author

Thanks @robert-hh for the review.

Just a note: As you know RP2 and MIMXRT do not have yet the uart.irq method.

Yes, thank you for that. That PR will definitely be needed!

@Gadgetoid
Copy link
Contributor

Gadgetoid commented Jul 16, 2024

I've been trying to get this working with a SimCom A7683E on a Pico W. I seem to be able to bring it up to the point where I it's "connected" and I can see the IP address. I can use socket.getaddrinfo, and even socket.connect and socket.send appear to work. However, trying to recv data with a raw socket will stall forever. A basic requests.get just hangs, too.

Setting up the same chip using Linux ppp on a Raspberry Pi 5 will get us ~11k (saturated 115200 baud rate), and the module also works with some custom Python to use AT commands to make web requests.

Any ideas what could be amiss? I guess if this code works on ESP32 and the A76783 works otherwise, it could be related to the RP2's implementation of uart.irq?

To elaborate, getaddrinfo works:

>>> import socket
>>> socket.getaddrinfo("shop.pimoroni.com", 80)
[(2, 1, 0, '', ('23.227.38.74', 80))]

And attempting to request a file:

>>> resp = requests.get("https://shop.pimoroni.com/robots.txt")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "requests/__init__.py", line 182, in get
  File "requests/__init__.py", line 95, in request
OSError: [Errno 104] ECONNRESET
>>> resp = requests.get("http://shop.pimoroni.com/robots.txt")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "requests/__init__.py", line 182, in get
  File "requests/__init__.py", line 127, in request
OSError: [Errno 104] ECONNRESET

(note I seem to be getting ECONNRESET for requests.get, though a socket.recv will just stall)

@victorallume
Copy link
Contributor

I guess if this code works on ESP32 and the A76783 works otherwise,

The ESP32 uses a completely different implementation of PPP (provided by the ESP-IDF) so that's not the best comparison except to prove the cellular module works.

@dpgeorge
Copy link
Member Author

I've been trying to get this working with a SimCom A7683E on a Pico W.
...
Any ideas what could be amiss?

The rp2 port doesn't yet support user-side UART IRQs, so this PR will only work if you either merge #14041 as well as this PR, or call the ppp.poll() method regularly (eg every 50ms using a Timer callback).

Apart from that, you probably need to set a timeout on the UART, eg machine.UART(115200, timeout=1). I found that if the UART is in non-blocking mode (timeout = 0) then sometimes it will fail to receive data and pass it up the PPP stack.

@Gadgetoid
Copy link
Contributor

I merged both this and #14041 though it's done via CI so I'll double check we're actually getting the UART IRQ stuff as expected.

I figured if socket.getaddrinfo works then it's probably not that.

Tried timeout and char_timeout of 1000ms, but didn't try lower values. Will give it another poke, thanks.

For anyone else who wants to poke this on Pico. The build is here: pimoroni/pimoroni-pico#947

@dpgeorge dpgeorge force-pushed the extmod-network-ppp-lwip branch from dad02e5 to 9a94ca6 Compare August 7, 2024 07:59
@nestorld
Copy link

I guess if this code works on ESP32 and the A76783 works otherwise,

The ESP32 uses a completely different implementation of PPP (provided by the ESP-IDF) so that's not the best comparison except to prove the cellular module works.

Hello @victorallume, do you have more details about how the PPP implementation in the ESP32 uses the UART? I’m working on a cmux library to multiplex 4 virtual UARTs over the physical UART of a SIMCom modem. The cmux logic is working well but I need to emulate the UART with a stream object to pass it to network.ppp, something is missing because the REPL connection is crashing when I try to connect the PPP with my virtual UART. Please take a look here for more details: https://github.com/orgs/micropython/discussions/9263
I need to now what the PPP is needing from the UART to replicate it

@victorallume
Copy link
Contributor

do you have more details about how the PPP implementation in the ESP32 uses the UART?

Not sure; all I know is that the ESP32 implementation of PPP comes from the ESP-IDF (which I think uses LWIP internally)

@Gadgetoid
Copy link
Contributor

Gadgetoid commented Aug 13, 2024

Still no luck with the SimCom A7683E on RP2, though I've noticed the UART code has been updated since when I last cut a build (yesterday) and now so I'll try bumping that too.

Edit: Still no dice.

@Gadgetoid
Copy link
Contributor

Gadgetoid commented Aug 19, 2024

Okay I have finally got a response out of PPP, and despite merging the UART IRQ pull-request and seeing the irq method right there on the UART, I was unable to get PPP functioning on RP2 until I added:

tmr = Timer()
tmr.init(mode=Timer.PERIODIC, period=20, callback=ppp.poll)

I've just seen the UART IRQ stuff had recent updates, though, so I guess I should try that again.

Failing that I will try a minimal repro, since it's clear the IRQ stuff is not working for me (or perhaps I am missing some means of enabling it properly?)

Update: To answer my own question, no. The UART IRQ stuff works and the machine_uart_irq_rxidle test with pins 0 and 1 tied on my Pico passes.

If I hook uart.irq, like so I can see it firing:

def poll(u):
    if u.irq().flags() & u.IRQ_RXIDLE:
        print("poll!")
        ppp.poll()

uart.irq(poll, uart.IRQ_RXIDLE)

But this does not get me working network requests. Eventually it stalls and... nada.

If I use the above code to "manually" poll every 20ms, then I get working network responses instantly.

(Edit: Snipped off my nonsense confusing freq with period in the Timer class)

@dpgeorge
Copy link
Member Author

But this does not get me working network requests. Eventually it stalls and... nada.

If I use the above code to "manually" poll every 20ms, then I get working network responses instantly.

I think I may have found the problem: upon UART IRQ, network_ppp_poll was only reading up to 256 bytes and then returning. So if more bytes were available in the UART then they would not be processed until the next IRQ, which may never occur. Adding a manual poll would make it work.

I've now fixed this by making sure network_ppp_poll drains the UART.

I also added PPP debug printing as a temporary measure. That will be disabled once things work.

@Gadgetoid
Copy link
Contributor

Fantastic! I’ll do my merge dance and give it a try this morning!

@Gadgetoid
Copy link
Contributor

Gadgetoid commented Aug 20, 2024

Somehow the latest code is running into a hardfault. There doesn't seem to be any pattern as to where.

Here are some runs of requests.get("https://shop.pimoroni.com/robots.txt"), captured from the last IRQ firing.

03: UART IRQ!
ppp_out(n=44,data=21:45:00:00:28:00:08:00:00:ff:06:c4:f0:0a:e3:ad:c7:17:e3:26:4a:d8:06:01:bb:00:00:1a:04:9d:26:4e:1b:50:10:12:c0:c7:35:00:00:34:7c:7e:)
ppp_out(n=44,data=21:45:00:00:28:00:09:00:00:ff:06:c4:ef:0a:e3:ad:c7:17:e3:26:4a:d8:06:01:bb:00:00:1a:04:9d:26:4e:1b:50:10:19:00:c0:f5:00:00:41:af:7e:)
ppp_in(n=256,data=7e:21:45:28:03:48:00:0b:00:00:7c:06:44:a6:17:e3:26:4a:0a:e3:ad:c7:01:bb:d8:06:9d:26:4e:1b:00:00:1a:04:50:10:ff:ff:2c:aa:00:00:9e:fb:0e:72:b1:1d:9b:bc:03:f9:49:05:d8:81:dd:05:b4:2a:d6:41:e9:ac:01:76:95:0a:0f:d8:df:d5:bd:12:1f:35:2f:28:17:6c:d2:98:c1:a8:09:64:77:6e:47:37:ba:ce:ac:59:5e:68:9d:7f:72:d6:89:c5:06:41:29:3e:59:3e:dd:26:f5:24:c9:11:a7:5a:a3:4c:40:1f:46:a1:99:b5:a7:3a:51:6e:86:3b:9e:7d:5d:72:a7:12:05:78:59:ed:3e:51:78:15:0b:03:8f:8d:d0:2f:05:b2:3e:7b:4a:1c:4b:73:05:12:fc:c6:ea:e0:50:13:7c:43:93:74:b3:ca:74:e7:8e:1f:01:08:d0:30:d4:5b:71:36:b4:07:ba:c1:30:30:5c:48:b7:82:3b:98:a6:7d:5d:60:8a:a2:a3:29:82:cc:ba:bd:83:04:1b:a2:83:03:41:a1:d6:05:f1:1b:c2:b6:f0:a8:7c:86:3b:46:a8:48:2a:88:dc:76:9a:76:bf:1f:6a:a5:3d:19:8f:eb:38:f3:64:de:c8:2b:0d:0a:28:ff:f7:db:)
ppp_in(n=256,data=e2:15:42:d4:22:d0:27:5d:e1:79:fe:18:e7:70:88:ad:4e:e6:d9:8b:3a:c6:dd:27:51:6e:ff:bc:64:f5:33:43:4f:02:03:01:00:01:a3:82:01:46:30:82:01:42:30:0f:06:03:55:1d:13:01:01:ff:04:05:30:03:01:01:ff:30:0e:06:03:55:1d:0f:01:01:ff:04:04:03:02:01:06:30:4b:06:08:2b:06:01:05:05:07:01:01:04:3f:30:3d:30:3b:06:08:2b:06:01:05:05:07:30:02:86:2f:68:74:74:70:3a:2f:2f:61:70:70:73:2e:69:64:65:6e:74:72:75:73:74:2e:63:6f:6d:2f:72:6f:6f:74:73:2f:64:73:74:72:6f:6f:74:63:61:78:33:2e:70:37:63:30:1f:06:03:55:1d:23:04:18:30:16:80:14:c4:a7:b1:a4:7b:2c:71:fa:db:e1:4b:90:75:ff:c4:15:60:85:89:10:30:54:06:03:55:1d:20:04:4d:30:4b:30:08:06:06:67:81:0c:01:02:01:30:3f:06:0b:2b:06:01:04:01:82:df:13:01:01:01:30:30:30:2e:06:08:2b:06:01:05:05:07:02:01:16:22:68:74:74:70:3a:2f:2f:63:70:73:2e:72:6f:6f:74:)
ppp_in(n=256,data=2d:78:31:2e:6c:65:74:73:65:6e:63:72:79:70:74:2e:6f:72:67:30:3c:06:03:55:1d:1f:04:35:30:33:30:31:a0:2f:a0:2d:86:2b:68:74:74:70:3a:2f:2f:63:72:6c:2e:69:64:65:6e:74:72:75:73:74:2e:63:6f:6d:2f:44:53:54:52:4f:4
02: UART IRQ!
ppp_out(n=194,data=21:45:00:00:be:00:04:00:00:ff:06:ec:f9:0a:a5:85:6a:17:e3:26:4a:dc:52:01:bb:00:00:19:6e:98:f9:e7:04:50:18:19:00:ce:e5:00:00:16:03:03:00:91:01:00:00:8d:03:03:66:c4:7f:0f:b7:53:8a:36:ff:b4:37:aa:cb:22:52:9b:94:1a:16:51:e6:5a:7a:18:dc:d2:07:f1:1e:56:a2:66:00:00:26:c0:2c:c0:30:c0:24:c0:28:c0:0a:c0:14:c0:2b:c0:2f:c0:23:c0:27:c0:09:c0:13:00:9d:00:3d:00:35:00:9c:00:3c:00:2f:00:ff:01:00:00:3e:00:00:00:16:00:14:00:00:11:73:68:6f:70:2e:70:69:6d:6f:72:6f:6e:69:2e:63:6f:6d:00:0a:00:08:00:06:00:17:00:18:00:19:00:0d:00:0e:00:0c:06:03:06:01:05:03:05:01:04:03:04:01:00:0b:00:02:01:00:c0:f8:7e:)
ppp_in(n=45,data=7e:21:45:28:00:28:9d:bd:40:00:37:06:d7:ae:17:e3:26:4a:0a:a5:85:6a:01:bb:dc:52:98:f9:e7:04:00:00:1a:04:50:10:ff:ff:69:88:00:00:5b:9c:7e:)
ppp_in(n=256,data=7e:21:45:28:03:48:9d:be:40:00:37:06:d4:8d:17:e3:26:4a:0a:a5:85:6a:01:bb:dc:52:98:f9:e7:04:00:00:1a:04:50:10:ff:ff:f7:97:00:00:16:03:03:00:5b:02:00:00:57:03:03:66:c4:70:fe:97:82:c2:b3:b0:73:97:fa:db:2c:f2:c3:30:63:e6:bc:35:f7:3c:ea:44:4f:57:4e:47:52:44:01:20:3a:b9:7c:e6:d4:b6:3c:b5:74:98:a6:bc:88:c1:e3:8a:19:45:b7:0c:1e:d6:f6:0d:99:0d:aa:fd:70:c3:59:d8:c0:2f:00:00:0f:00:00:00:00:ff:01:00:01:00:00:0b:00:02:01:00:16:03:03:0f:73:0b:00:0f:6f:00:0f:6c:00:04:f5:30:82:04:f1:30:82:03:d9:a0:03:02:01:02:02:12:04:49:bb:13:09:e9:db:1e:33:a1:15:65:0c:4f:82:ad:73:b9:30:0d:06:09:2a:86:48:86:f7:0d:01:01:0b:05:00:30:33:31:0b:30:09:06:03:55:04:06:13:02:55:53:31:16:30:14:06:03:55:04:0a:13:0d:4c:65:74:27:73:20:45:6e:63:72:79:70:74:31:0c:30:0a:06:03:55:04:03:13:03:52:31:31:30:1e:)
ppp_in(n=256,data=17:0d:32:34:30:37:30:31:31:37:33:34:33:37:5a:17:0d:32:34:30:39:32:39:31:37:33:34:33:36:5a:30:1c:31:1a:30:18:06:03:55:04:03:13:11:73:68:6f:70:2e:70:69:6d:6f:72:6f:6e:69:2e:63:6f:6d:30:82:01:22:30:0d:06:09:2a:86:48:86:f7:0d:01:01:01:05:00:03:82:01:0f:00:30:82:01:0a:02:82:01:01:00:b2:fc:23:c9:2d:89:19:69:f0:2d:54:73:d2:9d:ba:74:de:a9:7d:5e:55:e4:d8:b8:9e:82:2f:64:59:82:5e:4d:93:98:3e:ce:9b:39:d4:21:1d:09:44:13:9f:4d:b8:e1:e6:0c:4e:10:1c:33:22:df:ef:ea:77:ed:a6:aa:c0:9d:8e:71:b8:6b:64:2b:f5:ca:08:3c:38:54:3b:7b:18:e7:42:0b:ab:f1:c3:b0:33:eb:09:8b:89:64:26:75:fe:0e:b6:14:3c:0f:79:48:33:6c:d1:55:3f:35:1d:20:63:4e:3a:35:92:c1:6b:78:96:e7:3c:43:26:4c:95:9f:d9:fd:7d:5e:00:4f:fe:c3:dd:9b:38:40:3f:13:93:23:31:7a:19:c6:b6:92:c6:7f:68:f0:77:c1:b5:85:a6:a6:6b:51:d1:e6:7b:)
ppp_in(n=256,data=b7:54:72:19:7d:5d:82:9a:bf:02:2d:ba:86:b4:2a:43:9d:17:5d:2e:e4:bc:83:38:c2:7d:5e:5b:55:3c:0e:6d:3d:58:97:dc:7a:21:f6:5e:fd:d0:e4:bd:39:8d:a3:ff:71:0f:d3:36:6e:ec:74:3d:76:59:af:ef:2d:b7:9c:f2:2d:7d:5e:17:54:a9:a6:75:07:89:e7:a8:81:15:89:37:7f:e2:50:53:a2:82:b9:2f:e7:c2:b3:cb:fc:84:38:e4:5b:9f:02:03:01:00:01:a3:82:02:14:30:82:02:10:30:0e:06:03:55:1d:0f:01:01:ff:04:04:03:02:05:a0:30:1d:06:03:55:1d:25:04:16:30:14:06:08:2b:06:01:05:05:07:03:01:06:08:2b:06:01:05:05:07:03:02:30:0c:06:03:55:1d:13:01:01:ff:04:02:30:00:30:1d:06:03:55:1d:0e:04:16:04:14:e4:4b:a6:ba:6d:5b:52:ce:4d:b5:f1:58:d7:4d:99:52:b8:b9:f2:e7:30:1f:06:03:55:1d:23:04:18:30:16:80:14:c5:cf:46:a4:ea:f4:c3:c0:7a:6c:95:c4:2d:b0:5e:92:2f:26:e3:b9:30:57:06:08:2b:06:01:05:05:07:01:01:04:4b:30:49:30:22:06:08:)
ppp_in(n=256,data=2b:06:01:05:05:07:30:01:86:16:68:74:74:70:3a:2f:2f:72:31:31:2e:6f:2e:6c:65:6e:63:72:2e:6f:72:67:30:23:06:08:2b:06:01:05:05:07:30:02:86:17:68:74:74:70:3a:2f:2f:72:31:31:2e:69:2e:6c:65:6e:63:72:2e:6f:72:67:2f:30:1c:06:03:55:1d:11:04:15:30:99:02:7e:7e:21:45:28:03:48:9d:bf:40:00:37:06:d4:8c:17:e3:26:4a:0a:a5:85:6a:01:bb:dc:52:98:f9:ea:24:00:00:1a:04:50:10:ff:ff:11:82:00:00:13:82:11:73:68:6f:70:2e:70:69:6d:6f:72:6f:6e:69:2e:63:6f:6d:30:13:06:03:55:1d:20:04:0c:30:0a:30:08:06:06:67:81:0c:01:02:01:30:82:01:03:06:0a:2b:06:01:04:01:d6:79:02:04:02:04:81:f4:04:81:f1:00:ef:00:75:00:3f:17:4b:4f:d7:22:47:58:94:1d:65:1c:84:be:0d:12:ed:90:37:7f:1f:85:6a:eb:c1:bf:28:85:ec:f8:64:6e:00:00:01:90:6f:93:d6:51:00:00:04:03:00:46:30:44:02:20:7c:63:6b:c5:c8:99:65:a7:77:70:80:9f:8c:b8:)
ppp_in(n=256,data=24:f9:26:db:bf:aa:c2:5e:3e:d7:fb:ee:52:f9:5f:4e:15:be:02:20:16:41:17:0e:37:1d:52:11:e2:91:b0:2d:c0:2c:98:5d:6f:ba:b8:f9:c5:82:c5:c4:19:d9:2f:2c:0f:bf:eb:13:00:76:00:48:b0:e3:6b:da:a6:47:34:0f:e5:6a:02:fa:9d:30:eb:1c:52:01:cb:56:dd:2c:81:d9:bb:bf:ab:39:d8:84:73:00:00:01:90:6f:93:de:25:00:00:04:03:00:47:30:45:02:20:5f:de:7f:58:d3:98:99:87:e6:53:0a:5d:a1:88:3c:ed:84:e4:5b:21:a0:c8:a3:c5:1b:44:98:9d:95:5d:91:4e:02:21:00:da:d6:fa:bb:8c:95:38:92:8b:72:65:93:80:42:fe:f9:ee:c3:d0:3e:ff:4a:01:5f:e6:0e:4b:86:83:4f:2a:bc:30:0d:06:09:2a:86:48:86:f7:0d:01:01:0b:05:00:03:82:01:01:00:5e:49:94:76:e5:6b:dc:8a:80:a3:88:92:9e:e8:02:63:f5:19:e9:90:b0:33:fa:47:07:2e:94:ad:6c:e0:23:75:6e:10:68:7d:5e:8f:6a:4c:32:c7:8d:b2:88:f3:7a:83:b7:d0:37:5d:ee:96:c3:41:9c:16:a1:67:07:ba:80:b8:)
ppp_in(n=256,data=c5:4e:d7:a4:41:57:df:0a:62:f9:bc:7d:5d:3d:ac:74:d5:6c:20:cb:65:f5:62:12:85:85:c2:de:d4:7d:5e:6e:fe:0c:1a:d9:9c:8a:77:5f:c1:c9:0a:01:a3:f5:d9:43:79:7b:57:12:67:a2:9e:3c:24:78:33:35:7d:5e:40:a1:45:de:f2:b9:cf:4e:f7:21:da:1f:72:23:39:aa:69:42:ed:ab:9d:74:01:da:4e:8a:10:06:66:79:e9:ca:c5:5c:d0:f6:be:fc:ce:7d:5e:01:cd:2b:b8:ed:4a:1f:ba:c6:82:57:3b:f2:89:c9:9a:4d:55:14:5d:9b:39:35:6e:04:fa:45:08:ed:aa:65:39:bf:45:35:6f:57:89:82:3a:e2:c7:8f:92:a1:ae:e5:c7:40:e4:9e:17:ff:a9:58:ad:45:2e:b3:af:59:80:ce:b7:c2:43:bb:cc:34:6b:17:cf:b1:21:c7:3f:ce:28:12:14:84:dc:7f:bc:f8:c8:b8:57:91:cd:bd:bd:8e:9b:00:05:0a:30:82:05:06:30:82:02:ee:a0:03:02:01:02:02:11:00:8a:7d:5d:3e:13:d6:2f:30:ef:23:86:bd:29:07:6b:34:f8:30:0d:06:09:2a:86:48:86:f7:0d:01:01:0b:05:00:30:4f:31:0b:30:09:06:03:)
ppp_in(n=256,data=55:04:06:13:02:55:53:31:29:30:27:06:03:55:04:0a:13:20:49:6e:74:65:72:6e:65:74:20:53:65:63:75:72:69:74:79:20:52:65:73:65:61:72:63:68:20:47:72:6f:75:70:31:15:30:13:06:03:55:04:03:13:0c:49:53:52:47:20:52:6f:6f:74:20:58:31:30:1e:17:0d:32:34:30:33:31:33:30:30:30:30:30:30:5a:17:0d:32:37:30:33:31:32:32:33:35:39:35:39:5a:30:33:31:0b:30:09:06:03:55:04:06:13:02:55:53:31:16:30:14:06:03:55:04:0a:13:0d:4c:65:74:27:73:20:45:6e:63:72:79:70:74:31:0c:30:0a:06:03:55:04:03:13:03:52:31:31:30:82:01:22:bf:e1:7e:7e:21:45:28:03:48:9d:c0:40:00:37:06:d4:8b:17:e3:26:4a:0a:a5:85:6a:01:bb:dc:52:98:f9:ed:44:00:00:1a:04:50:10:ff:ff:ba:8f:00:00:30:0d:06:09:2a:86:48:86:f7:0d:01:01:01:05:00:03:82:01:0f:00:30:82:01:0a:02:82:01:01:00:ba:87:bc:5c:1b:00:39:cb:ca:0a:cd:d4:67:10:f9:01:3c:a5:4e:a5:)
ppp_out(n=45,data=7e:21:45:00:00:28:00:05:00:00:ff:06:ed:8e:0a:a5:85:6a:17:e3:26:4a:dc:52:01:bb:00:00:1a:04:98:f9:ed:44:50:10:12:c0:50:88:00:00:ff:05:7e:)
ppp_in(n=256,data=61:cb:26:ca:52:fb:15:01:b7:b9:28:f5:28:1e:ed:27:b3:24:18:39:67:09:0c:08:ec:e0:3a:b0:3b:77:0e:bd:f3:e5:39:54:41:0c:4e:ae:41:d6:99:74:de:51:db:ef:7b:ff:58:bd:a8:b7:13:f6:de:31:d5:f2:72:c9:72:6a:0b:83:74:95:9c:46:00:64:14:99:f3:b1:d9:22:d9:cd:a8:92:aa:1c:26:7a:3f:fe:ef:58:05:7b:08:95:81:db:71:0f:8e:fb:e3:31:09:bb:09:be:50:4d:5f:8f:91:76:3d:5a:9d:9e:83:f2:e9:c4:66:b3:e1:06:66:43:48:18:80:65:a0:37:18:9a:9b:84:32:97:b1:b2:bd:c4:f8:15:00:9d:27:88:fb:e2:63:17:96:6c:9b:27:67:4b:c4:db:28:5e:69:c2:79:f0:49:5c:e0:24:50:e1:c4:bc:a1:05:ac:7b:40:6d:00:b4:c2:41:3f:a7:58:b8:2f:c5:5c:9b:a5:bb:09:9e:f1:fe:eb:b0:85:39:fd:a8:0a:ef:45:c4:78:eb:65:2a:c2:cf:5f:3c:de:e3:5c:4d:1b:f7:0b:27:2b:aa:0b:42:77:53:4f:79:6a:1d:87:d9:02:03:01:00:01:a3:81:f8:30:81:f5:30:0e:06:03:55:1d:0f:01:01:)
ppp_in(n=256,data=ff:04:04:03:02:01:86:30:1d:06:03:55:1d:25:04:16:30:14:06:08:2b:06:01:05:05:07:03:02:06:08:2b:06:01:05:05:07:03:01:30:12:06:03:55:1d:13:01:01:ff:04:08:30:06:01:01:ff:02:01:00:30:1d:06:03:55:1d:0e:04:16:04:14:c5:cf:46:a4:ea:f4:c3:c0:7a:6c:95:c4:2d:b0:5e:92:2f:26:e3:b9:30:1f:06:03:55:1d:23:04:18:30:16:80:14:79:b4:59:e6:7b:b6:e5:e4:01:73:80:08:88:c8:1a:58:f6:e9:9b:6e:30:32:06:08:2b:06:01:05:05:07:01:01:04:26:30:24:30:22:06:08:2b:06:01:05:05:07:30:02:86:16:68:74:74:70:3a:2f:2f:78:31:2e:69:2e:6c:65:6e:63:72:2e:6f:72:67:2f:30:13:06:03:55:1d:20:04:0c:30:0a:30:08:06:06:67:81:0c:01:02:01:30:27:06:03:55:1d:1f:04:20:30:1e:30:1c:a0:1a:a0:18:86:16:68:74:74:70:3a:2f:2f:78:31:2e:63:2e:6c:65:6e:63:72:2e:6f:72:67:2f:30:0d:06:09:2a:86:48:86:f7:0d:01:01:0b:05:00:03:82:02:01:00:)
ppp_in(n=256,data=4e:e2:89:5d:0a:03:1c:90:38:d0:f5:1f:f9:71:5c:f8:c3:8f:b2:37:88:7a:6f:b0:25:1f:ed:be:b7:d8:86:06:8e:e9:09:84:cd:72:bf:81:f3:fc:ca:cf:53:48:ed:bd:f6:69:42:d4:a5:11:3e:35:c8:13:b2:92:1d:05:5f:ea:2e:d4:d8:f8:49:c3:ad:f5:99:96:9c:ef:26:d8:e1:b4:24:0b:48:20:4d:fc:d3:54:b4:a9:c6:21:c8:e1:36:1b:ff:77:64:29:17:b9:f0:4b:ef:5d:ea:cd:79:d0:bf:90:bf:be:23:b2:90:da:4a:a9:48:31:74:a9:44:0b:e1:e2:f6:2d:83:71:a4:75:7b:d2:94:c1:05:19:46:1c:b9:8f:f3:c4:74:48:25:2a:0d:e5:f5:db:43:e2:db:93:9b:b9:19:b4:1f:2f:df:6a:0e:8f:31:d3:63:0f
03: UART IRQ!
ppp_out(n=44,data=21:45:00:00:28:00:0a:00:00:ff:06:bb:46:0a:35:b8:1d:17:e3:26:4a:e0:53:01:bb:00:00:1a:04:17:b2:05:12:50:10:0e:0d:88:71:00:00:b4:f3:7e:)
ppp_out(n=44,data=21:45:00:00:28:00:0b:00:00:ff:06:bb:45:0a:35:b8:1d:17:e3:26:4a:e0:53:01:bb:00:00:1a:04:17:b2:05:12:50:10:14:4d:82:31:00:00:8b:8d:7e:)
ppp_out(n=120,data=7e:21:45:00:00:73:00:0c:00:00:ff:06:ba:f9:0a:35:b8:1d:17:e3:26:4a:e0:53:01:bb:00:00:1a:04:17:b2:05:12:50:18:19:00:5b:5c:00:00:16:03:03:00:46:10:00:00:42:41:04:df:14:75:e6:46:35:a6:e6:93:64:fd:af:8c:98:06:53:3b:98:a8:15:16:49:da:cd:d6:19:bc:b3:63:6a:be:55:a6:dc:20:e9:61:c6:a9:e1:74:b2:18:74:d1:94:96:07:d9:86:e7:96:26:30:77:12:22:a1:8b:07:f2:95:c4:42:42:bb:7e:)
06: UART IRQ!
ppp_out(n=44,data=21:45:00:00:28:00:0a:00:00:ff:06:fd:8a:0a:59:75:b5:17:e3:26:4a:ec:61:01:bb:00:00:1a:04:83:75:a6:37:50:10:15:e0:a9:eb:00:00:5f:e9:7e:)
ppp_in(n=256,data=7e:21:45:28:01:bb:00:0b:00:00:7c:06:7d:5e:cf:17:e3:26:4a:0a:59:75:b5:01:bb:ec:61:83:75:a6:37:00:00:1a:04:50:18:ff:ff:ea:6c:00:00:58:98:ae:ea:bd:45:45:a1:88:5d:66:ca:fe:10:e9:6f:82:c8:11:42:0d:fb:e9:ec:e3:86:00:de:9d:10:e3:38:fa:a4:7d:5d:b1:d8:e8:49:82:84:06:9b:2b:e8:6b:4f:01:0c:38:77:2e:f9:dd:e7:39:16:03:03:01:4d:0c:00:01:49:03:00:17:41:04:f8:4c:e7:87:67:a2:38:bc:b6:f7:17:00:6e:7c:55:bd:1a:5c:b5:45:04:51:0f:93:cb:27:f8:02:59:d8:14:63:c1:76:50:68:9a:ba:2f:1a:d3:37:f2:b1:d7:ee:9b:91:4e:33:d3:98:aa:b4:b5:4b:59:ac:eb:c9:3e:23:7a:3b:04:01:01:00:09:78:cf:a2:59:b1:4c:57:43:fa:b0:97:1c:03:c3:a2:ee:5e:e7:bb:fc:75:19:05:51:16:61:86:5c:07:de:1d:33:fb:21:89:a0:8f:6a:fe:ef:aa:6b:45:b0:6a:a4:df:76:2d:de:6d:83:29:2d:37:25:29:c5:64:f2:0c:a9:7f:57:d7:98:71:69:89:b9:f2:1e:ef:)
ppp_in(n=195,data=df:c5:b8:5b:cc:d4:66:8a:24:d5:ca:61:53:ac:0d:ab:ab:d5:c1:ca:90:85:f4:f9:36:3d:90:2b:9d:9c:c0:17:1a:44:26:f5:94:ec:0e:03:92:a5:a5:1a:ac:d2:b6:96:19:18:24:44:40:cf:bd:5a:1b:eb:65:6e:d9:0e:22:13:16:ab:31:90:db:3c:cf:9d:38:70:2b:cc:7b:10:6d:2d:92:d3:9e:16:9d:1c:ed:e0:c2:75:b3:d4:61:59:b3:36:a3:4a:58:04:f7:7d:5d:80:b8:b9:7c:4e:4f:4d:8d:0e:d8:24:3b:df:e9:a8:

Once instance even failed before getting any input....

ppp_out(n=67,data=21:45:00:00:3f:00:01:00:00:ff:11:4f:05:0a:c0:17:1a:0a:cd:40:01:22:34:00:35:00:2b:f5:9f:69:79:01:00:00:01:00:00:00:00:00:00:04:73:68:6f:70:08:70:69:6d:6f:72:6f:6e:69:03:63:6f:6d:00:00:01:00:01:dc:98:7e:)
ppp_out(n=

This is a pretty glued together MicroPython including RP2350 fixes (though these tests are running on RP2040), the UART IRQ stuff and this PR so it's possible any number of things have gone awry. Though... this is new!

Edit:

  • Merged this commit and the IRQ into master to produce a build without the RP2350 complications. Same deal- locks up and hangs indefinitely, except now it doesn't matter if I try to manually poll or not 😬
  • Feels like the UART isn't getting torn down nicely on soft reset, too, since I will reset and my code will stall while creating the UART() instance.

@dpgeorge dpgeorge force-pushed the extmod-network-ppp-lwip branch from 18ca76a to 654711c Compare August 20, 2024 12:06
@dpgeorge
Copy link
Member Author

Somehow the latest code is running into a hardfault. There doesn't seem to be any pattern as to where

This could simply be due to the debug output, which will attempt to write to the USB CDC within an lwIP callback, which is probably not safe (it's safe enough for debug purposes but not in general, probably).

I've updated this PR to disable the debug printing. Please try it again!

@Gadgetoid
Copy link
Contributor

Tried again and was hitting the same stalling issue (with and without polling), so I bumped both timeout and timeout_char to 10ms- it worked once, and now it's stubbornly refusing to work again.

Continuing to poke some other settings to see if it'll make any difference, but it's not looking promising and the failure is repeatable. With polling I can see the IRQ fire a couple of times after making a request, and then nothing. Without polling i fires ~12 times and also hangs. Same class of problem, I guess, but it can't be papered over with polling anymore.

(Ha, if I do the maths (256 bytes * 8 bits / 115200 bps) and plug in a 10ms poll interval it works again.)

I am still having trouble constructing a UART instance after a soft reset, perhaps related to the IRQ stuff.

@robert-hh
Copy link
Contributor

I am still having trouble constructing a UART instance after a soft reset, perhaps related to the IRQ stuff.

I made a small change in the RP2 software that might fix this problem. Not sure since I do not know the state of your code whwn it happens.

@Gadgetoid
Copy link
Contributor

Gadgetoid commented Aug 20, 2024

Not sure since I do not know the state of your code whwn it happens.

That makes two of us! But thanks for trying- I'll test ASAP.

Edit: I think it's made an improvement. No stalls on creating the UART instance, though I have to power cycle anyway since the LTE module really likes to get into a bad state.

No further luck getting the cursed thing to work without polling! I'm now doing:

POLL_TIME = int(256 * 8 / UART_BAUD * 1000)

uart.irq(lambda x: None, uart.IRQ_RXIDLE)

tmr = Timer()
tmr.init(mode=Timer.PERIODIC, period=POLL_TIME, callback=ppp.poll)

Which works great 😆

I've also noticed that if I set rxbuf to 512 I start getting weird memory corruption errors, suggesting the UART is writing to, but not actually allocating, a larger receive buffer...

@Gadgetoid
Copy link
Contributor

I've also noticed that if I set rxbuf to 512 I start getting weird memory corruption errors, suggesting the UART is writing to, but not actually allocating, a larger receive buffer...

Okay this was a bug in #14041 and it has now been fixed.

Plot twist, now if I set my rxbuf to 1k+ PPP seems to be working 🤔 Maybe the IRQ being garbage collected was my problem all along. 512 bytes does not seem to work, only a couple of requests will be successful (eventual buffer overrun?). I've tested a 1k bytes rxbuf up to 100 successive requests, albeit the payload is quite small. This is all at 115200 baud and agonisingly slow so I'll do some poking at faster speeds to see how those fare too.

With the UART fixes if my code doesn't crash and I ppp.disconnect() then everything works fine on soft reset too 🥳 (I need to figure out what ppp.disconnect() is doing because sending +++ got me nowhere fast).

I think I also tested with a hardware IRQ, replacing the default one by using: uart.irq(ppp.poll, uart.IRQ_RXIDLE, hard=True). This accomplished roughly nothing.

Anyway, TLDR: with an rxbuf of 1024 and both timeout and timeout_char set to 0, I can get PPP working to my LTE module reliably at 115200 baud. Preliminary tests suggest it also works at 230400 and 460800. 🎉

:shipit:

@robert-hh
Copy link
Contributor

Anyway, TLDR: with an rxbuf of 1024 and both timeout and timeout_char set to 0, I can get PPP working to my LTE module reliably at 115200 baud. Preliminary tests suggest it also works at 230400 and 460800. 🎉

That sounds good. Thank you for testing and confirmation, and for revealing the bugs.

@nestorld
Copy link

Hello guys, I apologize for insisting, but maybe you can help on something that would be very useful for PPP connections with modems. I have a custom library in MicroPython to implement cmux between an ESP32 and a SIMCom modem. It would allow to use 4 virtual UARTs over a physical UART to send AT commands and to have a PPP connection on the same physical UART. It is working well but only failing at the very last step when I pass a virtual UART to network.ppp. For some reason the ppp service is not able to handle the virtual UART even when I’m adding to it all the methods that it should have to handle read and write. It is just crashing the Thonny console when executing ppp.connect(). The same data flow is correctly setting the ppp connection when I pass it to a physical UART of a second microcontroller, which means the cmux handshaking is doing well. Here is my library (https://github.com/MicropythonShare/cmux). Please take a look, I have not been able to find what is missing or what the ppp module is expecting from the virtual UART. This would be useful not only for ESP32 but for any other microcontroller running MicroPython. I’d really appreciate any help on this 🙂

@andrewleech
Copy link
Contributor

There's more detail / context on the efforts by @nestorld here: https://github.com/orgs/micropython/discussions/9263

@Gadgetoid
Copy link
Contributor

@nestorld AIUI and at a bleary glance through misty eyes this morning, you’re missing the “irq” method. Called here:

mp_load_method(self->stream, MP_QSTR_irq, dest);

Your virtual UART could presumably just create a timer and call the “poll” method it’s handed using my timings above. (basically a function of buffer size and baud rate)

@nestorld
Copy link

nestorld commented Aug 22, 2024

@nestorld AIUI and at a bleary glance through misty eyes this morning, you’re missing the “irq” method. Called here:

mp_load_method(self->stream, MP_QSTR_irq, dest);

Your virtual UART could presumably just create a timer and call the “poll” method it’s handed using my timings above. (basically a function of buffer size and baud rate)

Thanks for helping @Gadgetoid. That irq method seems not to be used in ESP32's UARTs. I have tried creating a fake method like this (like the one shown in the UART documentation), just to confirm if it is invoked at any moment:

def irq(self, trigger, priority=1, handler=None, wake=0):
    print("Using irq")

...and I never see that print in the console. I have done the same for all the methods in my virtual UART and none of them are invoked between ppp.connect() and the crash. Micropython UART documentation says that the irq method is only available for WiPy, which is not my case. In fact, if I see all the properties and methods for a physical UART in Thonny, this is what I get (no irq method):
Screenshot 2024-08-22 at 1 21 33 PM

I don't have big skills with the C code, but here is the last point where I was able to get some printf in the micropython/ports/esp32/network_ppp.c file before the crash (inserting a printf before the return line):

static u32_t ppp_output_callback(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx) {
    ppp_if_obj_t *self = ctx; int err;
    return mp_stream_rw(self->stream, data, len, &err, MP_STREAM_RW_WRITE);
}

mp_stream_rw function is in micropython/py/streams.c file. I suspect about line 50 there:

const mp_stream_p_t *stream_p = mp_get_stream(stream);

Where "stream" is the UART, or the virtual UART in this case.

@robert-hh
Copy link
Contributor

That irq method seems not to be used in ESP32's UARTs.

It will not be available until PR #14041 is merged.

@nestorld
Copy link

That irq method seems not to be used in ESP32's UARTs.

It will not be available until PR #14041 is merged.

But is it needed for a virtual UART to emulate what a physical UART does? I would guess no

@vshymanskyy
Copy link
Contributor

Based on my (mostly positive) experience working with PPP on ESP32, I'd like to raise a concern regarding DNS in multi-interface configurations.

ESP32 docs say:

DNS server configuration in lwIP is global, not interface-specific. If you are using multiple network interfaces with distinct DNS servers, exercise caution to prevent inadvertent overwrites of one interface's DNS settings when acquiring a DHCP lease from another interface.

For example, if you have Ethernet, WiFi, and PPP interfaces, the peer DNS of PPP will typically override the system DNS server settings (because PPP often takes the longest time to initialize). This will almost certainly render WiFi and Ethernet interfaces unusable for DNS.

I understand this may be beyond the scope of this PR, but I wanted to highlight it so that appropriate action can be taken.

@dpgeorge dpgeorge force-pushed the extmod-network-ppp-lwip branch from 654711c to 9defa9c Compare August 28, 2024 07:36
@dpgeorge
Copy link
Member Author

Documentation for network.PPP has now been added, and the commits cleaned up. I also made it so PPP can be enabled on the rp2 port with a simple #define MICROPY_PY_NETWORK_PPP_LWIP (1) in the board's mpconfigboard.h file; @Gadgetoid FYI

This is now ready to merged.

This updates lwIP from STABLE-2_1_3_RELEASE, which was released in November
2021.  The latest STABLE-2_2_0_RELEASE was released in September 2023.

Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
This commit adds a new `network.PPP` interface which works on any port that
has bare-metal lwIP, eg rp2, stm32, mimxrt.

It has been tested on stm32.  A board needs to enable
`MICROPY_PY_NETWORK_PPP_LWIP` and then it can use it as follows:

    import network

    ppp = network.PPP(uart)
    ppp.connect()

    while not ppp.isconnected():
        pass

    # use `socket` module as usual, etc

    ppp.disconnect()

Usually the application must first configure the cellular/etc UART link to
get it connected and in to PPP mode first (eg ATD*99#), before handing over
control to `network.PPP`.

The PPP interface automatically configures the UART IRQ callback to call
PPP.poll() on incoming data.

Signed-off-by: Damien George <damien@micropython.org>
Can be enabled by a board by enabling `MICROPY_PY_NETWORK_PPP_LWIP`.

Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
The errcode should be cleared so the caller sees a successful write, even
if it's a short write.

Signed-off-by: Damien George <damien@micropython.org>
When timeout=0 (non-blocking mode) the UART should still wait for each
character to go out.  Otherwise non-blocking mode with CTS enabled is
useless because it can only write one character at a time.

Signed-off-by: Damien George <damien@micropython.org>
This allows enabling lwIP debugging output.  For example, to enable PPP
debugging add the following to `mpconfigboard.h`:

    #define LWIP_DEBUG 1
    #define PPP_DEBUG LWIP_DBG_ON

Signed-off-by: Damien George <damien@micropython.org>
Can be enabled by a board by enabling `MICROPY_PY_NETWORK_PPP_LWIP`.

Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
@dpgeorge dpgeorge force-pushed the extmod-network-ppp-lwip branch from 9defa9c to 35b6a66 Compare August 29, 2024 13:48
@dpgeorge dpgeorge merged commit 35b6a66 into micropython:master Aug 29, 2024
64 checks passed
@dpgeorge dpgeorge deleted the extmod-network-ppp-lwip branch August 29, 2024 14:13
@vshymanskyy
Copy link
Contributor

Please check this issue: #15900
The code looks OK according to the documentation but it doesn't work.
Is something obvious missing?

@eskereli
Copy link

eskereli commented Oct 4, 2024

Hello friends, in our project that we developed with MP v1.24.0-preview on Mimixrt1020, we access the internet with PPP via GSM module.

While there is no problem when sending 300-500 bytes of data with socket, the application freezes when data is larger (for example: 1KB, 2KB), sometimes it acts as if the data is gone before it is completely gone.

We tried the following tests that we saw in the comments on Discord and GitHub, but we still could not get any results:
1- #14461 (comment)
2- We increased the LWIP buffer value as stated in the comments,
3- Our UART RX and TX buffer values ​​were 256B, we made them 30000B,
4- We put a 50ms wait in each cycle by chunking the data.

We have tried each of the above separately, and also all combinations, but still no results.

A problem that has been blocking our way for about two months, we are open to any suggestions. I am waiting for your ideas that may help.

@DeadCat93
Copy link

Hello.
Please tell me how to build micropython firmware with this feature for Pico W.
Thanks for your help!

@robert-hh
Copy link
Contributor

While there is no problem when sending 300-500 bytes of data with socket, the application freezes when data is larger (for example: 1KB, 2KB), sometimes it acts as if the data is gone before it is completely gone.

@eskereli @dpgeorge I found a bug in MIMXRT UART, causing the UART buffer size to be reset to 256B on every call to uart.init() unless the size is deliberately set in this call. Maybe that is you issue as well in your attempts. The same applies to RP2 and SAMD. Will send fixes.

@Gadgetoid
Copy link
Contributor

The same applies to RP2

Can confirm. Had been working around this without recognising it as a bug 🤦

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
extmod Relates to extmod/ directory in source
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants