From aa77894c35f819b19ed68501856381166336bbe6 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Sat, 29 Oct 2016 23:42:44 +0200 Subject: [PATCH] Modem signals implementaions (windows) --- serial_windows.go | 78 ++++++++++++++++++++++++++++++++++++++++++++-- syscall_windows.go | 22 ++++++++++--- 2 files changed, 93 insertions(+), 7 deletions(-) diff --git a/serial_windows.go b/serial_windows.go index 9aef79d..ed04e6b 100644 --- a/serial_windows.go +++ b/serial_windows.go @@ -10,6 +10,7 @@ package serial // import "go.bug.st/serial.v1" // MSDN article on Serial Communications: // http://msdn.microsoft.com/en-us/library/ff802693.aspx +// (alternative link) https://msdn.microsoft.com/en-us/library/ms810467.aspx // Arduino Playground article on serial communication with Windows API: // http://playground.arduino.cc/Interfacing/CPPWindows @@ -186,6 +187,28 @@ var stopBitsMap = map[StopBits]byte{ TwoStopBits: twoStopBits, } +//sys escapeCommFunction(handle syscall.Handle, function uint32) (res bool) = EscapeCommFunction + +const ( + commFunctionSetXOFF = 1 + commFunctionSetXON = 2 + commFunctionSetRTS = 3 + commFunctionClrRTS = 4 + commFunctionSetDTR = 5 + commFunctionClrDTR = 6 + commFunctionSetBreak = 8 + commFunctionClrBreak = 9 +) + +//sys getCommModemStatus(handle syscall.Handle, bits *uint32) (res bool) = GetCommModemStatus + +const ( + msCTSOn = 0x0010 + msDSROn = 0x0020 + msRingOn = 0x0040 + msRLSDOn = 0x0080 +) + func (port *windowsPort) SetMode(mode *Mode) error { params := dcb{} if getCommState(port.handle, ¶ms) != nil { @@ -212,15 +235,64 @@ func (port *windowsPort) SetMode(mode *Mode) error { } func (port *windowsPort) SetDTR(dtr bool) error { - return &PortError{} + var res bool + if dtr { + res = escapeCommFunction(port.handle, commFunctionSetDTR) + } else { + res = escapeCommFunction(port.handle, commFunctionClrDTR) + } + if !res { + return &PortError{} + } + return nil } func (port *windowsPort) SetRTS(rts bool) error { - return &PortError{} + // It seems that there is a bug in the Windows VCP driver: + // it doesn't send USB control message when the RTS bit is + // changed, so the following code not always works with + // USB-to-serial adapters. + + /* + var res bool + if rts { + res = escapeCommFunction(port.handle, commFunctionSetRTS) + } else { + res = escapeCommFunction(port.handle, commFunctionClrRTS) + } + if !res { + return &PortError{} + } + return nil + */ + + // The following seems a more reliable way to do it + + params := &dcb{} + if err := getCommState(port.handle, params); err != nil { + return &PortError{causedBy: err} + } + params.Flags &= dcbRTSControlDisbaleMask + if rts { + params.Flags |= dcbRTSControlEnable + } + if err := setCommState(port.handle, params); err != nil { + return &PortError{causedBy: err} + } + return nil } func (port *windowsPort) GetModemStatusBits() (*ModemStatusBits, error) { - return nil, &PortError{} + var bits uint32 + if !getCommModemStatus(port.handle, &bits) { + return nil, &PortError{} + } + return &ModemStatusBits{ + CTS: (bits & msCTSOn) != 0, + DCD: (bits & msRLSDOn) != 0, + DSR: (bits & msDSROn) != 0, + RI: (bits & msRingOn) != 0, + }, nil } func nativeOpen(portName string, mode *Mode) (*windowsPort, error) { diff --git a/syscall_windows.go b/syscall_windows.go index 17b0f8c..dfa3f84 100644 --- a/syscall_windows.go +++ b/syscall_windows.go @@ -15,10 +15,12 @@ var ( modadvapi32 = windows.NewLazySystemDLL("advapi32.dll") modkernel32 = windows.NewLazySystemDLL("kernel32.dll") - procRegEnumValueW = modadvapi32.NewProc("RegEnumValueW") - procGetCommState = modkernel32.NewProc("GetCommState") - procSetCommState = modkernel32.NewProc("SetCommState") - procSetCommTimeouts = modkernel32.NewProc("SetCommTimeouts") + procRegEnumValueW = modadvapi32.NewProc("RegEnumValueW") + procGetCommState = modkernel32.NewProc("GetCommState") + procSetCommState = modkernel32.NewProc("SetCommState") + procSetCommTimeouts = modkernel32.NewProc("SetCommTimeouts") + procEscapeCommFunction = modkernel32.NewProc("EscapeCommFunction") + procGetCommModemStatus = modkernel32.NewProc("GetCommModemStatus") ) func regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, value *uint16, valueLen *uint32) (regerrno error) { @@ -64,3 +66,15 @@ func setCommTimeouts(handle syscall.Handle, timeouts *commTimeouts) (err error) } 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 +}