Skip to content

Commit 2b15b67

Browse files
committed
Updated go.bug.st/serial.v1
1 parent 2973655 commit 2b15b67

File tree

4 files changed

+286
-25
lines changed

4 files changed

+286
-25
lines changed

Diff for: Gopkg.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: vendor/go.bug.st/serial.v1/.travis.yml

+29
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
language: go
22

3+
os:
4+
- linux
5+
- osx
6+
37
go:
48
- 1.7.x
59
- 1.8.x
10+
- 1.9.x
11+
- 1.10.x
612

713
go_import_path: go.bug.st/serial.v1
814

@@ -20,6 +26,29 @@ env:
2026
- TEST_OS=openbsd TEST_ARCH=arm
2127

2228
matrix:
29+
exclude:
30+
- os: linux
31+
env: TEST_OS=darwin TEST_ARCH=386
32+
- os: linux
33+
env: TEST_OS=darwin TEST_ARCH=amd64
34+
- os: osx
35+
env: TEST_OS=linux TEST_ARCH=386
36+
- os: osx
37+
env: TEST_OS=linux TEST_ARCH=amd64
38+
- os: osx
39+
env: TEST_OS=linux TEST_ARCH=arm
40+
- os: osx
41+
env: TEST_OS=windows TEST_ARCH=386
42+
- os: osx
43+
env: TEST_OS=windows TEST_ARCH=amd64
44+
- os: osx
45+
env: TEST_OS=freebsd TEST_ARCH=amd64
46+
- os: osx
47+
env: TEST_OS=openbsd TEST_ARCH=amd64
48+
- os: osx
49+
env: TEST_OS=openbsd TEST_ARCH=386
50+
- os: osx
51+
env: TEST_OS=openbsd TEST_ARCH=arm
2352
allow_failures:
2453
- env: TEST_OS=openbsd TEST_ARCH=arm
2554

Diff for: vendor/go.bug.st/serial.v1/enumerator/usb_darwin.go

+34-24
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
// license that can be found in the LICENSE file.
55
//
66

7+
// +build go1.10,darwin
8+
79
package enumerator // import "go.bug.st/serial.v1/enumerator"
810

9-
// #cgo LDFLAGS: -framework CoreFoundation -framework IOKit -fconstant-cfstrings
11+
// #cgo LDFLAGS: -framework CoreFoundation -framework IOKit
1012
// #include <IOKit/IOKitLib.h>
1113
// #include <CoreFoundation/CoreFoundation.h>
1214
// #include <stdlib.h>
@@ -46,12 +48,13 @@ func extractPortInfo(service C.io_registry_entry_t) (*PortDetails, error) {
4648
port.IsUSB = false
4749

4850
usbDevice := service
51+
var searchErr error
4952
for usbDevice.GetClass() != "IOUSBDevice" {
50-
if usbDevice, err = usbDevice.GetParent("IOService"); err != nil {
53+
if usbDevice, searchErr = usbDevice.GetParent("IOService"); searchErr != nil {
5154
break
5255
}
5356
}
54-
if err == nil {
57+
if searchErr == nil {
5558
// It's an IOUSBDevice
5659
vid, _ := usbDevice.GetIntProperty("idVendor", C.kCFNumberSInt16Type)
5760
pid, _ := usbDevice.GetIntProperty("idProduct", C.kCFNumberSInt16Type)
@@ -125,6 +128,16 @@ func cfStringCreateWithString(s string) C.CFStringRef {
125128
C.kCFAllocatorDefault, c, C.kCFStringEncodingMacRoman)
126129
}
127130

131+
func (ref C.CFStringRef) Release() {
132+
C.CFRelease(C.CFTypeRef(ref))
133+
}
134+
135+
// CFTypeRef
136+
137+
func (ref C.CFTypeRef) Release() {
138+
C.CFRelease(ref)
139+
}
140+
128141
// io_registry_entry_t
129142

130143
func (me *C.io_registry_entry_t) GetParent(plane string) (C.io_registry_entry_t, error) {
@@ -138,40 +151,41 @@ func (me *C.io_registry_entry_t) GetParent(plane string) (C.io_registry_entry_t,
138151
return parent, nil
139152
}
140153

141-
func (me *C.io_registry_entry_t) GetClass() string {
142-
obj := (*C.io_object_t)(me)
143-
return obj.GetClass()
154+
func (me *C.io_registry_entry_t) CreateCFProperty(key string) (C.CFTypeRef, error) {
155+
k := cfStringCreateWithString(key)
156+
defer k.Release()
157+
property := C.IORegistryEntryCreateCFProperty(*me, k, C.kCFAllocatorDefault, 0)
158+
if property == 0 {
159+
return 0, errors.New("Property not found: " + key)
160+
}
161+
return property, nil
144162
}
145163

146164
func (me *C.io_registry_entry_t) GetStringProperty(key string) (string, error) {
147-
k := cfStringCreateWithString(key)
148-
defer C.CFRelease(C.CFTypeRef(k))
149-
property := C.IORegistryEntryCreateCFProperty(*me, k, C.kCFAllocatorDefault, 0)
150-
if property == nil {
151-
return "", errors.New("Property not found: " + key)
165+
property, err := me.CreateCFProperty(key)
166+
if err != nil {
167+
return "", err
152168
}
153-
defer C.CFRelease(property)
169+
defer property.Release()
154170

155-
if ptr := C.CFStringGetCStringPtr((C.CFStringRef)(unsafe.Pointer(property)), 0); ptr != nil {
171+
if ptr := C.CFStringGetCStringPtr(C.CFStringRef(property), 0); ptr != nil {
156172
return C.GoString(ptr), nil
157173
}
158174
// in certain circumstances CFStringGetCStringPtr may return NULL
159175
// and we must retrieve the string by copy
160176
buff := make([]C.char, 1024)
161-
if C.CFStringGetCString((C.CFStringRef)(property), &buff[0], 1024, 0) != C.true {
177+
if C.CFStringGetCString(C.CFStringRef(property), &buff[0], 1024, 0) != C.true {
162178
return "", fmt.Errorf("Property '%s' can't be converted", key)
163179
}
164180
return C.GoString(&buff[0]), nil
165181
}
166182

167183
func (me *C.io_registry_entry_t) GetIntProperty(key string, intType C.CFNumberType) (int, error) {
168-
k := cfStringCreateWithString(key)
169-
defer C.CFRelease(C.CFTypeRef(k))
170-
property := C.IORegistryEntryCreateCFProperty(*me, k, C.kCFAllocatorDefault, 0)
171-
if property == nil {
172-
return 0, errors.New("Property not found: " + key)
184+
property, err := me.CreateCFProperty(key)
185+
if err != nil {
186+
return 0, err
173187
}
174-
defer C.CFRelease(property)
188+
defer property.Release()
175189
var res int
176190
if C.CFNumberGetValue((C.CFNumberRef)(property), intType, unsafe.Pointer(&res)) != C.true {
177191
return res, fmt.Errorf("Property '%s' can't be converted or has been truncated", key)
@@ -199,10 +213,6 @@ func (me *C.io_iterator_t) Next() (C.io_object_t, bool) {
199213
return res, res != 0
200214
}
201215

202-
func (me *C.io_iterator_t) Release() {
203-
C.IOObjectRelease(C.io_object_t(*me))
204-
}
205-
206216
// io_object_t
207217

208218
func (me *C.io_object_t) Release() {
+222
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
//
2+
// Copyright 2014-2017 Cristian Maglie. All rights reserved.
3+
// Use of this source code is governed by a BSD-style
4+
// license that can be found in the LICENSE file.
5+
//
6+
7+
// +build !go1.10,darwin
8+
9+
// This file is here to keep compatibility with the older versions of go
10+
// and is no more maintained or bugfixed, please update your go version
11+
// to at least 1.10 to get the latest updates.
12+
13+
package enumerator // import "go.bug.st/serial.v1/enumerator"
14+
15+
// #cgo LDFLAGS: -framework CoreFoundation -framework IOKit
16+
// #include <IOKit/IOKitLib.h>
17+
// #include <CoreFoundation/CoreFoundation.h>
18+
// #include <stdlib.h>
19+
import "C"
20+
import (
21+
"errors"
22+
"fmt"
23+
"unsafe"
24+
)
25+
26+
func nativeGetDetailedPortsList() ([]*PortDetails, error) {
27+
var ports []*PortDetails
28+
29+
services, err := getAllServices("IOSerialBSDClient")
30+
if err != nil {
31+
return nil, &PortEnumerationError{causedBy: err}
32+
}
33+
for _, service := range services {
34+
defer service.Release()
35+
36+
port, err := extractPortInfo(C.io_registry_entry_t(service))
37+
if err != nil {
38+
return nil, &PortEnumerationError{causedBy: err}
39+
}
40+
ports = append(ports, port)
41+
}
42+
return ports, nil
43+
}
44+
45+
func extractPortInfo(service C.io_registry_entry_t) (*PortDetails, error) {
46+
name, err := service.GetStringProperty("IOCalloutDevice")
47+
if err != nil {
48+
return nil, fmt.Errorf("Error extracting port info from device: %s", err.Error())
49+
}
50+
port := &PortDetails{}
51+
port.Name = name
52+
port.IsUSB = false
53+
54+
usbDevice := service
55+
for usbDevice.GetClass() != "IOUSBDevice" {
56+
if usbDevice, err = usbDevice.GetParent("IOService"); err != nil {
57+
break
58+
}
59+
}
60+
if err == nil {
61+
// It's an IOUSBDevice
62+
vid, _ := usbDevice.GetIntProperty("idVendor", C.kCFNumberSInt16Type)
63+
pid, _ := usbDevice.GetIntProperty("idProduct", C.kCFNumberSInt16Type)
64+
serialNumber, _ := usbDevice.GetStringProperty("USB Serial Number")
65+
//product, _ := usbDevice.GetStringProperty("USB Product Name")
66+
//manufacturer, _ := usbDevice.GetStringProperty("USB Vendor Name")
67+
//fmt.Println(product + " - " + manufacturer)
68+
69+
port.IsUSB = true
70+
port.VID = fmt.Sprintf("%04X", vid)
71+
port.PID = fmt.Sprintf("%04X", pid)
72+
port.SerialNumber = serialNumber
73+
}
74+
return port, nil
75+
}
76+
77+
func getAllServices(serviceType string) ([]C.io_object_t, error) {
78+
i, err := getMatchingServices(serviceMatching(serviceType))
79+
if err != nil {
80+
return nil, err
81+
}
82+
defer i.Release()
83+
84+
var services []C.io_object_t
85+
tries := 0
86+
for tries < 5 {
87+
// Extract all elements from iterator
88+
if service, ok := i.Next(); ok {
89+
services = append(services, service)
90+
continue
91+
}
92+
// If iterator is still valid return the result
93+
if i.IsValid() {
94+
return services, nil
95+
}
96+
// Otherwise empty the result and retry
97+
for _, s := range services {
98+
s.Release()
99+
}
100+
services = []C.io_object_t{}
101+
i.Reset()
102+
tries++
103+
}
104+
// Give up if the iteration continues to fail...
105+
return nil, fmt.Errorf("IOServiceGetMatchingServices failed, data changed while iterating")
106+
}
107+
108+
// serviceMatching create a matching dictionary that specifies an IOService class match.
109+
func serviceMatching(serviceType string) C.CFMutableDictionaryRef {
110+
t := C.CString(serviceType)
111+
defer C.free(unsafe.Pointer(t))
112+
return C.IOServiceMatching(t)
113+
}
114+
115+
// getMatchingServices look up registered IOService objects that match a matching dictionary.
116+
func getMatchingServices(matcher C.CFMutableDictionaryRef) (C.io_iterator_t, error) {
117+
var i C.io_iterator_t
118+
err := C.IOServiceGetMatchingServices(C.kIOMasterPortDefault, matcher, &i)
119+
if err != C.KERN_SUCCESS {
120+
return 0, fmt.Errorf("IOServiceGetMatchingServices failed (code %d)", err)
121+
}
122+
return i, nil
123+
}
124+
125+
// CFStringRef
126+
127+
func cfStringCreateWithString(s string) C.CFStringRef {
128+
c := C.CString(s)
129+
defer C.free(unsafe.Pointer(c))
130+
return C.CFStringCreateWithCString(
131+
C.kCFAllocatorDefault, c, C.kCFStringEncodingMacRoman)
132+
}
133+
134+
// io_registry_entry_t
135+
136+
func (me *C.io_registry_entry_t) GetParent(plane string) (C.io_registry_entry_t, error) {
137+
cPlane := C.CString(plane)
138+
defer C.free(unsafe.Pointer(cPlane))
139+
var parent C.io_registry_entry_t
140+
err := C.IORegistryEntryGetParentEntry(*me, cPlane, &parent)
141+
if err != 0 {
142+
return 0, errors.New("No parent device available")
143+
}
144+
return parent, nil
145+
}
146+
147+
func (me *C.io_registry_entry_t) GetClass() string {
148+
obj := (*C.io_object_t)(me)
149+
return obj.GetClass()
150+
}
151+
152+
func (me *C.io_registry_entry_t) GetStringProperty(key string) (string, error) {
153+
k := cfStringCreateWithString(key)
154+
defer C.CFRelease(C.CFTypeRef(k))
155+
property := C.IORegistryEntryCreateCFProperty(*me, k, C.kCFAllocatorDefault, 0)
156+
if property == nil {
157+
return "", errors.New("Property not found: " + key)
158+
}
159+
defer C.CFRelease(property)
160+
161+
if ptr := C.CFStringGetCStringPtr((C.CFStringRef)(unsafe.Pointer(property)), 0); ptr != nil {
162+
return C.GoString(ptr), nil
163+
}
164+
// in certain circumstances CFStringGetCStringPtr may return NULL
165+
// and we must retrieve the string by copy
166+
buff := make([]C.char, 1024)
167+
if C.CFStringGetCString((C.CFStringRef)(property), &buff[0], 1024, 0) != C.true {
168+
return "", fmt.Errorf("Property '%s' can't be converted", key)
169+
}
170+
return C.GoString(&buff[0]), nil
171+
}
172+
173+
func (me *C.io_registry_entry_t) GetIntProperty(key string, intType C.CFNumberType) (int, error) {
174+
k := cfStringCreateWithString(key)
175+
defer C.CFRelease(C.CFTypeRef(k))
176+
property := C.IORegistryEntryCreateCFProperty(*me, k, C.kCFAllocatorDefault, 0)
177+
if property == nil {
178+
return 0, errors.New("Property not found: " + key)
179+
}
180+
defer C.CFRelease(property)
181+
var res int
182+
if C.CFNumberGetValue((C.CFNumberRef)(property), intType, unsafe.Pointer(&res)) != C.true {
183+
return res, fmt.Errorf("Property '%s' can't be converted or has been truncated", key)
184+
}
185+
return res, nil
186+
}
187+
188+
// io_iterator_t
189+
190+
// IsValid checks if an iterator is still valid.
191+
// Some iterators will be made invalid if changes are made to the
192+
// structure they are iterating over. This function checks the iterator
193+
// is still valid and should be called when Next returns zero.
194+
// An invalid iterator can be Reset and the iteration restarted.
195+
func (me *C.io_iterator_t) IsValid() bool {
196+
return C.IOIteratorIsValid(*me) == C.true
197+
}
198+
199+
func (me *C.io_iterator_t) Reset() {
200+
C.IOIteratorReset(*me)
201+
}
202+
203+
func (me *C.io_iterator_t) Next() (C.io_object_t, bool) {
204+
res := C.IOIteratorNext(*me)
205+
return res, res != 0
206+
}
207+
208+
func (me *C.io_iterator_t) Release() {
209+
C.IOObjectRelease(C.io_object_t(*me))
210+
}
211+
212+
// io_object_t
213+
214+
func (me *C.io_object_t) Release() {
215+
C.IOObjectRelease(*me)
216+
}
217+
218+
func (me *C.io_object_t) GetClass() string {
219+
class := make([]C.char, 1024)
220+
C.IOObjectGetClass(*me, &class[0])
221+
return C.GoString(&class[0])
222+
}

0 commit comments

Comments
 (0)