Reading from USB COM port in go
If you want an easy copy and paste, no nonsense way to print the output of a COM PORT to the terminal in go, then have a look at the code at the bottom of this post.
Firstly, the go.bug.st/serial/enumerator package provides a very nice interface for getting details of connected devices, and includes more details than the example code in go.bug.st/serial that I found first time around.
Thanks to the toit devs for being responsive and helping me quickly figure out how I could make my ESP spit some USB content out over the COM port.
The code
In a nutshell is this:
- Loops forever
- Targets a specific device ID, such a
1a86:7523
- Waits for it to appear as connected
- Uses baud rate 115200
- Opens the port
- Prints all output received to the console
package main
import (
"fmt"
"time"
"github.com/sirupsen/logrus"
"go.bug.st/serial"
"go.bug.st/serial/enumerator"
)
func main() {
for {
doStuff()
}
}
func doStuff() {
targetID := "1a86:7523" // the esp boards
var found *enumerator.PortDetails
for {
ports, err := enumerator.GetDetailedPortsList()
if err != nil {
logrus.Error(err)
}
if len(ports) == 0 {
fmt.Println("No serial ports found!")
time.Sleep(1 * time.Second)
continue
}
fmt.Printf("Found %d serial ports\n", len(ports))
for _, port := range ports {
fmt.Printf("Found port: %s\n", port.Name)
if port.IsUSB {
fmt.Printf(" USB ID %s:%s\n", port.VID, port.PID)
fmt.Printf(" USB serial %s\n", port.SerialNumber)
if port.VID+":"+port.PID == targetID {
if found != nil {
logrus.Error("Multiple ports found with expected ID", targetID)
time.Sleep(1 * time.Second)
continue
}
found = port
}
}
if port.Product != "" {
fmt.Printf(" Product %s\n", port.Product)
}
}
if found != nil {
break
}
time.Sleep(1 * time.Second)
}
fmt.Println("Found port with expected ID", targetID)
// baud 115200
mode := &serial.Mode{
BaudRate: 115200,
}
fmt.Println("Opening port")
port, err := serial.Open(found.Name, mode)
if err != nil {
logrus.Error(err)
return
}
defer port.Close()
fmt.Println("Reading from port")
buff := make([]byte, 100)
for {
n, err := port.Read(buff)
if err != nil {
logrus.Error(err)
break
}
if n == 0 {
fmt.Println("\nEOF")
break
}
fmt.Printf("%v", string(buff[:n]))
}
}
Code language: JavaScript (javascript)
Testing with toit & an ESP32
I had a small chat with the toit developers in their Discord channel, and they helpfully pointed out that the print
function in toit by default sends over the port via the usb-uart converter.
You can just print in Toit, and it will go through the usb-uart converter.
On the other side you can listen to the uart port and get the data out.
floitsch
So I was able to use a simple hello world type script
main:
print "Hello world"
while true:
print "Time: $Time.now"
sleep --ms=1000
Code language: PHP (php)
Run it on my ESP32 using jaguar.
jag run uart.toit --device 192.168.68.51
Code language: CSS (css)
And see my go code connect to the device and start printing the output that was coming over USB.