I want to connect the code running in the browser, to the ECU. The browser code sends requests that the ECU processes in a synchronous manner and sends back the data.
sequenceDiagram
participant Browser
participant ECU
Browser->>+ECU: Request
ECU->>-Browser: Response
If I use Chrome on a desktop, I can use the WebSerial API and do effectively that. Running at 115200 baud I can get about a 60Hz rate poll rate, which is pretty decent.
However, the final target for this is ideally running on any device using any browser, so I need a layer of indirection.
That takes the form of an ESP32 running a websocket server that any browser can talk to, which bridges the data to the serial port on the ECU; resulting in something like this
sequenceDiagram
participant Browser
participant ESP32
participant ECU
Browser->>ESP32: Request
ESP32->>+ECU: Request
ECU->>-ESP32: Response
ESP32->>Browser: Response
That works, but the poll rate is only 10Hz. Bugger.
The reality is that it’s more complicated than that. There are a lot more moving parts in the chain, any of which could contribute to the latency.
sequenceDiagram
autonumber
participant Browser
participant Browser Network Stack
participant Wifi
participant ESP32 Network Stack
participant ESP32
participant ECU
Browser->>Browser Network Stack: Request
Browser Network Stack->>Wifi: Request
Wifi->>ESP32 Network Stack: Request
ESP32 Network Stack->>ESP32: Request
ESP32->>+ECU: Request
ECU->>-ESP32: Response
ESP32->>ESP32 Network Stack: Response
ESP32 Network Stack->>Wifi: Response
Wifi->>Browser Network Stack: Response
Browser Network Stack->>Browser: Response
One of my coding mantras at work is “You can’t optimise what you can’t measure”. I could guess where the latency is and waste time fixing something that isn’t a problem. And of course that is what I immediately did by rewriting the ESP32 firmware another two times.
However, when I ended up with a sexy and svelte piece of ESP-IDF code (none of that Arduino mollycoddling thank you very much!) I was still only getting about 10Hz. I need to measure stuff.
Clocks
I need to log timestamped events everywhere in the software. I can also do network captures to correlate when the data actually gets transmitted.
For the browser and the network this is easy as the PCs clock is used for both, and that is synchronised to atomic clocks via NTP
The ESP32 has a microsecond precise (not necessarily accurate) timer that counts the time from boot. I need a way to correlate that to the time on the PC.
Fortunately I had a DS3231 lying around that I bought for some reason from Amazon in 2019. I discovered I had it when I went to buy one from Amazon and they said I’d already bought one in 2019.
5 minutes digging through my project drawer turned it up.
Unfortunately these devices only store time precise to the second, I need milliseconds. Handily they output a 1Hz square wave that rises on the half second and falls on the second boundary. I wrote some code that watches this, and notes the internal ESP32 clock when a second starts. I can then use the current millis minus that to know how far I am into a second at any given point. The internal clock seems to drift a bit over time so this has the added benefit of resetting that drift every second.
So that is where I am right now. I need to now use this code and add logging to the ESP32, the browser and capture some network traffic. With that, I should be able to find where in the diagram above I’m wasting time. My money is on powersaving in the ESP32 delaying the traffic, but I want proof first.