aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/tarm/serial/serial_windows.go
diff options
context:
space:
mode:
authorDimitri Sokolyuk <demon@dim13.org>2017-08-27 17:22:56 +0200
committerDimitri Sokolyuk <demon@dim13.org>2017-08-27 17:22:56 +0200
commit3ee2c48a1d5599c4e6754636d1755b1e1e897301 (patch)
treeba857ebb21b0b13248192e1711af496227a2b202 /vendor/github.com/tarm/serial/serial_windows.go
parent41acedced077f9da2c6b62a3932d661566af3ca6 (diff)
Add vendor
Diffstat (limited to 'vendor/github.com/tarm/serial/serial_windows.go')
-rw-r--r--vendor/github.com/tarm/serial/serial_windows.go327
1 files changed, 327 insertions, 0 deletions
diff --git a/vendor/github.com/tarm/serial/serial_windows.go b/vendor/github.com/tarm/serial/serial_windows.go
new file mode 100644
index 0000000..a41bf4f
--- /dev/null
+++ b/vendor/github.com/tarm/serial/serial_windows.go
@@ -0,0 +1,327 @@
+// +build windows
+
+package serial
+
+import (
+ "fmt"
+ "os"
+ "sync"
+ "syscall"
+ "time"
+ "unsafe"
+)
+
+type Port struct {
+ f *os.File
+ fd syscall.Handle
+ rl sync.Mutex
+ wl sync.Mutex
+ ro *syscall.Overlapped
+ wo *syscall.Overlapped
+}
+
+type structDCB struct {
+ DCBlength, BaudRate uint32
+ flags [4]byte
+ wReserved, XonLim, XoffLim uint16
+ ByteSize, Parity, StopBits byte
+ XonChar, XoffChar, ErrorChar, EofChar, EvtChar byte
+ wReserved1 uint16
+}
+
+type structTimeouts struct {
+ ReadIntervalTimeout uint32
+ ReadTotalTimeoutMultiplier uint32
+ ReadTotalTimeoutConstant uint32
+ WriteTotalTimeoutMultiplier uint32
+ WriteTotalTimeoutConstant uint32
+}
+
+func openPort(name string, baud int, databits byte, parity Parity, stopbits StopBits, readTimeout time.Duration) (p *Port, err error) {
+ if len(name) > 0 && name[0] != '\\' {
+ name = "\\\\.\\" + name
+ }
+
+ h, err := syscall.CreateFile(syscall.StringToUTF16Ptr(name),
+ syscall.GENERIC_READ|syscall.GENERIC_WRITE,
+ 0,
+ nil,
+ syscall.OPEN_EXISTING,
+ syscall.FILE_ATTRIBUTE_NORMAL|syscall.FILE_FLAG_OVERLAPPED,
+ 0)
+ if err != nil {
+ return nil, err
+ }
+ f := os.NewFile(uintptr(h), name)
+ defer func() {
+ if err != nil {
+ f.Close()
+ }
+ }()
+
+ if err = setCommState(h, baud, databits, parity, stopbits); err != nil {
+ return nil, err
+ }
+ if err = setupComm(h, 64, 64); err != nil {
+ return nil, err
+ }
+ if err = setCommTimeouts(h, readTimeout); err != nil {
+ return nil, err
+ }
+ if err = setCommMask(h); err != nil {
+ return nil, err
+ }
+
+ ro, err := newOverlapped()
+ if err != nil {
+ return nil, err
+ }
+ wo, err := newOverlapped()
+ if err != nil {
+ return nil, err
+ }
+ port := new(Port)
+ port.f = f
+ port.fd = h
+ port.ro = ro
+ port.wo = wo
+
+ return port, nil
+}
+
+func (p *Port) Close() error {
+ return p.f.Close()
+}
+
+func (p *Port) Write(buf []byte) (int, error) {
+ p.wl.Lock()
+ defer p.wl.Unlock()
+
+ if err := resetEvent(p.wo.HEvent); err != nil {
+ return 0, err
+ }
+ var n uint32
+ err := syscall.WriteFile(p.fd, buf, &n, p.wo)
+ if err != nil && err != syscall.ERROR_IO_PENDING {
+ return int(n), err
+ }
+ return getOverlappedResult(p.fd, p.wo)
+}
+
+func (p *Port) Read(buf []byte) (int, error) {
+ if p == nil || p.f == nil {
+ return 0, fmt.Errorf("Invalid port on read %v %v", p, p.f)
+ }
+
+ p.rl.Lock()
+ defer p.rl.Unlock()
+
+ if err := resetEvent(p.ro.HEvent); err != nil {
+ return 0, err
+ }
+ var done uint32
+ err := syscall.ReadFile(p.fd, buf, &done, p.ro)
+ if err != nil && err != syscall.ERROR_IO_PENDING {
+ return int(done), err
+ }
+ return getOverlappedResult(p.fd, p.ro)
+}
+
+// Discards data written to the port but not transmitted,
+// or data received but not read
+func (p *Port) Flush() error {
+ return purgeComm(p.fd)
+}
+
+var (
+ nSetCommState,
+ nSetCommTimeouts,
+ nSetCommMask,
+ nSetupComm,
+ nGetOverlappedResult,
+ nCreateEvent,
+ nResetEvent,
+ nPurgeComm,
+ nFlushFileBuffers uintptr
+)
+
+func init() {
+ k32, err := syscall.LoadLibrary("kernel32.dll")
+ if err != nil {
+ panic("LoadLibrary " + err.Error())
+ }
+ defer syscall.FreeLibrary(k32)
+
+ nSetCommState = getProcAddr(k32, "SetCommState")
+ nSetCommTimeouts = getProcAddr(k32, "SetCommTimeouts")
+ nSetCommMask = getProcAddr(k32, "SetCommMask")
+ nSetupComm = getProcAddr(k32, "SetupComm")
+ nGetOverlappedResult = getProcAddr(k32, "GetOverlappedResult")
+ nCreateEvent = getProcAddr(k32, "CreateEventW")
+ nResetEvent = getProcAddr(k32, "ResetEvent")
+ nPurgeComm = getProcAddr(k32, "PurgeComm")
+ nFlushFileBuffers = getProcAddr(k32, "FlushFileBuffers")
+}
+
+func getProcAddr(lib syscall.Handle, name string) uintptr {
+ addr, err := syscall.GetProcAddress(lib, name)
+ if err != nil {
+ panic(name + " " + err.Error())
+ }
+ return addr
+}
+
+func setCommState(h syscall.Handle, baud int, databits byte, parity Parity, stopbits StopBits) error {
+ var params structDCB
+ params.DCBlength = uint32(unsafe.Sizeof(params))
+
+ params.flags[0] = 0x01 // fBinary
+ params.flags[0] |= 0x10 // Assert DSR
+
+ params.BaudRate = uint32(baud)
+
+ params.ByteSize = databits
+
+ switch parity {
+ case ParityNone:
+ params.Parity = 0
+ case ParityOdd:
+ params.Parity = 1
+ case ParityEven:
+ params.Parity = 2
+ case ParityMark:
+ params.Parity = 3
+ case ParitySpace:
+ params.Parity = 4
+ default:
+ return ErrBadParity
+ }
+
+ switch stopbits {
+ case Stop1:
+ params.StopBits = 0
+ case Stop1Half:
+ params.StopBits = 1
+ case Stop2:
+ params.StopBits = 2
+ default:
+ return ErrBadStopBits
+ }
+
+ r, _, err := syscall.Syscall(nSetCommState, 2, uintptr(h), uintptr(unsafe.Pointer(&params)), 0)
+ if r == 0 {
+ return err
+ }
+ return nil
+}
+
+func setCommTimeouts(h syscall.Handle, readTimeout time.Duration) error {
+ var timeouts structTimeouts
+ const MAXDWORD = 1<<32 - 1
+
+ // blocking read by default
+ var timeoutMs int64 = MAXDWORD - 1
+
+ if readTimeout > 0 {
+ // non-blocking read
+ timeoutMs = readTimeout.Nanoseconds() / 1e6
+ if timeoutMs < 1 {
+ timeoutMs = 1
+ } else if timeoutMs > MAXDWORD-1 {
+ timeoutMs = MAXDWORD - 1
+ }
+ }
+
+ /* From http://msdn.microsoft.com/en-us/library/aa363190(v=VS.85).aspx
+
+ For blocking I/O see below:
+
+ Remarks:
+
+ If an application sets ReadIntervalTimeout and
+ ReadTotalTimeoutMultiplier to MAXDWORD and sets
+ ReadTotalTimeoutConstant to a value greater than zero and
+ less than MAXDWORD, one of the following occurs when the
+ ReadFile function is called:
+
+ If there are any bytes in the input buffer, ReadFile returns
+ immediately with the bytes in the buffer.
+
+ If there are no bytes in the input buffer, ReadFile waits
+ until a byte arrives and then returns immediately.
+
+ If no bytes arrive within the time specified by
+ ReadTotalTimeoutConstant, ReadFile times out.
+ */
+
+ timeouts.ReadIntervalTimeout = MAXDWORD
+ timeouts.ReadTotalTimeoutMultiplier = MAXDWORD
+ timeouts.ReadTotalTimeoutConstant = uint32(timeoutMs)
+
+ r, _, err := syscall.Syscall(nSetCommTimeouts, 2, uintptr(h), uintptr(unsafe.Pointer(&timeouts)), 0)
+ if r == 0 {
+ return err
+ }
+ return nil
+}
+
+func setupComm(h syscall.Handle, in, out int) error {
+ r, _, err := syscall.Syscall(nSetupComm, 3, uintptr(h), uintptr(in), uintptr(out))
+ if r == 0 {
+ return err
+ }
+ return nil
+}
+
+func setCommMask(h syscall.Handle) error {
+ const EV_RXCHAR = 0x0001
+ r, _, err := syscall.Syscall(nSetCommMask, 2, uintptr(h), EV_RXCHAR, 0)
+ if r == 0 {
+ return err
+ }
+ return nil
+}
+
+func resetEvent(h syscall.Handle) error {
+ r, _, err := syscall.Syscall(nResetEvent, 1, uintptr(h), 0, 0)
+ if r == 0 {
+ return err
+ }
+ return nil
+}
+
+func purgeComm(h syscall.Handle) error {
+ const PURGE_TXABORT = 0x0001
+ const PURGE_RXABORT = 0x0002
+ const PURGE_TXCLEAR = 0x0004
+ const PURGE_RXCLEAR = 0x0008
+ r, _, err := syscall.Syscall(nPurgeComm, 2, uintptr(h),
+ PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR, 0)
+ if r == 0 {
+ return err
+ }
+ return nil
+}
+
+func newOverlapped() (*syscall.Overlapped, error) {
+ var overlapped syscall.Overlapped
+ r, _, err := syscall.Syscall6(nCreateEvent, 4, 0, 1, 0, 0, 0, 0)
+ if r == 0 {
+ return nil, err
+ }
+ overlapped.HEvent = syscall.Handle(r)
+ return &overlapped, nil
+}
+
+func getOverlappedResult(h syscall.Handle, overlapped *syscall.Overlapped) (int, error) {
+ var n int
+ r, _, err := syscall.Syscall6(nGetOverlappedResult, 4,
+ uintptr(h),
+ uintptr(unsafe.Pointer(overlapped)),
+ uintptr(unsafe.Pointer(&n)), 1, 0, 0)
+ if r == 0 {
+ return n, err
+ }
+
+ return n, nil
+}