Skip to content

Commit e7ea376

Browse files
authored
fix: Serial Monitor corrupted output in some rare cases (#1032)
* Synchronize multiple open commands coming together. * Allow re-opening of already opened ports * Renamed mutex var and added comment * Error out if baudrate and buftype of already opened port do not match
1 parent b717430 commit e7ea376

File tree

2 files changed

+27
-23
lines changed

2 files changed

+27
-23
lines changed

serial.go

+6-13
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import (
3131

3232
type serialhub struct {
3333
// Opened serial ports.
34-
ports map[*serport]bool
34+
ports map[string]*serport
3535

3636
mu sync.Mutex
3737
}
@@ -60,15 +60,15 @@ type SpPortItem struct {
6060
var serialPorts SerialPortList
6161

6262
var sh = serialhub{
63-
ports: make(map[*serport]bool),
63+
ports: make(map[string]*serport),
6464
}
6565

6666
// Register serial ports from the connections.
6767
func (sh *serialhub) Register(port *serport) {
6868
sh.mu.Lock()
6969
//log.Print("Registering a port: ", p.portConf.Name)
7070
h.broadcastSys <- []byte("{\"Cmd\":\"Open\",\"Desc\":\"Got register/open on port.\",\"Port\":\"" + port.portConf.Name + "\",\"Baud\":" + strconv.Itoa(port.portConf.Baud) + ",\"BufferType\":\"" + port.BufferType + "\"}")
71-
sh.ports[port] = true
71+
sh.ports[port.portName] = port
7272
sh.mu.Unlock()
7373
}
7474

@@ -77,7 +77,7 @@ func (sh *serialhub) Unregister(port *serport) {
7777
sh.mu.Lock()
7878
//log.Print("Unregistering a port: ", p.portConf.Name)
7979
h.broadcastSys <- []byte("{\"Cmd\":\"Close\",\"Desc\":\"Got unregister/close on port.\",\"Port\":\"" + port.portConf.Name + "\",\"Baud\":" + strconv.Itoa(port.portConf.Baud) + "}")
80-
delete(sh.ports, port)
80+
delete(sh.ports, port.portName)
8181
close(port.sendBuffered)
8282
close(port.sendNoBuf)
8383
sh.mu.Unlock()
@@ -86,15 +86,8 @@ func (sh *serialhub) Unregister(port *serport) {
8686
func (sh *serialhub) FindPortByName(portname string) (*serport, bool) {
8787
sh.mu.Lock()
8888
defer sh.mu.Unlock()
89-
90-
for port := range sh.ports {
91-
if strings.EqualFold(port.portConf.Name, portname) {
92-
// we found our port
93-
//spHandlerClose(port)
94-
return port, true
95-
}
96-
}
97-
return nil, false
89+
port, ok := sh.ports[portname]
90+
return port, ok
9891
}
9992

10093
// List broadcasts a Json representation of the ports found

serialport.go

+21-10
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"encoding/base64"
2121
"io"
2222
"strconv"
23+
"sync"
2324
"sync/atomic"
2425
"time"
2526
"unicode/utf8"
@@ -273,7 +274,13 @@ func (p *serport) writerRaw() {
273274
h.broadcastSys <- []byte(msgstr)
274275
}
275276

277+
// This lock is used to prevent multiple threads from trying to open the same port at the same time.
278+
// It presents issues with the serial port driver on some OS's: https://github.com/arduino/arduino-create-agent/issues/1031
279+
var spHandlerOpenLock sync.Mutex
280+
276281
func spHandlerOpen(portname string, baud int, buftype string) {
282+
spHandlerOpenLock.Lock()
283+
defer spHandlerOpenLock.Unlock()
277284

278285
log.Print("Inside spHandler")
279286

@@ -295,11 +302,14 @@ func spHandlerOpen(portname string, baud int, buftype string) {
295302
sp, err := serial.Open(portname, mode)
296303
log.Print("Just tried to open port")
297304
if err != nil {
298-
//log.Fatal(err)
299-
log.Print("Error opening port " + err.Error())
300-
//h.broadcastSys <- []byte("Error opening port. " + err.Error())
301-
h.broadcastSys <- []byte("{\"Cmd\":\"OpenFail\",\"Desc\":\"Error opening port. " + err.Error() + "\",\"Port\":\"" + conf.Name + "\",\"Baud\":" + strconv.Itoa(conf.Baud) + "}")
302-
305+
existingPort, ok := sh.FindPortByName(portname)
306+
if ok && existingPort.portConf.Baud == baud && existingPort.BufferType == buftype {
307+
log.Print("Port already opened")
308+
h.broadcastSys <- []byte("{\"Cmd\":\"Open\",\"Desc\":\"Port already opened.\",\"Port\":\"" + existingPort.portConf.Name + "\",\"Baud\":" + strconv.Itoa(existingPort.portConf.Baud) + ",\"BufferType\":\"" + existingPort.BufferType + "\"}")
309+
} else {
310+
log.Print("Error opening port " + err.Error())
311+
h.broadcastSys <- []byte("{\"Cmd\":\"OpenFail\",\"Desc\":\"Error opening port. " + err.Error() + "\",\"Port\":\"" + conf.Name + "\",\"Baud\":" + strconv.Itoa(conf.Baud) + "}")
312+
}
303313
return
304314
}
305315
log.Print("Opened port successfully")
@@ -331,7 +341,6 @@ func spHandlerOpen(portname string, baud int, buftype string) {
331341
p.bufferwatcher = bw
332342

333343
sh.Register(p)
334-
defer sh.Unregister(p)
335344

336345
serialPorts.MarkPortAsOpened(portname)
337346
serialPorts.List()
@@ -342,10 +351,12 @@ func spHandlerOpen(portname string, baud int, buftype string) {
342351
go p.writerNoBuf()
343352
// this is thread to send to serial port but with base64 decoding
344353
go p.writerRaw()
345-
346-
p.reader(buftype)
347-
348-
serialPorts.List()
354+
// this is the thread that reads from the serial port
355+
go func() {
356+
p.reader(buftype)
357+
serialPorts.List()
358+
sh.Unregister(p)
359+
}()
349360
}
350361

351362
func (p *serport) Close() {

0 commit comments

Comments
 (0)