Modem signals implementaions (windows)

This commit is contained in:
Cristian Maglie
2016-10-29 23:42:44 +02:00
parent a736b8f7b9
commit aa77894c35
2 changed files with 93 additions and 7 deletions

View File

@@ -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, &params) != 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) {

View File

@@ -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
}