Coder Social home page Coder Social logo

albenik / go-serial Goto Github PK

View Code? Open in Web Editor NEW
61.0 6.0 23.0 121 KB

A cross-platform serial library for go-lang (custom implementation based on http://go.bug.st/serial.v1)

License: BSD 3-Clause "New" or "Revised" License

Go 100.00%
go serial serial-port library cross-platform golang macos

go-serial's Introduction

github.com/albenik/go-serial/v2

Go

A cross-platform serial library for Go. Forked from github.com/bugst/go-serial and now developing independently.

Many ideas are bein taken from github.com/bugst/go-serial and github.com/pyserial/pyserial.

Any PR-s are welcome.

INSTALL

Not work in GOPATH mode!!!

go get -u github.com/albenik/go-serial/v2

MacOS build note

  • Since version v2.1.0 the macos build requires IOKit as dependency and is only possible on Mac with cgo enabled.
  • Apple M1 (darwin/arm64) is supported. (Thanks to martinhpedersen)

Documentation and examples

See the godoc here: https://pkg.go.dev/github.com/albenik/go-serial/v2

License

The software is release under a BSD 3-clause license

go-serial's People

Contributors

albenik avatar bmuessig avatar danielhongwoo avatar donfede avatar edieruby avatar martinhpedersen avatar milabs avatar rede97 avatar smihica avatar xylo04 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

go-serial's Issues

GetPortsList panic under linux

Trying to use GetPortList and it panic

OS

Distributor ID: Ubuntu
Description: Ubuntu 16.04.4 LTS
Release: 16.04
Codename: xenial

GO

go version go1.11.5 linux/amd64

package main

import (
	"fmt"
	"log"

	"github.com/albenik/go-serial"
)

func main() {

	ports, err := serial.GetPortsList()
	if err != nil {
		log.Fatal(err)
	}
	if len(ports) == 0 {
		log.Fatal("No serial ports found!")
	}
	for _, port := range ports {
		fmt.Printf("Found port: %v\n", port)
	}

}

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0x4c09a2]

goroutine 1 [running]:
github.com/albenik/go-serial/unixutils.(*Pipe).Write(0x0, 0xc0000d1d17, 0x1, 0x1, 0x519000, 0xc000457c68, 0xc0000182d0)
/home/renatho/Documentos/GoWork/src/github.com/albenik/go-serial/unixutils/pipe.go:44 +0x22
github.com/albenik/go-serial.(*unixPort).Close.func1(0xc0003a1e80, 0x519000, 0xc000457c68)
/home/renatho/Documentos/GoWork/src/github.com/albenik/go-serial/serial_unix.go:46 +0x5a
github.com/albenik/go-serial.(*unixPort).Close(0xc0003a1e80, 0xc0000d1e58, 0x519000)
/home/renatho/Documentos/GoWork/src/github.com/albenik/go-serial/serial_unix.go:60 +0x3e
github.com/albenik/go-serial.nativeOpen(0xc000457c70, 0xa, 0xc0000d1e58, 0xc000015601, 0x5, 0xc000457c70)
/home/renatho/Documentos/GoWork/src/github.com/albenik/go-serial/serial_unix.go:338 +0x590

github.com/albenik/go-serial.nativeGetPortsList(0x7f50f2282000, 0x0, 0xc0000386f0, 0x40c138, 0x70)
/home/renatho/Documentos/GoWork/src/github.com/albenik/go-serial/serial_unix.go:404 +0x382
github.com/albenik/go-serial.GetPortsList(0xc000060070, 0xc000038730, 0x40fde2, 0xc000038750, 0x45e7d6a4)
/home/renatho/Documentos/GoWork/src/github.com/albenik/go-serial/serial.go:111 +0x22
main.main()
/home/renatho/Documentos/GoWork/src/test/main.go:17 +0x34
exit status 2

@albenik please help me to solve this, your lib fits perfectly to what I need, because of setReadTimeout but I need the GetPortList working too, in windows and Linux.

Broken on Darwin/macOS

In PR la5nta/pat#222, I noticed this module was recently broken.

According to ory/dockertest#212 (comment), zsyscall_darwin.go should not be using unix.SYS_IOCTL, but instead

unix.IoctlGetTermios and unix.IoctlSetTermios. Direct system calls are considered unsupported by the Darwin maintainers.

Read returns 0 bytes

Not sure what conditions would cause this. Possibly following the expiration of a read timeout?

Nonstandard baud rates

Any ideas on how to support non-standard baud rates? I'm specifically trying to use 1,250,000

Thanks!

Package v2 not found?

After running the install command:

go get -u github.com/albenik/go-serial/v2

I get an error message:

package github.com/albenik/go-serial/v2: cannot find package "github.com/albenik/go-serial/v2" in any of:
c:\go\src\github.com\albenik\go-serial\v2 (from $GOROOT)
C:\Users\user\go\src\github.com\albenik\go-serial\v2 (from $GOPATH)

Not able to connect on WSL

When I try to connect to a serial port from Windows Subsystem for Linux, this is not possible.

The code:

c, err := serial.Open(port, serial.WithBaudrate(9600), serial.WithParity(serial.NoParity),serial.WithDataBits(8),serial.WithStopBits(serial.OneStopBit), serial.WithReadTimeout(1000))
defer c.Close()
if err != nil {
   fmt.Print(port+" ")
   fmt.Println(err)
}

gives the error:

/dev/ttyS3 operating system error: inappropriate ioctl for device

If the code is compiled for Windows the connection is possible. Connecting to the serial console from WSL using screen is also possible. Any ideas?

Unable read from port in Mac M1

Hey there,

go version go1.21.6 darwin/arm64

`
import (
"fmt"
"github.com/albenik/go-serial/v2"
"log"
)

func main() {
ports, err := serial.GetPortsList()
if err != nil {
log.Fatal(err)
}
if len(ports) == 0 {
log.Fatal("No serial ports found!")
}

// Print the list of detected ports
for _, port := range ports {
	fmt.Printf("Found port: %v\n", port)
}

port, err := serial.Open(ports[0],
	serial.WithBaudrate(9600),
	serial.WithDataBits(8),
	serial.WithParity(serial.NoParity),
	serial.WithStopBits(serial.OneStopBit),
	serial.WithReadTimeout(2000),
	serial.WithWriteTimeout(2000),
	serial.WithHUPCL(false),
)
if err != nil {
	log.Fatal(err)
}

n, err := port.Write([]byte("sdadas dasdasd dasdasd dasdasda dasd asdas dasd asd as"))
if err != nil {
	log.Fatal(err)
}
fmt.Printf("Sent %v bytes\n", n)

buff := make([]byte, 1024)
for {
	n, err := port.Read(buff)
	fmt.Printf("Length %v", err)
	fmt.Printf("Length %d", n)
	if n == 0 {
		fmt.Println("\nEOF")
		break
	}
	fmt.Printf("%v", string(buff[:n]))
}

}
`

The output of above code is

Found port: /dev/cu.Bluetooth-Incoming-Port Found port: /dev/cu.wlan-debug Found port: /dev/tty.Bluetooth-Incoming-Port Found port: /dev/tty.wlan-debug Sent 54 bytes Length <nil>Length 0 EOF

No matter what I send it gives length of read bytes as 0.
Can you please suggest what am I missing here.

Detecting Parity errors

Hey, awesome library!

General question: would it be possible to detect Parity errors ? I have been experimenting with Mark and Space Parity and would be interested if there is a way to catch potential errors, from my experiments so far the errors have been ignored and the data was still received correctly.

Is there some indication you could point me to ? I could try coming up with a PR, any tipps are welcome :-)

Darwin: operating system error: bad address with v2.3.0 (v2.2.0 and below work ok)

Hi,

triggered by a bug report, I found a problem opening certain serial devices on Mac OS (11.4 Big Sur).

Took the small test program from the README:

package main

import (
	"fmt"
	"github.com/albenik/go-serial/v2"
	"log"
)

func main() {
	// Retrieve the port list
	ports, err := serial.GetPortsList()
	if err != nil {
		log.Fatal(err)
	}
	if len(ports) == 0 {
		log.Fatal("No serial ports found!")
	}

	// Print the list of detected ports
	for _, port := range ports {
		fmt.Printf("Found port: %v\n", port)
	}

	port, err := serial.Open("/dev/cu.SCSDRAGON7800-SerialPort",
		serial.WithBaudrate(115200),
		serial.WithDataBits(8),
		serial.WithParity(serial.NoParity),
		serial.WithStopBits(serial.OneStopBit),
		serial.WithReadTimeout(1000),
		serial.WithWriteTimeout(1000),
		serial.WithHUPCL(false),
	)
	if err != nil {
		log.Fatal(err)
	}
	log.Println("Serial Port opened!")
	// Send the string "ABCDEF" to the serial port
	n, err := fmt.Fprint(port, "ABCDEF")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Sent %v bytes\n", n)

	// Read and print the response
	buff := make([]byte, 100)
	for {
		// Reads up to 100 bytes
		n, err := port.Read(buff)
		if err != nil {
			log.Fatal(err)
		}
		if n == 0 {
			fmt.Println("\nEOF")
			break
		}
		fmt.Printf("%v", string(buff[:n]))
	}

}

Current v2.3.0 is showing the following error:

X-MacBook-Air-2:ports harenber$ go run .
Found port: /dev/cu.Bluetooth-Incoming-Port
Found port: /dev/cu.BoseSoundSport-SPPDev-2
Found port: /dev/cu.BoseSoundSport-SPPDev-4
Found port: /dev/cu.HC-05-SPPDev
Found port: /dev/cu.SCSDRAGON7800-SerialPort
Found port: /dev/cu.THBoseQuietComfort35-SP
Found port: /dev/cu.THBoseQuietComfort35-SP-2
Found port: /dev/tty.Bluetooth-Incoming-Port
Found port: /dev/tty.BoseSoundSport-SPPDev-2
Found port: /dev/tty.BoseSoundSport-SPPDev-4
Found port: /dev/tty.HC-05-SPPDev
Found port: /dev/tty.SCSDRAGON7800-SerialPort
Found port: /dev/tty.THBoseQuietComfort35-SP
Found port: /dev/tty.THBoseQuietComfort35-SP-2
2021/11/14 18:26:30 invalid serial port: operating system error: bad address
exit status 1

v2.2.0 and below are running fine:

Found port: /dev/cu.Bluetooth-Incoming-Port
Found port: /dev/cu.BoseSoundSport-SPPDev-2
Found port: /dev/cu.BoseSoundSport-SPPDev-4
Found port: /dev/cu.HC-05-SPPDev
Found port: /dev/cu.SCSDRAGON7800-SerialPort
Found port: /dev/cu.THBoseQuietComfort35-SP
Found port: /dev/cu.THBoseQuietComfort35-SP-2
Found port: /dev/tty.Bluetooth-Incoming-Port
Found port: /dev/tty.BoseSoundSport-SPPDev-2
Found port: /dev/tty.BoseSoundSport-SPPDev-4
Found port: /dev/tty.HC-05-SPPDev
Found port: /dev/tty.SCSDRAGON7800-SerialPort
Found port: /dev/tty.THBoseQuietComfort35-SP
Found port: /dev/tty.THBoseQuietComfort35-SP-2
2021/11/14 18:54:36 Serial Port opened!
Sent 6 bytes

EOF

I found no clue in any OS log file about the root cause of the problem.

Kind regards,

Torsten

Build failure on darwin arm64 ("Apple Silicon")

Hello,

This package does not compile on the new darwin+arm64 (aka "Apple Silicon") port of Go (new in 1.16).

$ GOOS=darwin GOARCH=arm64 go build
# github.com/albenik/go-serial/v2
./serial_unix.go:298:13: p.retrieveTermSettings undefined (type *Port has no field or method retrieveTermSettings)
./serial_unix.go:315:12: p.applyTermSettings undefined (type *Port has no field or method applyTermSettings)
./serial_unix.go:401:13: p.retrieveTermSettings undefined (type *Port has no field or method retrieveTermSettings)
./serial_unix.go:422:10: p.applyTermSettings undefined (type *Port has no field or method applyTermSettings)
./termios_unix.go:20:23: undefined: tcCMSPAR
./termios_unix.go:25:23: undefined: tcCMSPAR
./termios_unix.go:30:23: undefined: tcCMSPAR
./termios_unix.go:33:6: undefined: tcCMSPAR
./termios_unix.go:38:22: undefined: tcCMSPAR
./termios_unix.go:41:6: undefined: tcCMSPAR
./termios_unix.go:41:6: too many errors

Reading from the serial port can drop bytes

If there is data available for reading, but not as many bytes as were requested, and on the second pass through the loop there are more bytes available than requested, this library may drop data. The patch below fixes this for unix environments.

diff --git a/serial_unix.go b/serial_unix.go
index cf89f83..d696a3f 100644
--- a/serial_unix.go
+++ b/serial_unix.go
@@ -100,7 +100,7 @@ func (port *unixPort) Read(p []byte) (int, error) {
                if !res.IsReadable(port.handle) {
                        break
                }
-               n, err := unix.Read(port.handle, buf[read:])
+               n, err := unix.Read(port.handle, buf)
                // read should always return some data as select reported it was ready to read when we get to this point.
                if err == nil && n == 0 {
                        err = &PortError{code: ReadFailed}
@@ -108,7 +108,7 @@ func (port *unixPort) Read(p []byte) (int, error) {
                if err != nil {
                        return read, err
                }
-               copy(p[read:], buf[read:read+n])
+               copy(p[read:], buf[:n])
                read += n
 
                now = time.Now()

Linux, "bad address" while setting DTR

Hello,

There is a problem with DTR line setting while running on Linux:

package main

import (
	"log"
	"github.com/albenik/go-serial/v2"
)

func main() {
	port, err := serial.Open("/dev/ttyUSB0",
		serial.WithBaudrate(115200),
		serial.WithDataBits(8),
		serial.WithParity(serial.NoParity),
		serial.WithStopBits(serial.OneStopBit),
	)

	if err != nil {
		log.Fatal(err)
	}

	defer port.Close()

	log.Println("Opened", port)

	if err := port.SetDTR(true); err != nil {
		log.Println(err)
	}
}

Running as:

$ go run test.go
2024/01/24 23:00:11 Opened /dev/ttyUSB0
2024/01/24 23:00:11 operating system error: bad address

Device (converter) information from dmesg:

[1113444.099145] usb 1-1: new full-speed USB device number 5 using xhci_hcd
[1113444.226199] usb 1-1: New USB device found, idVendor=1a86, idProduct=7523, bcdDevice= 2.64
[1113444.226213] usb 1-1: New USB device strings: Mfr=0, Product=2, SerialNumber=0
[1113444.226220] usb 1-1: Product: USB Serial
[1113444.228034] ch341 1-1:1.0: ch341-uart converter detected
[1113444.228747] usb 1-1: ch341-uart converter now attached to ttyUSB0

Calling SetDTR() or SetRTS() before opening crashes in an unexpected fashion

If the SetDTR() or SetRTS() functions are called before the connection is opened, the program crashes through means of a segmentation fault, due to nullpointers. This should really be mitigated by checking for nullpointer dereference ahead of time to prevent this unclean segmentation fault. A proper Go panic is prefered here.

Output:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x48 pc=0x4d1b85]

cannot get PortDetails.Product

Hi, I found a problem when i want to get PortDetails.Product (friendlyName).

setupDiGetDeviceRegistryProperty
setupDiGetDeviceRegistryProperty(device.set, &device.data, spdrpDeviceDesc /* spdrpFriendlyName */, nil, friendlyNameP, &friendlyNameSize, nil)

accroding to SetupDiGetDeviceRegistryPropertyW
WINSETUPAPI BOOL SetupDiGetDeviceRegistryPropertyA( HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD Property, PDWORD PropertyRegDataType, PBYTE PropertyBuffer, DWORD PropertyBufferSize, PDWORD RequiredSize );
PropertyBufferSize is DWORD not PDOWRD, "&friendlyNameSize" should be “friendlyNameSize", it works.

Why change Port from interface to struct in v2?

I probably have missed something here but why change the Port type from interface to struct when changing to v2?
My guess is that there were some really big benefits.
With the bugst version I was able to create a mock port for testing stuff but that would require Port to be a interface I could implement. Mocking without interfaces i much harder.

Support for Android?

Dear @albenik ,

a question (sorry for using the "Issue" feature here): I used your fine library on my Android tablet (inside of Termux) to get a connection between this device and a Bluetooth "modem".

I had to hack the Linux code a bit and remove several calls to (on Android) unsupported features.

My question would be: would you be interested in these changes so that your library could "officially" support Android?

Thanks and kind regards,

Torsten

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.