Week 15
Please refer to the group page to read about the group assignment.
Group Assignment:
- [] Compare as many tool options as possible.
- [] Document your work on the group work page and reflect on your individual page what you learned.
Individual Assignment:
- [] Write an application for the embedded board that you made, that interfaces a user with an input and/or output device(s)
Learnings from the group assignment
Node-RED
I decided to start with low-level programming using Node-RED. There seems to be quite some good documentation and tutorials.
The first step was to set up the program on my (Windows) PC. Here are the instructions on the installation process.
When I completed the first step, I check in Powershell according to the instructions.
PS C:\Users\johannes> node --version; npm --version
v22.15.0
npm : File C:\Program Files\nodejs\npm.ps1 cannot be loaded because running scripts is disabled on this system. For mor
e information, see about_Execution_Policies at https:/go.microsoft.com/fwlink/?LinkID=135170.
At line:1 char:17
+ node --version; npm --version
+ ~~~
+ CategoryInfo : SecurityError: (:) [], PSSecurityException
+ FullyQualifiedErrorId : UnauthorizedAccess
Now that is a disappointment - my workplace regulations don't allow running scripts for security reasons and I think it doesn't make sense to continue here.
Rust
Next I started looking a Rust.
I opened the online playground and ran some examples there. It looked okay to me, but to me it was still absolutely unclear how I could approach the communication with an embedded device.
I searched for examples or tutorials for USB Serial but found that I would need a library, but there were so many different available and I couldn't quite find a page explaining it straight forward, giving me the confidence to give it a try.
I therefor decided to go to Processing first.
===================
After having succesfully got a program running in Processing, I decided to come back to Rust and give it a try. I was shocked, that the installation requires around 6 GB, so installation took quite a while.
While waiting for the installation to finish, I found out, that it would have possibly been easier to set up Rust for VS Code. I tried that, but got redirected to the same installation page as before, which requires Visual Studio to be installed... It seems to be a requirement anyway.
After some time the installation eventually finished. First I tried using Rust from the Windows Command Prompt, but I found it a bit complicated (many steps) to get the Hello World program running, so I looked at this tutorial to open the rust project in VS Code and run it there.
That worked fine, so I continued and tried to listen to the serial port.
I found a library that I was able to add to the compiler using cargo add serialport
.
First I ran a simple code to get a list of active COM ports available.
fn main() {
let ports = serialport::available_ports().expect("No ports found!");
for p in ports {
println!("{}", p.port_name);
}
}
Then I struggled reading from the port and got all kinds of different error messages. I looked for another tutorial and found this.
However, it still didn't get me to the point being able to read the Serial port. I searched and tried for some more hours and eventually got this code running:
use serialport;
use std::time::Duration;
use std::io::{BufRead, BufReader};
fn main() {
let mut serial_port = serialport::new("COM33", 9600)
.timeout(Duration::from_millis(1000))
.open()
.unwrap();
serial_port.set_flow_control(serialport::FlowControl::Hardware)
.unwrap();
let mut reader = BufReader::new(serial_port);
let mut my_str = String::new();
loop {
let read_line = reader.read_line(&mut my_str);
match read_line {
Ok(_n) => {
dbg!(&my_str);
my_str.clear();
},
Err(_e) => {}
}
}
}
This looks much more complicated then in C++ and I don't quite understand what is going on in each line.
Nevertheless, I decided to spend a bt more time on it and see if I could rig up a simple GUI.
There seem to be dozen of options for GUI and I ended up picking Iced.
I looked for some tutorials and documentation and ended up trying to follow this tutorial, after having unsuccesfully tried to get some examples working.
However, even the most simple example produces some kind of error message, relate to conflicts in crates, that I wasn't able to solve.
I therfore decided to give up on Iced and Rust.
Processing
Processing is a free software developing environment with a huge community sharing libraries and code.
After installing and opening the software, I felt immediatly at home. It looks almost the same as the Arduino IDE and was therefore quite intuitive to navigate.
Serial Read
I quickly found an example Libraries->Serial->SimpleRead that looked like it could be a good base to start. It also provided the corresponding code for the microcontroller! It will listen to the serial port from the microcontroller which sends a 1
when the button is pushed and a 0
if not. Depending on that it will change colors on the interface.
Because I had my SAMD11C board from week 8 on the desk, I decided to use it for this assignment. I had to adpot the program to the pinout of my board.
Here is the code:
int switchPin = 2; // Button connected to pin 2
void setup() {
pinMode(switchPin, INPUT); // Set switchPin as an input
Serial.begin(9600); // Start serial communication at 9600 bps
}
void loop() {
if (digitalRead(switchPin) == HIGH) { // If switch is ON,
Serial.write(1); // send 1 to Processing
} else { // If the switch is not ON,
Serial.write((byte) 0x00); // send 0 (as hex code) to Processing
}
delay(100); // Wait 100 milliseconds
}
Next was to set up the code in Processing. Here I had to figure out where on the COM-port list the SAMD11 is. (It is number three in my list).
import processing.serial.*;
Serial myPort; // Create object from Serial class
int val; // Data received from the serial port
void setup()
{
size(200, 200);
String portName = Serial.list()[2]; // Define which COM port is used
myPort = new Serial(this, portName, 9600);
}
void draw()
{
if ( myPort.available() > 0) { // If data is available,
val = myPort.read(); // read it and store it in val
}
background(255);
if (val == 0){ // Button not pushed
background(204); // set background to light gray
fill(0); // set text to black
textSize(64);
text("OFF",50,120);
}else { // Button pushed
background(204,102,0); // set background to orange
textSize(64);
text("ON",50,120);
}
}
Works well.
JavaScript
Another programming language that I decided to test is JavaScript. For that I made shure that node.js was already set up and the I got the Code Runner extension for VS Code.
I found this tutorial on how to communicate via serial port. It looked easier then in Rust, so I gave it a try. However, after compiling the code I got a lot of errors. After searching on the internet, it turned out that due to changes in the libraries, some commands had changed and needed to be adapted. I worked through it for every error that I encountered and eventually got it working to read the serial port with this code:
const http = require('http');
const {SerialPort} = require("serialport");
const {ReadlineParser} = require("@serialport/parser-readline");
const path = require('path');
// Defining the serial port
const port = new SerialPort({path:'COM33',baudRate: 9600});
// The Serial port parser
const parser = new ReadlineParser();
port.pipe(parser);
const hostname = '127.0.0.1';
const hostport = '3000';
const server = http.createServer((req,res)=>{
res.statusCode=200;
res.setHeader('Content-Type','text/plain');
res.end('Hallo heimur');
});
server.listen(hostport, hostname, () => {
console.log(`Server running at http://${hostname}:${hostport}/`)
})
// Read the data from the serial port
parser.on("data", (line) => console.log(line));
Now I could listen to the serial port and print the input in the console.
The next step was to make an html page with a button and either display the input there or preferably create a button to send a command to the microcontroller.
I create an html file with a reference to the javascript and a button...
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Serial test</title>
<link rel="stylesheet" href="style.css">
<script src="app.js" defer></script>
</head>
<body>
<form>
<h1>Light switch</h1>
<br><br>
Click on the button to turn the LED ON or OFF.
<button type="button" id="lightswitch">Switch the light!</button>
</form>
</body>
</html>
...and used the live server extension to display the page.
Then I had to realize, that even though the serial communication was working earlier, it is not supported by the browser / web javascript.
I searched for a solution and found the webpack, but it looks very complicated implement and as I wasn't sure that this would be the important step to get towards a working html/js to serial GUI I decided to abort here.