Anyone familiar with PICO Pi SDK and networking?

Aug 29, 2023 Last reply: 2 years ago 19 Replies

I decided to have a PICO day today. Well that's 8 hours of my life I wont get back struggling with the appalling lack of documentation for the PICO W and its toolkit, and for a piece of software that Poettering would be proud of in terms of its utterly unnecessary complexity, bugs and lack of documentation.



I refer to *cmake*.


I have got the SDK as far as I can tell up and running with LWIP and the various CY_43_ARCH libraries are concerned, and can compile and install code that runs and access GPIO pins and so on, and prints cheerful messages to teh console, but s far as networking is concerned the moment I try and connect to wifi, I get compile errors deep in the stack.



everything works until I add the last line..



#include "pico/stdlib.h" #include "pico/cyw43_arch.h" #include "hardware/adc.h" #include "lwip/tcp.h" #include "lwip/netif.h" #include "lwip/pbuf.h" ...



int ret; stdio_init_all(); if (cyw43_arch_init_with_country(CYW43_COUNTRY_UK)) { printf("Wi-Fi init failed"); return -1; } cyw43_arch_enable_sta_mode(); // doesn't compile ret = cyw43_arch_wifi_connect_timeout_ms(ssid, password, CYW43_AUTH_WPA2_AES_PSK, 10000); ======================================= When the make process barfs with : /opt/pico-sdk/lib/cyw43-driver/src/cyw43_lwip.c: In function 'cyw43_cb_tcpip_init': /opt/pico-sdk/lib/cyw43-driver/src/cyw43_lwip.c:209:5: warning: implicit declaration of function 'netif_set_hostname'; did you mean 'netif_set_down'? [-Wimplicit-function-declaration] 209 | netif_set_hostname(n, CYW43_HOST_NAME); | ^~~~~~~~~~~~~~~~~~ | netif_set_down /opt/pico-sdk/lib/cyw43-driver/src/cyw43_lwip.c: In function 'cyw43_cb_tcpip_deinit': /opt/pico-sdk/lib/cyw43-driver/src/cyw43_lwip.c:252:32: error: 'netif_list' undeclared (first use in this function); did you mean 'netif_find'? 252 | for (struct netif *netif = netif_list; netif != NULL; netif = netif->next) { | ^~~~~~~~~~ | netif_find /opt/pico-sdk/lib/cyw43-driver/src/cyw43_lwip.c:252:32: note: each undeclared identifier is reported only once for each function it appears in /opt/pico-sdk/lib/cyw43-driver/src/cyw43_lwip.c:252:72: error: 'struct netif' has no member named 'next' 252 | for (struct netif *netif = netif_list; netif != NULL; netif = netif->next)


Blah blah blah.



Clearly its not finding a header file,(netif.h) but it's there and on the path.



Currently the magic spells in the CMakefiles.txt are =================================



cmake_minimum_required(VERSION 3.13)



include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake)



project(thermometer C CXX ASM)



set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 17) set(PICO_BOARD pico_w)



pico_sdk_init()



add_executable(${PROJECT_NAME} main.c)



pico_add_extra_outputs(${PROJECT_NAME})



target_link_libraries(${PROJECT_NAME} pico_stdlib hardware_adc pico_lwip pico_cyw43_arch_lwip_poll )



pico_enable_stdio_usb(${PROJECT_NAME} 1) pico_enable_stdio_uart(${PROJECT_NAME} 0)



Anyone have any clue how to fix this? Answers of the category 'why not use python?' will be treated with the contempt they deserve.



It's failing building the Pico library (specifically LWIP), not your code. So the #include in your code doesn't make any difference.

formatting link
that a later version of the library fixes it.

Not sure where you got the library from, but if you downloaded a packaged version maybe try the most recent git sources?

I haven't used the Pico, but as a general rule I like to use Platformio as a tool to abstract away all the weird device-specific toolchain stuff. They have lots of fancy GUI tools, but PlatformIO Core is a simple(r) command line build environment. Although it does use Python (as the build system, not for the code).

Theo

It's very weird, because Ive got a bit further, but the toolkit is still saying it cant find netif_set_hostname

/opt/pico-sdk/lib/cyw43-driver/src/cyw43_lwip.c:209:5: warning: implicit declaration of function 'netif_set_hostname'

BUT that is a macro that is defined in a file its definitely including cos I hacked that source file

#define CYW43_LWIP 1 #include "cyw43.h"

and in cyw43.h

we see...

#if CYW43_LWIP #include "lwip/netif.h" #include "lwip/dhcp.h" #endif

and that macro is defined in lwip/netif.h

..er. ah. ok I hacked through it. lwipopts.h needs #define LWIP_NETIF_HOSTNAME 1

before netif.h will set that macro.

and then all seems to work. Well it compiles anyway.

What a shoddy load of crud.

You might like to try MicroPython instead.

I don't think you read my original post.

"Anyone who suggests Python will be treated with the contempt that they deserve." :-)

The problem with Python is that by and large it has bugs that no one can fix.

At least now if I have stumbled my way through the LWIP and Cmake morass, I probably have a chance to write code very fast.

It's the old old story, Online are a hundred articles citing the same examples, and a programmers mumblings that contain the truth that is however unfortunately only comprehensible to other people 100% familiar with the code. There is *nothing in between*. Just the odd hint here and there that you have to piece together to reveals the truth.

The key elements to be understood is that Cmake builds a makefile and a compile environment, from CMakefiles.txt and it's buggy. Rule #1 is whenever you invoke it, destroy everything it has built first (essentially the entire contents of the 'build' directory) because you cannot guarantee it wont preserve something you don't want.

The second key piece if information that is not highlighted anywhere, is that when using LWIP library for network, there is a file called lwipopts.h that you have to edit to select what elements you compile in from the source, because the libraries exist as source only. And as I discovered there are hidden dependencies that are not handled well. I am not using hostnames, but somewhere in the code, these are required by the library. You cannot actually compile the TCP without them. And you might also have reasonably thought that if you wanted DHCP the stack would *automatically* include UDP support.

Er, no.

In short TCP/IP on the Pico has been hacked from the LWIP sources till it *mostly* works, on a fine day with a following wind, but it is absolutely unstable, in the Linux sense. Python has presumably used it as a networking layer and hidden the worst of its ugliness, but it is still there.

Ah well. Twas ever thus. 99% of the time fighting poor documentation by clever programmers who didn't get the bugs out because that was too *boring*

Anyone else yearn for the days of a five line C program, followed by CC <source.c> and ./a.out?

Many thanks to the one person who at least understood the question, and pointed me in a slightly more fruitful direction.

Next step is to see if it can establish a WiFi connection...

Ah, no, I missed that. Too near the end of the post?

Ys, there are bugs, but I treat the Pico as a relatively new device with new software, and not as a device I would expect to run 24x7 without error. What I have found is that the Pico is sometimes supplied pre-mounted on some other board, further reducing the reach of the already small Wi-Fi antenna, and I read that 2xAA batteries may not be enough to power the Wi-Fi hardware.

On the other hand, the RPi Zero (2) W is something which will run 24x7 reliably. Perhaps that might suit your project better?

BTW: even though I haven't used MicroPython before, I have found development rapid and easy due to the large number of examples and the easy of using the IDE - no need to make and upload uf2 files after every change.

Yes. There is that.

Note to self. Wifi SSIDs are case sensitive. Finally got a connection...

And glory be to God, there is something calling itself PicoW in the DHCP table on the router.

I wonder how to set the hostname...

I missed it, too!

TNP, have you considered using Python?

Dont push your luck Pancho!

I will say this. In python you cannot set the hostname. In C you can. My DHCP table now says not PicoW, but 'Upstairs'.

Inch by bloody inch this cheap POS is starting to behave itself.

For the record, this is a pretty standard 'embedded' development experience. Every vendor has some degree of proprietary libraries and/or toolchain, and each vendor has a relatively small community of users. Some of whom have a hotline to the vendor's support staff which the rest of us don't.

So the platform is much less well tested than the standard Linux/glibc/gcc flow. Troubles like this aren't unusual in this environment.

Arduino on Atmega is probably the most beaten path in the embedded space - but less popular Arduino platforms suffer from similar creakiness.

Pico seems like it has devs who care about the user experience, rather than the typical vendor throwing things over the wall. But no doubt it will take time to mature (like first few years of the RPi 1), especially if you're using a less popular language.

Theo

I think you are completely right.

Well, for the record I stumbled through and now have at least the networking bit working.

It is extremely sketchy as far as documentation goes if you stray any way from the examples.

But a bit of second guessing now has a PICO W that starts up. connects to wifi, with a unique hostname, reads a thoroughly useless temperature from its chip, and sends its IP address, its hostname and location plus temperature and a voltage to a remote server on the PI Zero W.

I used hints from another piece of code, but in the end I built the thing from the raw LWIP API.

I added an external temperature sensor for that very reason!

For the messaging I used MQTT with a NodeRED server running an a RasPi-3B. I would have preferred to use SNMP but couldn't find a satisfactory implementation for the Pico.

Already on order!

Well LWIP includes an SNMP library but FFS for a custom app a text file is quite adequate....my thermometer assembles 4 lines of text then sends them to a socket. End of story.

..what is MOTT?

I wrote an utterly trivial daemon to run under Xinetd on the PI zero W that listens for the data, and just puts it in a file. Where the web server and the background daemon can read it.

I am strictly old school. As few 3rd party tools as possible, because, as I found with the SDK and cmake, you spend longer learning how to use the darned things than writing a low level piece of code.

I still cannot believe that with the TCP/IP, the code is 650kB+

It's pushing towards the limit of the PICO.

Oh and by the way for other people considering using the pico

- the uf2 file vanishes once its booted,

- placing a uf2 file in the pseudo usb drive causes it to reboot

- but not always as cleanly as one would like. I have found strange things in the serial buffer unless its rebooted cleanly with a subsequent power down.

- the only way to configure the damn thing is to patch the uf2 file, it seems. I haven't tried this yet. I hope they have not checksummed it.

A message queue service, used to be called mosquito. I have one running under docker on a rpi3 for all my home automation devices, smart plugs etc, connected to Domoticz.

formatting link

It runs, I think very little about it. I guess having a buffer service between sensors and the presentation web server is useful, but it's something forced upon me, rather than something I would proactively use.

You can use third party tools to interrogate it, which I guess is a plus.

On Wed, 30 Aug 2023 18:43:58 +0100, The Natural Philosopher wrote: [snip]

Well,

formatting link
says that "MQTT is an OASIS standard messaging protocol for the Internet of Things (IoT). It is designed as an extremely lightweight publish/subscribe messaging transport that is ideal for connecting remote devices with a small code footprint and minimal network bandwidth." and Wikipedia (in
formatting link
has a bit of the history of MQTT.

There are a number of implementations of the the MQTT client libraries and broker daemon. I use Mosquitto

formatting link
between my telephony server and my other systems, but there are other open-source implementations available (see
formatting link
It's reasonably lightweight; there is even an implementation or two (of the client library) for Arduino.

Agreed on third-party tools and needing to learn and find bugs. I've also had to work round the size limits on the Pico, and it would be nice if the 2041 (or whatever) had greater limits.

BTW, I've not seen any issues with uf2 files when using MicroPython and Thonny. Loading the uf2 is typically a one-off operation when you first get the Pico (or the firmware is updated), and any changes are simply editing Python plain text files and copying to/from the Pico to your host. Configuring can be just editing an include file which is read by your program. The simplicity of this over using C/C++ appealed to me.

Mm. Thats ok for a hobbyists. It would be trivial to plug the PICO into a USB port and generate a menu on the serial port. Execept do the changes persist through a reboot?

I am still not clear where the code goes after the boot loader has installed it.

No doubt I will find out, in time.

The changes would persist if your program wrote them back to a configuration file. Thonny displays a structure showing the files on the Pico, so that you can have two windows, one looking at the PC, the other at the Pico.

I've had pretty good luck with VSCodium and PlatformIO. They manage to abstract away most of the unpleasantness involved in dealing with yet another toolchain. With it, I've been able to wrangle different bits of code targeting microcontrollers with AVR, ARM, and RISC-V cores. Some have been a little easier to set up than others (the programmer dongle for some of the RISC-V dev boards I have needed its firmware updated with another tool first), but once it's sorted, writing code for any of them isn't too much different.

As the OP on this thread, I can say that once the documentation has been found, and its ambiguities tested against real life code, the code itself appears to be robust, as does the hardware. Unlike the somewhat flakiness of microPython, documented in other threads.

e.g. timeouts do not work reliably, but watchdog timers seem to, so I implemented a 'i cant connect in 5 seconds, so abort and try again' sequence to at least not brick the code if the server goes off line.

I have yet to test the wifi point going off line. That may requires some further delving.

It's been uphill and a struggle all the way, but I now have some minimal code that runs very well.

I have, in short, solid foundations on which to build any wifi connected gadgets around the place.

I might well have done it with Arduinos etc. but faced with zero knowledge of either platform software wise, I picked the Pi.

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required