I an application, a microcontroller system is controlled through a web interface (connected through WiFi). Communication occurs using a web socket.
This works, but from time to time I receive garbage messages on the microcontroller side. This seems to happen mostly when more data is transferred through the web socket. But data amounts really are not very high.
My question now is whether in the javascript part, when messages are sent from “multiple places”, the messages can be “mixed” up. In other words, is some kind of mutex required to lock access to the websocket?
Here is a sketch of how the code looks like:
ws = new WebSocket('ws://' + location.host + '/xxx');
(...)
function do_send(message) {
try {
ws.send(message);
} catch (err) {
(...)
}
}
var tickn = 1;
function tick() {
try {
do_send('{"tick": ' + tickn.toString()+'}');
tickn++;
}
catch (err) {
console.log("*** !!! ERROR in tick(): " + err);
}
}
(...)
setInterval(tick, 2000);
(...)
function send_params() {
var params = {
xxx: yyy,
};
do_send(JSON.stringify(params));
}
/* send_params is registered as event handler in several GUI elements */
Basically, there is a “tick” function that periodically sends a “ping” message to the controller, just to notify that an interface is connected.
My question now is whether there are concurrency issues on the javascript side. For example, when two GUI elements are modified rapidly after each other, then send_params()
is called multiple times. Could these two calls interfere? Also, could the tick()
heartbeat function be called while a GUI-triggered event leads to the invocation of send_params()
?
I understand that this boils down to whether some sort of concurrency occurs in this JavaScript code. From what I understand about JavaScript, this should not be the case, but I am not totally sure, especially what concerns I/O through the websocket.
UPDATE:
To answer the questions about the reading part:
This is a micropython program, running microdot as web server on an ESP32 microcontroller.
The corresponding route looks like this:
@app.route('/xxx')
@with_subscriber
@with_websocket
async def feed(request, ws, **kwargs):
# ...
try:
data = await uasyncio.wait_for(ws.receive(), 0.2)
print("WS-RCV: {}".format(data))
except uasyncio.TimeoutError:
pass
@with_subscriber
is a decorator that allocates a channel to forward data to subscribers (or receive data from them that are then sent over the web socket). As such, it has nothing to do with the problem that occurs.
def with_subscriber(func):
async def wrapper_func(*args, **kwargs):
sub = channel.subscribe(4)
print("WRAPPER: ^^^^^^^^ -- subscribe")
await func(*args, sub=sub, **kwargs)
print("WRAPPER: vvvvvvvv -- unsubscribe")
channel.unsubscribe(sub)
return wrapper_func
Here is an example of what I received on the micropython side:
WS-RCV: {"tick": 35}
WS-RCV: { "params": 123,"i":25}
WS-RCV: {"tick": 36}
WS-RCV: {"stop": 1}
WS-RCV: {"params": 123,"i":26}
WS-RCV: {"start": 1}
WS-RCV: {"tick": 37}
WS-RCV: b'x18Sxc7x01l:xdfH:ix9cx10 .'
WS-RCV: {"tick": 39}
WS-RCV: {"tick": 40}
WS-RCV: {"tick": 41}
Logging what is sent on the JavaScript side using console.log
, I see that {"tick": 38}
was sent but the garbled binary string is received instead.
8