I recently had an application for which the ESP8266 wasn't adequate, so I had to look into its new big brother the ESP32. And the NodeMCU Lua firmware I've been using for the 8266 wasn't ready for the 32. (As I write this it's in beta, which for a commercial project is just as bad.) So after reviewing my options I installed the Arduino IDE and the ESP32 plugin. I have little use for Arduino class devices when the Propeller exists, so this was my first rodeo with the whole ecosystem.
And I will say one thing the Arduino environment does well (in fact the only thing it seems to do well) is install itself on a variety of boxes without a lot of drama. The Windows self-installer worked fine, and I needed a video tutorial but it successfully guided me through the install of the ESP32 add-on. Within an hour I was blinken de light on a NodeMCU ESP32s.
Things went rapidly downhill from there.
My first task was a relatively simple relay that needed to accept a HTTP connection, relay the GET request to a serially connected server, and relay the reply to the original socket before closing it. This should have been straightforward and I did in fact get the basic functionality working after about a day of fighting the development system. There wasn't any example code that quite did what I needed, but I've been programming for almost 40 years and I was able to pick out the bits and pieces I needed.
Problem was, it took nearly six seconds to relay a 6 kilobyte webpage. Okay serial is slow but it's not that slow. I was able to prove with serial debug outputs of the ESP cycle count that the delays were in the TCP stack. The example code I'd followed worked one character at a time, calling a send function that accepted a uint-8 character argument. Obviously there was some overhead.
Now C++ has this terrible, horrible stupid feature called "overloading" which allows you to have multiple functions with the same name that are differentiated by the arguments they are declared to receive. The only purpose of this seems to be to maximize the confusion in debugging other peoples' code, which becomes effectively unreadable since it's unclear what any of the nonstandard (or even really standard) functions are doing. Now you'd expect that if there are four versions of a function which take different arguments and handle them differently, that somewhere there would be a list of them explaining their strengths, weaknesses, and limitations. In Arduinoland? Nope. Not for the core functions (which typically only example the simplest form of each function) and not for the extensions (which sometimes don't provide examples at all). Not being a C++ head it took me nearly half a day to figure out just how to use the "IPaddr" data type which actually comes from the ExpressIF ESP32 SDK and convert it to and from strings. There are of course simple functions for that, but there is no documentation of them and rooting in the source code first requires you to FIND the source code, which in my case required using a tool called Agent Ransack to find the ESP32 libs about nine folders deep beneath documents/arduino, and then comparing IPaddr function declares many of which were overloaded same-name functions doing quite different things with similar code from libraries I did have examples for and could understand.
And OK, I realize I'm dipping my toe in a really unfamiliar pool, but what mystifies me is that this is considered an appropriate environment, even what one might call the current default or index environment, for teaching programming to n00bs. If I'm using the PropTool and I want to know how the library works, all the "objects" are in the left hand panel and if I click on one there's the source, usually with a nice comment block at the top describing how to use it. In Arduinoland? Nope. Even if you find the source there are no comments, because why bother? Who would ever find it anyway in C:\Users\MyName\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.4\libraries\WiFi\src ?
So I suspected my problem with the byte-at-a-time driver might be solved if I collected all my data in a buffer (ESP32 has plenty of RAM for what I'm doing) and executed a single call to blow it out to the stack. This required me to get into the weeds of how you pass a pointer to a C byte array slash string to a function, which is another bit of non-obvious arcana. I really don't need the efficiency of pointer manipulation for this but it turns out via the fourth or fifth tutorial I scrounge up via the GOOG that C array names ARE pointers, and you can even set a non permanent pointer equal to one at which point it becomes a manipulable pointer, and walla. And that's basically the core concept in C for how you turn a byte array into what looks like a string for a function call. Stuff like this should be on page 1, fellas.
And yep, collecting my junk into an array and blasting it to the ESP32 TCP stack with one call solved the overhead problem which should have had a 24-point warning attached to it in the nonexistent documentation.
Now I've been programming as I said for nearly 40 years, in far more primitive and far more obtuse languages, and I can adapt. I've adapted before. But that requires me to know what I need to adapt to, and the Arduino environment seems almost defiantly arranged to prevent anyone from learning anything. Yes, you can get it set up and blink an LED and run the demo app you downloaded, but as soon as you want to do something even a little different from what the example shows, you are well and truly screwed.
So having made the serial relay work I was asked to do something else, which required me to run a simple non-relay webserver and a UDP server at the same time. The only UDP examples I could find used something called asyncUDP, obviously a fancy library with extra functions, but when I pasted that code into my app along with the webserver it crashed whenever it received a UDP packet. I got rid of the async web server and manually accepted the TCP connection and replied to it, but UDP still crashed. I knew the basic WiFi object had UDP support but with little experience it was not clear to me just how to convert the C++ object-oriented function definitions in the source to calls that could be made in C-like code. Finally, after hours of searching, I found one example which like about 3/4 of them I had encountered was on a discussion board under the question "Here is my code that doesn't work, what is wrong with it?" Fortunately what was wrong with it wasn't the UDP calls and I was able to get my own stuff to work using those as a template for what I was doing.
So after weeks of fighting with this, I ask again: What sadist thought this was a good way to teach programming? I now know why the coworker who does hobby robotics with Arduino doesn't know how 2's complement math works or how to convert a string into a numeric value to do math on it. He couldn't figure out how to unpack a 2-digit BCD value from a clock chip into binary to do math on it. Because really, he's been using this tool for several years but if you can't just copy boilerplate code and use it as found, it kicks your butt and is completely discouraging even if you know your way around a computer in both directions at high and low speed. It was easier hand compiling 6502 opcodes into hexadecimal and hand keying them into a Prolog ROM programmer than this crap.
And that's not even counting the hilariously bad user interface. (Orange on black status for downloads and errors? Really? and Sending 0%..4%..(long wait)..Done!) And we're supposed to do something more like this than Spin and the PropTool because... ???