Interface and Application Programming
Hero shot
Group assignment
ThrustMeter user interface
As a personal assignment, I decided to develop a new user interface for my ThrustMeter.
My first ThrustMeter has a Python interface.
I decided to write the same interface, using WebSerial.
WebSerial test
Warning
WebSerial is not supported by Firefox. Use Chrome or Edge instead.
I followed the Chrome tutorial about WebSerial.
I started by writing a minimalist interface that can:
- connect to an ESP32 with WebSerial
- close the connection properly
- send and receive data.
I ended with this HTML interface:
It has
- a "Connect" button to open the connection
- a "Disconnect" button to close the connection
- a "Start" button to send a control character ('A') to the ESP32.
ESP32 will react by streaming data. The text area will display the number of received data.
Here is a video showing it in action:
ESP32 code
I wrote a test code for the ESP32. It reacts at the same control characters as the Thrustmeter.
It sends fake data by enumerating the range of ADC values.
It'll allow me to check if data transmission works well.
#define SAMP_PER_US 1000
#define UNCONNECTED 0
#define IDLE 1
#define ACQUIRING 2
int8_t state;
uint16_t data;
void setup(void) {
Serial.begin(115200);
state = IDLE;
data = 0;
Serial.write('O');
}
void loop(void) {
char c = 0;
if (Serial.available() > 0) {
c = Serial.read();
}
switch (state) {
case IDLE:
if (c == 'A') { // host wants to connect
state = ACQUIRING;
data = 0;
}
break;
case ACQUIRING:
delayMicroseconds(SAMP_PER_US);
data = (data + 1) % 4096;
Serial.write(data & 0x00FF);
Serial.write(data >> 8);
if (c == 'S') { // host wants to connect
state = IDLE;
}
break;
default:
state = IDLE;
}
}
HTML code explanation
The HTML and javascript code is shown in the following tabs.
You can click on the ⊕ symbols to have more informations on the corresponding line.
The // ... lines indicates that some lines where omitted to ease the comprehension.
A link to the complete code is available ine the Useful files
<div style="margin:0 auto; width:250px; height:100px; border:1px solid black; padding:20px;"> <!-- Interface container (1) -->
<button id="connectBtn" style="background-color: #C0C0C0">Connect</button> <!-- "Connect" button (2) -->
<button id="disconnectBtn" style="background-color: #C0C0C0" disabled>Disconnect</button> <!-- "Disconnect" button (3) -->
<button id="startBtn" style="background-color: #C0C0C0" disabled>Start</button> <!-- "Start" button (4) -->
<div> <!-- Sub-container to display the number of received bytes (5) -->
<label for="byteNb">Byte received:</label>
<textarea id="byteNb" name="byteNb" rows="1" cols="4"> 0 </textarea>
</div>
</div>
- The HTML code creates a container for the WebSerial interface.
- The Connect button triggers the WebSerial connection.
- The Disconnect button triggers the WebSerial disconnection. it's disabled by default.
- The Start button triggers the data acquisition.
- This labeled text area will be used to show that data are received from the serial port.
- This function is triggered by a click on the Connect button.
- Tells the web browser to list the serial port and asks the user to select the right one. This can be seen in the video above.
- Opens the serial port, with the desired baud rate.
- If
serial.requestPort()orport.open()failed, thetryblock execution is interrupted and thecatchblock is executed. toggleButton()toggles the booleandisabledproperty of the given button.
The serial port's writable property returns a WritableStream that can be used to send data.
- This function is triggered by a click on the Connect button.
- These lines create a text output stream and connect it to the serial port output. It'll be used in the Start button handler.
- If running these lines raises an exception, the
tryblock execution is interrupted and thecatchblock is executed.
- This function is triggered by a click on the Start/Stop button.
- Creates a writer for
outputStream. Needed to send data. It also lock the serial port, to prevent other threads to access it. - Send a character to the Thrustmeter (and wait until it's sent)
- Serial port MUST be released to allow the other function to use it.
The serial port's readable property returns a ReadableStream that can be used to receive data.
- This function is triggered by a click on the Connect button.
- Lines 15-17 create a text input stream and connect it to the serial port input.
- Creates a reader for
inputStream. Needed to access its data. - Blocking read of the input stream. Wait for the Thrustmeter to send a byte, when it's ready.
- If running these lines raises an exception, the
tryblock execution is interrupted and thecatchblock is executed.
- This function contains the endless loop that reads data from the serial port.
- This "endless" loop listen the serial port input stream and count the received data. It ends when the disconnect button is clicked.
- Blocking read of the input stream. Wait for the Thrustmeter to send a new data.
- If
reader.cancel()is called (see "disconnection" tab),reader.read()returnsdoneastrue. It's time to end the read loop. - The reader lock on the serial port MUST be released to allow the serial port closing.
- This function is triggered by a click on the Disconnect button.
- This block ends the reader. That'll trigger the end of the read loop in the Connect button handler (see Input stream handling tab).
- This block ends the output stream
- Both reader and writer MUST be ended before closing the serial port.
- If running the
tryblock raises an exception, it's execution is interrupted and thecatchblock is executed.
HTML graphic interface
I never tried using HTML and Javascript to draw on a web page.
I read the canvasline.html given by Neil and modify it to obtain an animated sine wave.
The main difference is that I added a circular buffer to store the Y-axis data.
The idea is to copy the structure of my Python interface.