-
Notifications
You must be signed in to change notification settings - Fork 220
Description
Describe the problem
Opening a serial port with non-standard baud rate 25000 fails occasionally. The failure occurs in nativeOpen()
Lines 232 to 247 in f12391c
settings, err := port.getTermSettings() | |
if err != nil { | |
port.Close() | |
return nil, &PortError{code: InvalidSerialPort, causedBy: fmt.Errorf("error getting term settings: %w", err)} | |
} | |
// Set raw mode | |
setRawMode(settings) | |
// Explicitly disable RTS/CTS flow control | |
setTermSettingsCtsRts(false, settings) | |
if err = port.setTermSettings(settings); err != nil { | |
port.Close() | |
return nil, &PortError{code: InvalidSerialPort, causedBy: fmt.Errorf("error setting term settings: %w", err)} | |
} |
due to tcsetattr() rejecting non-standard baudrates.
Scenario:
Sometimes, getTermSettings() populates with a non-standard baud rate. Once the settings struct is populated with a non-standard baud rate, setTermSettings() and thus nativeOpen() will fail with EINVAL. This appears to be a MacOS specific behavior for tcsetattr rejecting non-standard baud rates (see related tcsetattr() issue in avrdude)
Note that a workaround for non-standard baud rate, setSpecialBaudRate(), is already called out in SetMode(), but it does not apply properly when getTermSettings (tcgetattr()) populates with a non-standard baud rate:
Lines 271 to 276 in f12391c
// MacOSX require that this operation is the last one otherwise an | |
// 'Invalid serial port' error is returned... don't know why... | |
if err := port.SetMode(mode); err != nil { | |
port.Close() | |
return nil, &PortError{code: InvalidSerialPort, causedBy: fmt.Errorf("error configuring port: %w", err)} | |
} |
This problem also applies to subsequent calls to SetMode w/ non-standard baud rate on a port that was Open()'d successfully. Please see the example code that I attached to reproduce this issue.
Possible Solution: We could replace the Ispeed and Ospeed fields with a standard baud rate before calling setTermSettings() if they are non-standard, then allow the setSpecialBaudRate() to set the non-standard baud rates.
To reproduce
package main
import (
"fmt"
"go.bug.st/serial"
)
func t1() error {
// setting non-standard baud-rate a second time fails on MacOS
// baud rate was set first in serial.Open()
// baud rate attempted to set again in SetMode()
Port := "/dev/tty.usbserial-DK0FPOX4"
port, err := serial.Open(Port, &serial.Mode{BaudRate: 250000})
if err != nil {
fmt.Println("Open() failed", err.Error())
return err
}
defer port.Close()
err = port.SetMode(&serial.Mode{BaudRate: 250000})
if err != nil {
fmt.Println("SetMode() failed", err.Error())
return err
}
fmt.Println("no error")
return nil
}
func t2() error {
// setting non-standard baud-rate works once on MacOS
// baud rate was set first in serial.Open()
// baud rate attempted to set again in SetMode()
Port := "/dev/tty.usbserial-DK0FPOX4"
port, err := serial.Open(Port, &serial.Mode{BaudRate: 9600})
if err != nil {
fmt.Println("Open() failed", err.Error())
return err
}
defer port.Close()
err = port.SetMode(&serial.Mode{BaudRate: 250000})
if err != nil {
fmt.Println("SetMode() failed", err.Error())
return err
}
fmt.Println("no error")
return nil
}
func main() {
fmt.Println("t1():")
t1()
fmt.Println("t2():")
t2()
}
t1():
SetMode() failed invalid argument
t2():
no error
Please double-check that you have reported each of the following
before submitting the issue.
- I've provided the FULL source code that causes the problem
- I've provided all the actions required to reproduce the problem
Expected behavior
Serial port should Open, and the workaround for MacOS non-standard baud rates should apply even when the port already has a non-standard baudrate.
Operating system and version
MacOS: Sequoia 15.5
Please describe your hardware setup
No response
Additional context
No response
Issue checklist
- I searched for previous requests in the issue tracker
- My request contains all necessary details