Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f0e4a45720 | ||
|
|
bcb0408701 | ||
|
|
5069d66aa2 | ||
|
|
3449d2e7f6 | ||
|
|
1ff9b6fa9a | ||
|
|
7dc6297645 | ||
|
|
fb4b111d50 | ||
|
|
b7483e31a7 | ||
|
|
0996f840dd | ||
|
|
f5a4685ea0 | ||
|
|
56ac2d4e76 | ||
|
|
1c72447e64 | ||
|
|
45e996e1b0 | ||
|
|
0b7848559a | ||
|
|
c18d387887 | ||
|
|
c768d77847 | ||
|
|
1282f62c6e | ||
|
|
4f7d935be3 | ||
|
|
03c961bc8a | ||
|
|
671075c6ac | ||
|
|
bac809c5a1 | ||
|
|
0925f99089 | ||
|
|
42bc112d18 | ||
|
|
259bdeb6c7 | ||
|
|
572f392ca9 | ||
|
|
14e5ea68ce | ||
|
|
bcd8695df4 | ||
|
|
92703ecb02 | ||
|
|
674fbae95a | ||
|
|
2aa105e32e | ||
|
|
7f490f208a |
78
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
78
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
# Source: https://github.com/arduino/tooling-project-assets/blob/main/issue-templates/forms/platform-dependent/bug-report.yml
|
||||
# See: https://docs.github.com/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-issue-forms
|
||||
|
||||
name: Bug report
|
||||
description: Report a problem with the code or documentation in this repository.
|
||||
labels:
|
||||
- bug
|
||||
body:
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Describe the problem
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: reproduce
|
||||
attributes:
|
||||
label: To reproduce
|
||||
description: |
|
||||
Provide the specific set of steps we can follow to reproduce the
|
||||
problem in particular the exact golang source code you used.
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: checklist-reproduce
|
||||
attributes:
|
||||
label: |
|
||||
Please double-check that you have reported each of the following
|
||||
before submitting the issue.
|
||||
options:
|
||||
- label: I've provided the FULL source code that causes the problem
|
||||
required: true
|
||||
- label: I've provided all the actions required to reproduce the problem
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected
|
||||
attributes:
|
||||
label: Expected behavior
|
||||
description: |
|
||||
What would you expect to happen after following those instructions?
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: os
|
||||
attributes:
|
||||
label: Operating system and version
|
||||
description: |
|
||||
Which operating system(s) version are you using on your computer?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: boards
|
||||
attributes:
|
||||
label: Please describe your hardware setup
|
||||
description: |
|
||||
Arduino boards, USB dongles, hubs or embedded devices you are using and how they
|
||||
are connected together.
|
||||
- type: textarea
|
||||
id: additional
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: |
|
||||
Add here any additional information that you think might be relevant to
|
||||
the problem.
|
||||
validations:
|
||||
required: false
|
||||
- type: checkboxes
|
||||
id: checklist
|
||||
attributes:
|
||||
label: Issue checklist
|
||||
description: |
|
||||
Please double-check that you have done each of the following things before
|
||||
submitting the issue.
|
||||
options:
|
||||
- label: I searched for previous requests in [the issue tracker](https://github.com/bugst/go-serial/issues)
|
||||
required: true
|
||||
- label: My request contains all necessary details
|
||||
required: true
|
||||
29
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
Normal file
29
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
# Source: https://github.com/arduino/tooling-project-assets/blob/main/issue-templates/forms/platform-dependent/feature-request.yml
|
||||
# See: https://docs.github.com/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-issue-forms
|
||||
|
||||
name: Feature request
|
||||
description: Suggest an enhancement to this project.
|
||||
labels:
|
||||
- "type: enhancement"
|
||||
body:
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Describe the new feature or change suggestion
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: additional
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Add any additional information about the feature request here.
|
||||
- type: checkboxes
|
||||
id: checklist
|
||||
attributes:
|
||||
label: Issue checklist
|
||||
description: Please double-check that you have done each of the following things before submitting the issue.
|
||||
options:
|
||||
- label: I searched for previous requests in [the issue tracker](https://github.com/bugst/go-serial/issues)
|
||||
required: true
|
||||
- label: My request contains all necessary details
|
||||
required: true
|
||||
23
.github/workflows/test.yaml
vendored
23
.github/workflows/test.yaml
vendored
@@ -15,13 +15,22 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/setup-go@v1
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: "1.17"
|
||||
- name: Build native
|
||||
go-version: "1.22"
|
||||
- name: Setup CGO Environment
|
||||
run: |
|
||||
if [ ${{ matrix.os }} == 'macOS-latest' ] ; then
|
||||
echo "CGO_ENABLED=1" >> "$GITHUB_ENV"
|
||||
fi
|
||||
shell: bash
|
||||
- name: Build AMD64
|
||||
run: GOARCH=amd64 go build -v ./...
|
||||
shell: bash
|
||||
- name: Build ARM64
|
||||
run: GOARCH=arm64 go build -v ./...
|
||||
shell: bash
|
||||
- name: Install socat
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: sudo apt-get install socat
|
||||
@@ -51,10 +60,10 @@ jobs:
|
||||
runs-on: "ubuntu-latest"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/setup-go@v1
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: "1.17"
|
||||
go-version: "1.22"
|
||||
- name: Cross-build
|
||||
run: |
|
||||
set ${{ matrix.go-os-pairs }}
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,5 +1,5 @@
|
||||
|
||||
Copyright (c) 2014-2023, Cristian Maglie.
|
||||
Copyright (c) 2014-2024, Cristian Maglie.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
10
README.md
10
README.md
@@ -2,17 +2,17 @@
|
||||
|
||||
# go.bug.st/serial
|
||||
|
||||
A cross-platform serial library for go-lang.
|
||||
A cross-platform serial port library for Go.
|
||||
|
||||
## Documentation and examples
|
||||
|
||||
See the godoc here: https://godoc.org/go.bug.st/serial
|
||||
See the package documentation here: https://pkg.go.dev/go.bug.st/serial
|
||||
|
||||
## go.mod transition
|
||||
|
||||
This library now support `go.mod` with the import `go.bug.st/serial`.
|
||||
This library supports `go.mod` with the import `go.bug.st/serial`.
|
||||
|
||||
If you came from the pre-`go.mod` era please update your import paths from `go.bug.st/serial.v1` to `go.bug.st/serial` to receive new updates. Anyway, the latest `v1` release should still be avaiable using the old import.
|
||||
If you came from the pre-`go.mod` era please update your import paths from `go.bug.st/serial.v1` to `go.bug.st/serial` to receive updates. The latest `v1` release is still available using the old import path.
|
||||
|
||||
## Credits
|
||||
|
||||
@@ -20,7 +20,7 @@ If you came from the pre-`go.mod` era please update your import paths from `go.b
|
||||
|
||||
## License
|
||||
|
||||
The software is release under a [BSD 3-clause license]
|
||||
This software is released under the [BSD 3-clause license].
|
||||
|
||||
[contributors]: https://github.com/bugst/go-serial/graphs/contributors
|
||||
[BSD 3-clause license]: https://github.com/bugst/go-serial/blob/master/LICENSE
|
||||
|
||||
2
doc.go
2
doc.go
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
|
||||
11
enumerator/usb_wasm.go
Normal file
11
enumerator/usb_wasm.go
Normal file
@@ -0,0 +1,11 @@
|
||||
//
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
|
||||
package enumerator
|
||||
|
||||
func nativeGetDetailedPortsList() ([]*PortDetails, error) {
|
||||
return nil, &PortEnumerationError{}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
@@ -98,7 +98,7 @@ const (
|
||||
spdrpUpperFilters = 0x00000011 // UpperFilters = R/W
|
||||
spdrpLowerFilters = 0x00000012 // LowerFilters = R/W
|
||||
spdrpBusTypeGUID = 0x00000013 // BusTypeGUID = R
|
||||
spdrpLegactBusType = 0x00000014 // LegacyBusType = R
|
||||
spdrpLegacyBusType = 0x00000014 // LegacyBusType = R
|
||||
spdrpBusNumber = 0x00000015 // BusNumber = R
|
||||
spdrpEnumeratorName = 0x00000016 // Enumerator Name = R
|
||||
spdrpSecurity = 0x00000017 // Security = R/W, binary form
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
|
||||
15
enumerator_wasm.go
Normal file
15
enumerator_wasm.go
Normal file
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
|
||||
package serial
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
func nativeGetPortsList() ([]string, error) {
|
||||
return nil, errors.New("nativeGetPortsList is not supported on wasm")
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
"go.bug.st/serial"
|
||||
)
|
||||
|
||||
func ExampleGetSetModemBits() {
|
||||
func ExamplePort_GetModemStatusBits() {
|
||||
// Open the first serial port detected at 9600bps N81
|
||||
mode := &serial.Mode{
|
||||
BaudRate: 9600,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
"go.bug.st/serial"
|
||||
)
|
||||
|
||||
func ExampleSerialPort_SetMode() {
|
||||
func ExamplePort_SetMode() {
|
||||
port, err := serial.Open("/dev/ttyACM0", &serial.Mode{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
|
||||
8
go.mod
8
go.mod
@@ -4,12 +4,12 @@ go 1.17
|
||||
|
||||
require (
|
||||
github.com/creack/goselect v0.1.2
|
||||
github.com/stretchr/testify v1.7.0
|
||||
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261
|
||||
github.com/stretchr/testify v1.8.4
|
||||
golang.org/x/sys v0.19.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
20
go.sum
20
go.sum
@@ -1,17 +1,21 @@
|
||||
github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0=
|
||||
github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY=
|
||||
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
@@ -12,7 +12,7 @@
|
||||
// Port: /dev/cu.usbmodemFD121
|
||||
// USB ID 2341:8053
|
||||
// USB serial FB7B6060504B5952302E314AFF08191A
|
||||
//
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
@@ -147,7 +147,7 @@ const (
|
||||
PortNotFound
|
||||
// InvalidSerialPort the requested port is not a serial port
|
||||
InvalidSerialPort
|
||||
// PermissionDenied the user doesn't have enough priviledges
|
||||
// PermissionDenied the user doesn't have enough privileges
|
||||
PermissionDenied
|
||||
// InvalidSpeed the requested speed is not valid or not supported
|
||||
InvalidSpeed
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
|
||||
package serial
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const devFolder = "/dev"
|
||||
const regexFilter = "^(cu|tty)\\..*"
|
||||
|
||||
var osPortFilter = regexp.MustCompile("^(cu|tty)\\..*")
|
||||
|
||||
const ioctlTcgetattr = unix.TIOCGETA
|
||||
const ioctlTcsetattr = unix.TIOCSETA
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
|
||||
package serial
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const devFolder = "/dev"
|
||||
const regexFilter = "^(cu|tty)\\..*"
|
||||
|
||||
var osPortFilter = regexp.MustCompile("^(cu|tty)\\..*")
|
||||
|
||||
// termios manipulation functions
|
||||
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
|
||||
package serial
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const devFolder = "/dev"
|
||||
const regexFilter = "(ttyS|ttyHS|ttyUSB|ttyACM|ttyAMA|rfcomm|ttyO|ttymxc)[0-9]{1,3}"
|
||||
|
||||
var osPortFilter = regexp.MustCompile("(ttyS|ttyHS|ttyUSB|ttyACM|ttyAMA|rfcomm|ttyO|ttymxc)[0-9]{1,3}")
|
||||
|
||||
// termios manipulation functions
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
|
||||
package serial
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const devFolder = "/dev"
|
||||
const regexFilter = "^(cu|tty)\\..*"
|
||||
|
||||
var osPortFilter = regexp.MustCompile("^(cu|tty)\\..*")
|
||||
|
||||
// termios manipulation functions
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
@@ -10,8 +10,7 @@ package serial
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"regexp"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
@@ -242,7 +241,7 @@ func nativeOpen(portName string, mode *Mode) (*unixPort, error) {
|
||||
// Explicitly disable RTS/CTS flow control
|
||||
setTermSettingsCtsRts(false, settings)
|
||||
|
||||
if port.setTermSettings(settings) != nil {
|
||||
if err = port.setTermSettings(settings); err != nil {
|
||||
port.Close()
|
||||
return nil, &PortError{code: InvalidSerialPort, causedBy: fmt.Errorf("error setting term settings: %w", err)}
|
||||
}
|
||||
@@ -292,16 +291,12 @@ func nativeOpen(portName string, mode *Mode) (*unixPort, error) {
|
||||
}
|
||||
|
||||
func nativeGetPortsList() ([]string, error) {
|
||||
files, err := ioutil.ReadDir(devFolder)
|
||||
files, err := os.ReadDir(devFolder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ports := make([]string, 0, len(files))
|
||||
regex, err := regexp.Compile(regexFilter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, f := range files {
|
||||
// Skip folders
|
||||
if f.IsDir() {
|
||||
@@ -309,7 +304,7 @@ func nativeGetPortsList() ([]string, error) {
|
||||
}
|
||||
|
||||
// Keep only devices with the correct name
|
||||
if !regex.MatchString(f.Name()) {
|
||||
if !osPortFilter.MatchString(f.Name()) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
15
serial_wasm.go
Normal file
15
serial_wasm.go
Normal file
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
|
||||
package serial
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
func nativeOpen(portName string, mode *Mode) (Port, error) {
|
||||
return nil, errors.New("nativeOpen is not supported on wasm")
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
@@ -18,48 +18,50 @@ package serial
|
||||
*/
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.org/x/sys/windows/registry"
|
||||
)
|
||||
|
||||
type windowsPort struct {
|
||||
mu sync.Mutex
|
||||
handle syscall.Handle
|
||||
mu sync.Mutex
|
||||
handle windows.Handle
|
||||
hasTimeout bool
|
||||
}
|
||||
|
||||
func nativeGetPortsList() ([]string, error) {
|
||||
subKey, err := syscall.UTF16PtrFromString("HARDWARE\\DEVICEMAP\\SERIALCOMM\\")
|
||||
key, err := registry.OpenKey(windows.HKEY_LOCAL_MACHINE, `HARDWARE\DEVICEMAP\SERIALCOMM\`, windows.KEY_READ)
|
||||
switch {
|
||||
case errors.Is(err, syscall.ERROR_FILE_NOT_FOUND):
|
||||
// On machines with no serial ports the registry key does not exist.
|
||||
// Return this as no serial ports instead of an error.
|
||||
return nil, nil
|
||||
case err != nil:
|
||||
return nil, &PortError{code: ErrorEnumeratingPorts, causedBy: err}
|
||||
}
|
||||
defer key.Close()
|
||||
|
||||
names, err := key.ReadValueNames(0)
|
||||
if err != nil {
|
||||
return nil, &PortError{code: ErrorEnumeratingPorts}
|
||||
return nil, &PortError{code: ErrorEnumeratingPorts, causedBy: err}
|
||||
}
|
||||
|
||||
var h syscall.Handle
|
||||
if err := syscall.RegOpenKeyEx(syscall.HKEY_LOCAL_MACHINE, subKey, 0, syscall.KEY_READ, &h); err != nil {
|
||||
if errno, isErrno := err.(syscall.Errno); isErrno && errno == syscall.ERROR_FILE_NOT_FOUND {
|
||||
return []string{}, nil
|
||||
var values []string
|
||||
for _, n := range names {
|
||||
v, _, err := key.GetStringValue(n)
|
||||
if err != nil || v == "" {
|
||||
continue
|
||||
}
|
||||
return nil, &PortError{code: ErrorEnumeratingPorts}
|
||||
}
|
||||
defer syscall.RegCloseKey(h)
|
||||
|
||||
var valuesCount uint32
|
||||
if syscall.RegQueryInfoKey(h, nil, nil, nil, nil, nil, nil, &valuesCount, nil, nil, nil, nil) != nil {
|
||||
return nil, &PortError{code: ErrorEnumeratingPorts}
|
||||
values = append(values, v)
|
||||
}
|
||||
|
||||
list := make([]string, valuesCount)
|
||||
for i := range list {
|
||||
var data [1024]uint16
|
||||
dataSize := uint32(len(data))
|
||||
var name [1024]uint16
|
||||
nameSize := uint32(len(name))
|
||||
if regEnumValue(h, uint32(i), &name[0], &nameSize, nil, nil, &data[0], &dataSize) != nil {
|
||||
return nil, &PortError{code: ErrorEnumeratingPorts}
|
||||
}
|
||||
list[i] = syscall.UTF16ToString(data[:])
|
||||
}
|
||||
return list, nil
|
||||
return values, nil
|
||||
}
|
||||
|
||||
func (port *windowsPort) Close() error {
|
||||
@@ -71,7 +73,7 @@ func (port *windowsPort) Close() error {
|
||||
if port.handle == 0 {
|
||||
return nil
|
||||
}
|
||||
return syscall.CloseHandle(port.handle)
|
||||
return windows.CloseHandle(port.handle)
|
||||
}
|
||||
|
||||
func (port *windowsPort) Read(p []byte) (int, error) {
|
||||
@@ -80,28 +82,35 @@ func (port *windowsPort) Read(p []byte) (int, error) {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer syscall.CloseHandle(ev.HEvent)
|
||||
defer windows.CloseHandle(ev.HEvent)
|
||||
|
||||
err = syscall.ReadFile(port.handle, p, &readed, ev)
|
||||
if err == syscall.ERROR_IO_PENDING {
|
||||
err = getOverlappedResult(port.handle, ev, &readed, true)
|
||||
}
|
||||
switch err {
|
||||
case nil:
|
||||
// operation completed successfully
|
||||
case syscall.ERROR_OPERATION_ABORTED:
|
||||
// port may have been closed
|
||||
return int(readed), &PortError{code: PortClosed, causedBy: err}
|
||||
default:
|
||||
// error happened
|
||||
return int(readed), err
|
||||
}
|
||||
if readed > 0 {
|
||||
return int(readed), nil
|
||||
}
|
||||
for {
|
||||
err = windows.ReadFile(port.handle, p, &readed, ev)
|
||||
if err == windows.ERROR_IO_PENDING {
|
||||
err = windows.GetOverlappedResult(port.handle, ev, &readed, true)
|
||||
}
|
||||
switch err {
|
||||
case nil:
|
||||
// operation completed successfully
|
||||
case windows.ERROR_OPERATION_ABORTED:
|
||||
// port may have been closed
|
||||
return int(readed), &PortError{code: PortClosed, causedBy: err}
|
||||
default:
|
||||
// error happened
|
||||
return int(readed), err
|
||||
}
|
||||
if readed > 0 {
|
||||
return int(readed), nil
|
||||
}
|
||||
|
||||
// Timeout
|
||||
return 0, nil
|
||||
// Timeout
|
||||
port.mu.Lock()
|
||||
hasTimeout := port.hasTimeout
|
||||
port.mu.Unlock()
|
||||
if hasTimeout {
|
||||
return 0, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (port *windowsPort) Write(p []byte) (int, error) {
|
||||
@@ -110,32 +119,25 @@ func (port *windowsPort) Write(p []byte) (int, error) {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer syscall.CloseHandle(ev.HEvent)
|
||||
err = syscall.WriteFile(port.handle, p, &writed, ev)
|
||||
if err == syscall.ERROR_IO_PENDING {
|
||||
defer windows.CloseHandle(ev.HEvent)
|
||||
err = windows.WriteFile(port.handle, p, &writed, ev)
|
||||
if err == windows.ERROR_IO_PENDING {
|
||||
// wait for write to complete
|
||||
err = getOverlappedResult(port.handle, ev, &writed, true)
|
||||
err = windows.GetOverlappedResult(port.handle, ev, &writed, true)
|
||||
}
|
||||
return int(writed), err
|
||||
}
|
||||
|
||||
func (port *windowsPort) Drain() (err error) {
|
||||
return syscall.FlushFileBuffers(port.handle)
|
||||
return windows.FlushFileBuffers(port.handle)
|
||||
}
|
||||
|
||||
const (
|
||||
purgeRxAbort uint32 = 0x0002
|
||||
purgeRxClear = 0x0008
|
||||
purgeTxAbort = 0x0001
|
||||
purgeTxClear = 0x0004
|
||||
)
|
||||
|
||||
func (port *windowsPort) ResetInputBuffer() error {
|
||||
return purgeComm(port.handle, purgeRxClear|purgeRxAbort)
|
||||
return windows.PurgeComm(port.handle, windows.PURGE_RXCLEAR|windows.PURGE_RXABORT)
|
||||
}
|
||||
|
||||
func (port *windowsPort) ResetOutputBuffer() error {
|
||||
return purgeComm(port.handle, purgeTxClear|purgeTxAbort)
|
||||
return windows.PurgeComm(port.handle, windows.PURGE_TXCLEAR|windows.PURGE_TXABORT)
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -152,119 +154,44 @@ const (
|
||||
dcbInX = 0x00000200
|
||||
dcbErrorChar = 0x00000400
|
||||
dcbNull = 0x00000800
|
||||
dcbRTSControlDisbaleMask = ^uint32(0x00003000)
|
||||
dcbRTSControlDisableMask = ^uint32(0x00003000)
|
||||
dcbRTSControlEnable = 0x00001000
|
||||
dcbRTSControlHandshake = 0x00002000
|
||||
dcbRTSControlToggle = 0x00003000
|
||||
dcbAbortOnError = 0x00004000
|
||||
)
|
||||
|
||||
type dcb struct {
|
||||
DCBlength uint32
|
||||
BaudRate uint32
|
||||
|
||||
// Flags field is a bitfield
|
||||
// fBinary :1
|
||||
// fParity :1
|
||||
// fOutxCtsFlow :1
|
||||
// fOutxDsrFlow :1
|
||||
// fDtrControl :2
|
||||
// fDsrSensitivity :1
|
||||
// fTXContinueOnXoff :1
|
||||
// fOutX :1
|
||||
// fInX :1
|
||||
// fErrorChar :1
|
||||
// fNull :1
|
||||
// fRtsControl :2
|
||||
// fAbortOnError :1
|
||||
// fDummy2 :17
|
||||
Flags uint32
|
||||
|
||||
wReserved uint16
|
||||
XonLim uint16
|
||||
XoffLim uint16
|
||||
ByteSize byte
|
||||
Parity byte
|
||||
StopBits byte
|
||||
XonChar byte
|
||||
XoffChar byte
|
||||
ErrorChar byte
|
||||
EOFChar byte
|
||||
EvtChar byte
|
||||
wReserved1 uint16
|
||||
}
|
||||
|
||||
type commTimeouts struct {
|
||||
ReadIntervalTimeout uint32
|
||||
ReadTotalTimeoutMultiplier uint32
|
||||
ReadTotalTimeoutConstant uint32
|
||||
WriteTotalTimeoutMultiplier uint32
|
||||
WriteTotalTimeoutConstant uint32
|
||||
}
|
||||
|
||||
const (
|
||||
noParity = 0
|
||||
oddParity = 1
|
||||
evenParity = 2
|
||||
markParity = 3
|
||||
spaceParity = 4
|
||||
)
|
||||
|
||||
var parityMap = map[Parity]byte{
|
||||
NoParity: noParity,
|
||||
OddParity: oddParity,
|
||||
EvenParity: evenParity,
|
||||
MarkParity: markParity,
|
||||
SpaceParity: spaceParity,
|
||||
NoParity: windows.NOPARITY,
|
||||
OddParity: windows.ODDPARITY,
|
||||
EvenParity: windows.EVENPARITY,
|
||||
MarkParity: windows.MARKPARITY,
|
||||
SpaceParity: windows.SPACEPARITY,
|
||||
}
|
||||
|
||||
const (
|
||||
oneStopBit = 0
|
||||
one5StopBits = 1
|
||||
twoStopBits = 2
|
||||
)
|
||||
|
||||
var stopBitsMap = map[StopBits]byte{
|
||||
OneStopBit: oneStopBit,
|
||||
OnePointFiveStopBits: one5StopBits,
|
||||
TwoStopBits: twoStopBits,
|
||||
OneStopBit: windows.ONESTOPBIT,
|
||||
OnePointFiveStopBits: windows.ONE5STOPBITS,
|
||||
TwoStopBits: windows.TWOSTOPBITS,
|
||||
}
|
||||
|
||||
const (
|
||||
commFunctionSetXOFF = 1
|
||||
commFunctionSetXON = 2
|
||||
commFunctionSetRTS = 3
|
||||
commFunctionClrRTS = 4
|
||||
commFunctionSetDTR = 5
|
||||
commFunctionClrDTR = 6
|
||||
commFunctionSetBreak = 8
|
||||
commFunctionClrBreak = 9
|
||||
)
|
||||
|
||||
const (
|
||||
msCTSOn = 0x0010
|
||||
msDSROn = 0x0020
|
||||
msRingOn = 0x0040
|
||||
msRLSDOn = 0x0080
|
||||
)
|
||||
|
||||
func (port *windowsPort) SetMode(mode *Mode) error {
|
||||
params := dcb{}
|
||||
if getCommState(port.handle, ¶ms) != nil {
|
||||
params := windows.DCB{}
|
||||
if windows.GetCommState(port.handle, ¶ms) != nil {
|
||||
port.Close()
|
||||
return &PortError{code: InvalidSerialPort}
|
||||
}
|
||||
port.setModeParams(mode, ¶ms)
|
||||
if setCommState(port.handle, ¶ms) != nil {
|
||||
if windows.SetCommState(port.handle, ¶ms) != nil {
|
||||
port.Close()
|
||||
return &PortError{code: InvalidSerialPort}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (port *windowsPort) setModeParams(mode *Mode, params *dcb) {
|
||||
func (port *windowsPort) setModeParams(mode *Mode, params *windows.DCB) {
|
||||
if mode.BaudRate == 0 {
|
||||
params.BaudRate = 9600 // Default to 9600
|
||||
params.BaudRate = windows.CBR_9600 // Default to 9600
|
||||
} else {
|
||||
params.BaudRate = uint32(mode.BaudRate)
|
||||
}
|
||||
@@ -278,22 +205,22 @@ func (port *windowsPort) setModeParams(mode *Mode, params *dcb) {
|
||||
}
|
||||
|
||||
func (port *windowsPort) SetDTR(dtr bool) error {
|
||||
// Like for RTS there are problems with the escapeCommFunction
|
||||
// Like for RTS there are problems with the windows.EscapeCommFunction
|
||||
// observed behaviour was that DTR is set from false -> true
|
||||
// when setting RTS from true -> false
|
||||
// 1) Connect -> RTS = true (low) DTR = true (low) OKAY
|
||||
// 2) SetDTR(false) -> RTS = true (low) DTR = false (heigh) OKAY
|
||||
// 3) SetRTS(false) -> RTS = false (heigh) DTR = true (low) ERROR: DTR toggled
|
||||
// 2) SetDTR(false) -> RTS = true (low) DTR = false (high) OKAY
|
||||
// 3) SetRTS(false) -> RTS = false (high) DTR = true (low) ERROR: DTR toggled
|
||||
//
|
||||
// In addition this way the CommState Flags are not updated
|
||||
/*
|
||||
var res bool
|
||||
var err error
|
||||
if dtr {
|
||||
res = escapeCommFunction(port.handle, commFunctionSetDTR)
|
||||
err = windows.EscapeCommFunction(port.handle, windows.SETDTR)
|
||||
} else {
|
||||
res = escapeCommFunction(port.handle, commFunctionClrDTR)
|
||||
err = windows.EscapeCommFunction(port.handle, windows.CLTDTR)
|
||||
}
|
||||
if !res {
|
||||
if err != nil {
|
||||
return &PortError{}
|
||||
}
|
||||
return nil
|
||||
@@ -301,15 +228,15 @@ func (port *windowsPort) SetDTR(dtr bool) error {
|
||||
|
||||
// The following seems a more reliable way to do it
|
||||
|
||||
params := &dcb{}
|
||||
if err := getCommState(port.handle, params); err != nil {
|
||||
params := &windows.DCB{}
|
||||
if err := windows.GetCommState(port.handle, params); err != nil {
|
||||
return &PortError{causedBy: err}
|
||||
}
|
||||
params.Flags &= dcbDTRControlDisableMask
|
||||
if dtr {
|
||||
params.Flags |= dcbDTRControlEnable
|
||||
params.Flags |= windows.DTR_CONTROL_ENABLE
|
||||
}
|
||||
if err := setCommState(port.handle, params); err != nil {
|
||||
if err := windows.SetCommState(port.handle, params); err != nil {
|
||||
return &PortError{causedBy: err}
|
||||
}
|
||||
|
||||
@@ -325,13 +252,13 @@ func (port *windowsPort) SetRTS(rts bool) error {
|
||||
// In addition this way the CommState Flags are not updated
|
||||
|
||||
/*
|
||||
var res bool
|
||||
var err error
|
||||
if rts {
|
||||
res = escapeCommFunction(port.handle, commFunctionSetRTS)
|
||||
err = windows.EscapeCommFunction(port.handle, windows.SETRTS)
|
||||
} else {
|
||||
res = escapeCommFunction(port.handle, commFunctionClrRTS)
|
||||
err = windows.EscapeCommFunction(port.handle, windows.CLRRTS)
|
||||
}
|
||||
if !res {
|
||||
if err != nil {
|
||||
return &PortError{}
|
||||
}
|
||||
return nil
|
||||
@@ -339,15 +266,15 @@ func (port *windowsPort) SetRTS(rts bool) error {
|
||||
|
||||
// The following seems a more reliable way to do it
|
||||
|
||||
params := &dcb{}
|
||||
if err := getCommState(port.handle, params); err != nil {
|
||||
params := &windows.DCB{}
|
||||
if err := windows.GetCommState(port.handle, params); err != nil {
|
||||
return &PortError{causedBy: err}
|
||||
}
|
||||
params.Flags &= dcbRTSControlDisbaleMask
|
||||
params.Flags &= dcbRTSControlDisableMask
|
||||
if rts {
|
||||
params.Flags |= dcbRTSControlEnable
|
||||
params.Flags |= windows.RTS_CONTROL_ENABLE
|
||||
}
|
||||
if err := setCommState(port.handle, params); err != nil {
|
||||
if err := windows.SetCommState(port.handle, params); err != nil {
|
||||
return &PortError{causedBy: err}
|
||||
}
|
||||
return nil
|
||||
@@ -355,22 +282,31 @@ func (port *windowsPort) SetRTS(rts bool) error {
|
||||
|
||||
func (port *windowsPort) GetModemStatusBits() (*ModemStatusBits, error) {
|
||||
var bits uint32
|
||||
if !getCommModemStatus(port.handle, &bits) {
|
||||
if err := windows.GetCommModemStatus(port.handle, &bits); err != nil {
|
||||
return nil, &PortError{}
|
||||
}
|
||||
return &ModemStatusBits{
|
||||
CTS: (bits & msCTSOn) != 0,
|
||||
DCD: (bits & msRLSDOn) != 0,
|
||||
DSR: (bits & msDSROn) != 0,
|
||||
RI: (bits & msRingOn) != 0,
|
||||
CTS: (bits & windows.EV_CTS) != 0,
|
||||
DCD: (bits & windows.EV_RLSD) != 0,
|
||||
DSR: (bits & windows.EV_DSR) != 0,
|
||||
RI: (bits & windows.EV_RING) != 0,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (port *windowsPort) SetReadTimeout(timeout time.Duration) error {
|
||||
commTimeouts := &commTimeouts{
|
||||
// This is a brutal hack to make the CH340 chipset work properly.
|
||||
// Normally this value should be 0xFFFFFFFE but, after a lot of
|
||||
// tinkering, I discovered that any value with the highest
|
||||
// bit set will make the CH340 driver behave like the timeout is 0,
|
||||
// in the best cases leading to a spinning loop...
|
||||
// (could this be a wrong signed vs unsigned conversion in the driver?)
|
||||
// https://github.com/arduino/serial-monitor/issues/112
|
||||
const MaxReadTotalTimeoutConstant = 0x7FFFFFFE
|
||||
|
||||
commTimeouts := &windows.CommTimeouts{
|
||||
ReadIntervalTimeout: 0xFFFFFFFF,
|
||||
ReadTotalTimeoutMultiplier: 0xFFFFFFFF,
|
||||
ReadTotalTimeoutConstant: 0xFFFFFFFE,
|
||||
ReadTotalTimeoutConstant: MaxReadTotalTimeoutConstant,
|
||||
WriteTotalTimeoutConstant: 0,
|
||||
WriteTotalTimeoutMultiplier: 0,
|
||||
}
|
||||
@@ -379,53 +315,63 @@ func (port *windowsPort) SetReadTimeout(timeout time.Duration) error {
|
||||
if ms > 0xFFFFFFFE || ms < 0 {
|
||||
return &PortError{code: InvalidTimeoutValue}
|
||||
}
|
||||
|
||||
if ms > MaxReadTotalTimeoutConstant {
|
||||
ms = MaxReadTotalTimeoutConstant
|
||||
}
|
||||
|
||||
commTimeouts.ReadTotalTimeoutConstant = uint32(ms)
|
||||
}
|
||||
|
||||
if err := setCommTimeouts(port.handle, commTimeouts); err != nil {
|
||||
port.mu.Lock()
|
||||
defer port.mu.Unlock()
|
||||
if err := windows.SetCommTimeouts(port.handle, commTimeouts); err != nil {
|
||||
return &PortError{code: InvalidTimeoutValue, causedBy: err}
|
||||
}
|
||||
port.hasTimeout = (timeout != NoTimeout)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (port *windowsPort) Break(d time.Duration) error {
|
||||
if err := setCommBreak(port.handle); err != nil {
|
||||
if err := windows.SetCommBreak(port.handle); err != nil {
|
||||
return &PortError{causedBy: err}
|
||||
}
|
||||
|
||||
time.Sleep(d)
|
||||
|
||||
if err := clearCommBreak(port.handle); err != nil {
|
||||
if err := windows.ClearCommBreak(port.handle); err != nil {
|
||||
return &PortError{causedBy: err}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createOverlappedEvent() (*syscall.Overlapped, error) {
|
||||
h, err := createEvent(nil, true, false, nil)
|
||||
return &syscall.Overlapped{HEvent: h}, err
|
||||
func createOverlappedEvent() (*windows.Overlapped, error) {
|
||||
h, err := windows.CreateEvent(nil, 1, 0, nil)
|
||||
return &windows.Overlapped{HEvent: h}, err
|
||||
}
|
||||
|
||||
func nativeOpen(portName string, mode *Mode) (*windowsPort, error) {
|
||||
portName = "\\\\.\\" + portName
|
||||
path, err := syscall.UTF16PtrFromString(portName)
|
||||
if !strings.HasPrefix(portName, `\\.\`) {
|
||||
portName = `\\.\` + portName
|
||||
}
|
||||
path, err := windows.UTF16PtrFromString(portName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
handle, err := syscall.CreateFile(
|
||||
handle, err := windows.CreateFile(
|
||||
path,
|
||||
syscall.GENERIC_READ|syscall.GENERIC_WRITE,
|
||||
windows.GENERIC_READ|windows.GENERIC_WRITE,
|
||||
0, nil,
|
||||
syscall.OPEN_EXISTING,
|
||||
syscall.FILE_FLAG_OVERLAPPED,
|
||||
windows.OPEN_EXISTING,
|
||||
windows.FILE_FLAG_OVERLAPPED,
|
||||
0)
|
||||
if err != nil {
|
||||
switch err {
|
||||
case syscall.ERROR_ACCESS_DENIED:
|
||||
case windows.ERROR_ACCESS_DENIED:
|
||||
return nil, &PortError{code: PortBusy}
|
||||
case syscall.ERROR_FILE_NOT_FOUND:
|
||||
case windows.ERROR_FILE_NOT_FOUND:
|
||||
return nil, &PortError{code: PortNotFound}
|
||||
}
|
||||
return nil, err
|
||||
@@ -436,23 +382,23 @@ func nativeOpen(portName string, mode *Mode) (*windowsPort, error) {
|
||||
}
|
||||
|
||||
// Set port parameters
|
||||
params := &dcb{}
|
||||
if getCommState(port.handle, params) != nil {
|
||||
params := &windows.DCB{}
|
||||
if windows.GetCommState(port.handle, params) != nil {
|
||||
port.Close()
|
||||
return nil, &PortError{code: InvalidSerialPort}
|
||||
}
|
||||
port.setModeParams(mode, params)
|
||||
params.Flags &= dcbDTRControlDisableMask
|
||||
params.Flags &= dcbRTSControlDisbaleMask
|
||||
params.Flags &= dcbRTSControlDisableMask
|
||||
if mode.InitialStatusBits == nil {
|
||||
params.Flags |= dcbDTRControlEnable
|
||||
params.Flags |= dcbRTSControlEnable
|
||||
params.Flags |= windows.DTR_CONTROL_ENABLE
|
||||
params.Flags |= windows.RTS_CONTROL_ENABLE
|
||||
} else {
|
||||
if mode.InitialStatusBits.DTR {
|
||||
params.Flags |= dcbDTRControlEnable
|
||||
params.Flags |= windows.DTR_CONTROL_ENABLE
|
||||
}
|
||||
if mode.InitialStatusBits.RTS {
|
||||
params.Flags |= dcbRTSControlEnable
|
||||
params.Flags |= windows.RTS_CONTROL_ENABLE
|
||||
}
|
||||
}
|
||||
params.Flags &^= dcbOutXCTSFlow
|
||||
@@ -468,7 +414,7 @@ func nativeOpen(portName string, mode *Mode) (*windowsPort, error) {
|
||||
params.XoffLim = 512
|
||||
params.XonChar = 17 // DC1
|
||||
params.XoffChar = 19 // C3
|
||||
if setCommState(port.handle, params) != nil {
|
||||
if windows.SetCommState(port.handle, params) != nil {
|
||||
port.Close()
|
||||
return nil, &PortError{code: InvalidSerialPort}
|
||||
}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
|
||||
package serial
|
||||
|
||||
//sys regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, value *uint16, valueLen *uint32) (regerrno error) = advapi32.RegEnumValueW
|
||||
|
||||
//sys getCommState(handle syscall.Handle, dcb *dcb) (err error) = GetCommState
|
||||
|
||||
//sys setCommState(handle syscall.Handle, dcb *dcb) (err error) = SetCommState
|
||||
|
||||
//sys setCommTimeouts(handle syscall.Handle, timeouts *commTimeouts) (err error) = SetCommTimeouts
|
||||
|
||||
//sys escapeCommFunction(handle syscall.Handle, function uint32) (res bool) = EscapeCommFunction
|
||||
|
||||
//sys getCommModemStatus(handle syscall.Handle, bits *uint32) (res bool) = GetCommModemStatus
|
||||
|
||||
//sys createEvent(eventAttributes *uint32, manualReset bool, initialState bool, name *uint16) (handle syscall.Handle, err error) = CreateEventW
|
||||
|
||||
//sys resetEvent(handle syscall.Handle) (err error) = ResetEvent
|
||||
|
||||
//sys getOverlappedResult(handle syscall.Handle, overlapEvent *syscall.Overlapped, n *uint32, wait bool) (err error) = GetOverlappedResult
|
||||
|
||||
//sys purgeComm(handle syscall.Handle, flags uint32) (err error) = PurgeComm
|
||||
|
||||
//sys setCommBreak(handle syscall.Handle) (err error) = SetCommBreak
|
||||
|
||||
//sys clearCommBreak(handle syscall.Handle) (err error) = ClearCommBreak
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
@@ -40,7 +40,7 @@ func (p *Pipe) ReadFD() int {
|
||||
return p.rd
|
||||
}
|
||||
|
||||
// WriteFD returns the flie handle for the write side of the pipe.
|
||||
// WriteFD returns the file handle for the write side of the pipe.
|
||||
func (p *Pipe) WriteFD() int {
|
||||
if !p.opened {
|
||||
return -1
|
||||
@@ -48,7 +48,7 @@ func (p *Pipe) WriteFD() int {
|
||||
return p.wr
|
||||
}
|
||||
|
||||
// Write to the pipe the content of data. Returns the numbre of bytes written.
|
||||
// Write to the pipe the content of data. Returns the number of bytes written.
|
||||
func (p *Pipe) Write(data []byte) (int, error) {
|
||||
if !p.opened {
|
||||
return 0, fmt.Errorf("Pipe not opened")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||||
// Copyright 2014-2024 Cristian Maglie. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
|
||||
@@ -1,161 +0,0 @@
|
||||
// Code generated by 'go generate'; DO NOT EDIT.
|
||||
|
||||
package serial
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var _ unsafe.Pointer
|
||||
|
||||
// Do the interface allocations only once for common
|
||||
// Errno values.
|
||||
const (
|
||||
errnoERROR_IO_PENDING = 997
|
||||
)
|
||||
|
||||
var (
|
||||
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
||||
errERROR_EINVAL error = syscall.EINVAL
|
||||
)
|
||||
|
||||
// errnoErr returns common boxed Errno values, to prevent
|
||||
// allocations at runtime.
|
||||
func errnoErr(e syscall.Errno) error {
|
||||
switch e {
|
||||
case 0:
|
||||
return errERROR_EINVAL
|
||||
case errnoERROR_IO_PENDING:
|
||||
return errERROR_IO_PENDING
|
||||
}
|
||||
// TODO: add more here, after collecting data on the common
|
||||
// error values see on Windows. (perhaps when running
|
||||
// all.bat?)
|
||||
return e
|
||||
}
|
||||
|
||||
var (
|
||||
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
|
||||
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
||||
|
||||
procRegEnumValueW = modadvapi32.NewProc("RegEnumValueW")
|
||||
procClearCommBreak = modkernel32.NewProc("ClearCommBreak")
|
||||
procCreateEventW = modkernel32.NewProc("CreateEventW")
|
||||
procEscapeCommFunction = modkernel32.NewProc("EscapeCommFunction")
|
||||
procGetCommModemStatus = modkernel32.NewProc("GetCommModemStatus")
|
||||
procGetCommState = modkernel32.NewProc("GetCommState")
|
||||
procGetOverlappedResult = modkernel32.NewProc("GetOverlappedResult")
|
||||
procPurgeComm = modkernel32.NewProc("PurgeComm")
|
||||
procResetEvent = modkernel32.NewProc("ResetEvent")
|
||||
procSetCommBreak = modkernel32.NewProc("SetCommBreak")
|
||||
procSetCommState = modkernel32.NewProc("SetCommState")
|
||||
procSetCommTimeouts = modkernel32.NewProc("SetCommTimeouts")
|
||||
)
|
||||
|
||||
func regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, value *uint16, valueLen *uint32) (regerrno error) {
|
||||
r0, _, _ := syscall.Syscall9(procRegEnumValueW.Addr(), 8, uintptr(key), uintptr(index), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(class)), uintptr(unsafe.Pointer(value)), uintptr(unsafe.Pointer(valueLen)), 0)
|
||||
if r0 != 0 {
|
||||
regerrno = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func clearCommBreak(handle syscall.Handle) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procClearCommBreak.Addr(), 1, uintptr(handle), 0, 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func createEvent(eventAttributes *uint32, manualReset bool, initialState bool, name *uint16) (handle syscall.Handle, err error) {
|
||||
var _p0 uint32
|
||||
if manualReset {
|
||||
_p0 = 1
|
||||
}
|
||||
var _p1 uint32
|
||||
if initialState {
|
||||
_p1 = 1
|
||||
}
|
||||
r0, _, e1 := syscall.Syscall6(procCreateEventW.Addr(), 4, uintptr(unsafe.Pointer(eventAttributes)), uintptr(_p0), uintptr(_p1), uintptr(unsafe.Pointer(name)), 0, 0)
|
||||
handle = syscall.Handle(r0)
|
||||
if handle == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func escapeCommFunction(handle syscall.Handle, function uint32) (res bool) {
|
||||
r0, _, _ := syscall.Syscall(procEscapeCommFunction.Addr(), 2, uintptr(handle), uintptr(function), 0)
|
||||
res = r0 != 0
|
||||
return
|
||||
}
|
||||
|
||||
func getCommModemStatus(handle syscall.Handle, bits *uint32) (res bool) {
|
||||
r0, _, _ := syscall.Syscall(procGetCommModemStatus.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(bits)), 0)
|
||||
res = r0 != 0
|
||||
return
|
||||
}
|
||||
|
||||
func getCommState(handle syscall.Handle, dcb *dcb) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procGetCommState.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(dcb)), 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getOverlappedResult(handle syscall.Handle, overlapEvent *syscall.Overlapped, n *uint32, wait bool) (err error) {
|
||||
var _p0 uint32
|
||||
if wait {
|
||||
_p0 = 1
|
||||
}
|
||||
r1, _, e1 := syscall.Syscall6(procGetOverlappedResult.Addr(), 4, uintptr(handle), uintptr(unsafe.Pointer(overlapEvent)), uintptr(unsafe.Pointer(n)), uintptr(_p0), 0, 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func purgeComm(handle syscall.Handle, flags uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procPurgeComm.Addr(), 2, uintptr(handle), uintptr(flags), 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func resetEvent(handle syscall.Handle) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procResetEvent.Addr(), 1, uintptr(handle), 0, 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setCommBreak(handle syscall.Handle) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetCommBreak.Addr(), 1, uintptr(handle), 0, 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setCommState(handle syscall.Handle, dcb *dcb) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetCommState.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(dcb)), 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setCommTimeouts(handle syscall.Handle, timeouts *commTimeouts) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetCommTimeouts.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(timeouts)), 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user