├── .gitattributes ├── .travis.yml ├── LICENSE ├── README.md ├── example └── example.go ├── generate.bat ├── serial.go ├── serial_bsd.go ├── serial_darwin.go ├── serial_linux.go ├── serial_openbsd.go ├── serial_posix.go ├── serial_test.go ├── serial_windows.go ├── syscall_windows.go ├── termios_bsd.go ├── termios_darwin.go ├── termios_linux.go ├── termios_mipsx.go ├── termios_openbsd.go ├── types_windows.go ├── zsyscall_windows.go └── ztypes_windows.go /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.go text 3 | *.bat text eol=crlf 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.7 5 | - 1.8 6 | - tip 7 | 8 | script: 9 | - go test -v ./... 10 | - GOOS=linux go build 11 | - GOOS=darwin go build 12 | - GOOS=freebsd go build 13 | - GOOS=windows go build 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Quoc-Viet Nguyen 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # serial [![Build Status](https://travis-ci.org/goburrow/serial.svg?branch=master)](https://travis-ci.org/goburrow/serial) [![GoDoc](https://godoc.org/github.com/goburrow/serial?status.svg)](https://godoc.org/github.com/goburrow/serial) 2 | ## Example 3 | ```go 4 | package main 5 | 6 | import ( 7 | "log" 8 | 9 | "github.com/goburrow/serial" 10 | ) 11 | 12 | func main() { 13 | port, err := serial.Open(&serial.Config{Address: "/dev/ttyUSB0"}) 14 | if err != nil { 15 | log.Fatal(err) 16 | } 17 | defer port.Close() 18 | 19 | _, err = port.Write([]byte("serial")) 20 | if err != nil { 21 | log.Fatal(err) 22 | } 23 | } 24 | ``` 25 | ## Testing 26 | 27 | ### Linux and Mac OS 28 | - `socat -d -d pty,raw,echo=0 pty,raw,echo=0` 29 | - on Mac OS, the socat command can be installed using homebrew: 30 | ````brew install socat```` 31 | 32 | ### Windows 33 | - [Null-modem emulator](http://com0com.sourceforge.net/) 34 | - [Terminal](https://sites.google.com/site/terminalbpp/) 35 | -------------------------------------------------------------------------------- /example/example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "io" 6 | "log" 7 | "os" 8 | "time" 9 | 10 | "github.com/goburrow/serial" 11 | ) 12 | 13 | var ( 14 | address string 15 | baudrate int 16 | databits int 17 | stopbits int 18 | parity string 19 | 20 | message string 21 | ) 22 | 23 | func main() { 24 | flag.StringVar(&address, "a", "/dev/ttyUSB0", "address") 25 | flag.IntVar(&baudrate, "b", 115200, "baud rate") 26 | flag.IntVar(&databits, "d", 8, "data bits") 27 | flag.IntVar(&stopbits, "s", 1, "stop bits") 28 | flag.StringVar(&parity, "p", "N", "parity (N/E/O)") 29 | flag.StringVar(&message, "m", "serial", "message") 30 | flag.Parse() 31 | 32 | config := serial.Config{ 33 | Address: address, 34 | BaudRate: baudrate, 35 | DataBits: databits, 36 | StopBits: stopbits, 37 | Parity: parity, 38 | Timeout: 30 * time.Second, 39 | } 40 | log.Printf("connecting %+v", config) 41 | port, err := serial.Open(&config) 42 | if err != nil { 43 | log.Fatal(err) 44 | } 45 | log.Println("connected") 46 | defer func() { 47 | err := port.Close() 48 | if err != nil { 49 | log.Fatal(err) 50 | } 51 | log.Println("closed") 52 | }() 53 | 54 | if _, err = port.Write([]byte(message)); err != nil { 55 | log.Fatal(err) 56 | } 57 | if _, err = io.Copy(os.Stdout, port); err != nil { 58 | log.Fatal(err) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /generate.bat: -------------------------------------------------------------------------------- 1 | go tool cgo -godefs types_windows.go | gofmt > ztypes_windows.go 2 | go generate syscall_windows.go 3 | -------------------------------------------------------------------------------- /serial.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package serial provides a cross-platform serial reader and writer. 3 | */ 4 | package serial 5 | 6 | import ( 7 | "errors" 8 | "io" 9 | "time" 10 | ) 11 | 12 | var ( 13 | // ErrTimeout is occurred when timing out. 14 | ErrTimeout = errors.New("serial: timeout") 15 | ) 16 | 17 | // Config is common configuration for serial port. 18 | type Config struct { 19 | // Device path (/dev/ttyS0) 20 | Address string 21 | // Baud rate (default 19200) 22 | BaudRate int 23 | // Data bits: 5, 6, 7 or 8 (default 8) 24 | DataBits int 25 | // Stop bits: 1 or 2 (default 1) 26 | StopBits int 27 | // Parity: N - None, E - Even, O - Odd (default E) 28 | // (The use of no parity requires 2 stop bits.) 29 | Parity string 30 | // Read (Write) timeout. 31 | Timeout time.Duration 32 | // Configuration related to RS485 33 | RS485 RS485Config 34 | } 35 | 36 | // platform independent RS485 config. Thie structure is ignored unless Enable is true. 37 | type RS485Config struct { 38 | // Enable RS485 support 39 | Enabled bool 40 | // Delay RTS prior to send 41 | DelayRtsBeforeSend time.Duration 42 | // Delay RTS after send 43 | DelayRtsAfterSend time.Duration 44 | // Set RTS high during send 45 | RtsHighDuringSend bool 46 | // Set RTS high after send 47 | RtsHighAfterSend bool 48 | // Rx during Tx 49 | RxDuringTx bool 50 | } 51 | 52 | // Port is the interface for controlling serial port. 53 | type Port interface { 54 | io.ReadWriteCloser 55 | // Connect connects to the serial port. 56 | Open(*Config) error 57 | } 58 | 59 | // Open opens a serial port. 60 | func Open(c *Config) (p Port, err error) { 61 | p = New() 62 | err = p.Open(c) 63 | return 64 | } 65 | -------------------------------------------------------------------------------- /serial_bsd.go: -------------------------------------------------------------------------------- 1 | // +build freebsd netbsd 2 | 3 | package serial 4 | 5 | import ( 6 | "fmt" 7 | "syscall" 8 | "unsafe" 9 | ) 10 | 11 | var baudRates = map[int]uint32{ 12 | 50: syscall.B50, 13 | 75: syscall.B75, 14 | 110: syscall.B110, 15 | 134: syscall.B134, 16 | 150: syscall.B150, 17 | 200: syscall.B200, 18 | 300: syscall.B300, 19 | 600: syscall.B600, 20 | 1200: syscall.B1200, 21 | 1800: syscall.B1800, 22 | 2400: syscall.B2400, 23 | 4800: syscall.B4800, 24 | 9600: syscall.B9600, 25 | 19200: syscall.B19200, 26 | 38400: syscall.B38400, 27 | 57600: syscall.B57600, 28 | 115200: syscall.B115200, 29 | 230400: syscall.B230400, 30 | 460800: syscall.B460800, 31 | } 32 | 33 | var charSizes = map[int]uint32{ 34 | 5: syscall.CS5, 35 | 6: syscall.CS6, 36 | 7: syscall.CS7, 37 | 8: syscall.CS8, 38 | } 39 | 40 | // syscallSelect is a wapper for syscall.Select that only returns error. 41 | func syscallSelect(n int, r *syscall.FdSet, w *syscall.FdSet, e *syscall.FdSet, tv *syscall.Timeval) error { 42 | return syscall.Select(n, r, w, e, tv) 43 | } 44 | 45 | // tcsetattr sets terminal file descriptor parameters. 46 | // See man tcsetattr(3). 47 | func tcsetattr(fd int, termios *syscall.Termios) (err error) { 48 | r, _, errno := syscall.Syscall(uintptr(syscall.SYS_IOCTL), 49 | uintptr(fd), uintptr(syscall.TIOCSETA), uintptr(unsafe.Pointer(termios))) 50 | if errno != 0 { 51 | err = errno 52 | return 53 | } 54 | if r != 0 { 55 | err = fmt.Errorf("tcsetattr failed %v", r) 56 | } 57 | return 58 | } 59 | 60 | // tcgetattr gets terminal file descriptor parameters. 61 | // See man tcgetattr(3). 62 | func tcgetattr(fd int, termios *syscall.Termios) (err error) { 63 | r, _, errno := syscall.Syscall(uintptr(syscall.SYS_IOCTL), 64 | uintptr(fd), uintptr(syscall.TIOCGETA), uintptr(unsafe.Pointer(termios))) 65 | if errno != 0 { 66 | err = errno 67 | return 68 | } 69 | if r != 0 { 70 | err = fmt.Errorf("tcgetattr failed %v", r) 71 | return 72 | } 73 | return 74 | } 75 | 76 | // fdget returns index and offset of fd in fds. 77 | func fdget(fd int, fds *syscall.FdSet) (index, offset int) { 78 | index = fd / (syscall.FD_SETSIZE / len(fds.X__fds_bits)) % len(fds.X__fds_bits) 79 | offset = fd % (syscall.FD_SETSIZE / len(fds.X__fds_bits)) 80 | return 81 | } 82 | 83 | // fdset implements FD_SET macro. 84 | func fdset(fd int, fds *syscall.FdSet) { 85 | idx, pos := fdget(fd, fds) 86 | fds.X__fds_bits[idx] = 1 << uint(pos) 87 | } 88 | 89 | // fdisset implements FD_ISSET macro. 90 | func fdisset(fd int, fds *syscall.FdSet) bool { 91 | idx, pos := fdget(fd, fds) 92 | return fds.X__fds_bits[idx]&(1< 0 { 95 | timeout := syscall.NsecToTimeval(p.timeout.Nanoseconds()) 96 | tv = &timeout 97 | } 98 | for { 99 | // If syscall.Select() returns EINTR (Interrupted system call), retry it 100 | if err = syscallSelect(fd+1, &rfds, nil, nil, tv); err == nil { 101 | break 102 | } 103 | if err != syscall.EINTR { 104 | err = fmt.Errorf("serial: could not select: %v", err) 105 | return 106 | } 107 | } 108 | if !fdisset(fd, &rfds) { 109 | // Timeout 110 | err = ErrTimeout 111 | return 112 | } 113 | n, err = syscall.Read(fd, b) 114 | return 115 | } 116 | 117 | // Write writes data to the serial port. 118 | func (p *port) Write(b []byte) (n int, err error) { 119 | n, err = syscall.Write(p.fd, b) 120 | return 121 | } 122 | 123 | func (p *port) setTermios(termios *syscall.Termios) (err error) { 124 | if err = tcsetattr(p.fd, termios); err != nil { 125 | err = fmt.Errorf("serial: could not set setting: %v", err) 126 | } 127 | return 128 | } 129 | 130 | // backupTermios saves current termios setting. 131 | // Make sure that device file has been opened before calling this function. 132 | func (p *port) backupTermios() { 133 | oldTermios := &syscall.Termios{} 134 | if err := tcgetattr(p.fd, oldTermios); err != nil { 135 | // Warning only. 136 | log.Printf("serial: could not get setting: %v\n", err) 137 | return 138 | } 139 | // Will be reloaded when closing. 140 | p.oldTermios = oldTermios 141 | } 142 | 143 | // restoreTermios restores backed up termios setting. 144 | // Make sure that device file has been opened before calling this function. 145 | func (p *port) restoreTermios() { 146 | if p.oldTermios == nil { 147 | return 148 | } 149 | if err := tcsetattr(p.fd, p.oldTermios); err != nil { 150 | // Warning only. 151 | log.Printf("serial: could not restore setting: %v\n", err) 152 | return 153 | } 154 | p.oldTermios = nil 155 | } 156 | 157 | // Helpers for termios 158 | 159 | func newTermios(c *Config) (termios *syscall.Termios, err error) { 160 | termios = &syscall.Termios{} 161 | flag := termios.Cflag 162 | // Baud rate 163 | if c.BaudRate == 0 { 164 | // 19200 is the required default. 165 | flag = syscall.B19200 166 | } else { 167 | var ok bool 168 | flag, ok = baudRates[c.BaudRate] 169 | if !ok { 170 | err = fmt.Errorf("serial: unsupported baud rate %v", c.BaudRate) 171 | return 172 | } 173 | } 174 | termios.Cflag |= flag 175 | // Input baud. 176 | cfSetIspeed(termios, flag) 177 | // Output baud. 178 | cfSetOspeed(termios, flag) 179 | // Character size. 180 | if c.DataBits == 0 { 181 | flag = syscall.CS8 182 | } else { 183 | var ok bool 184 | flag, ok = charSizes[c.DataBits] 185 | if !ok { 186 | err = fmt.Errorf("serial: unsupported character size %v", c.DataBits) 187 | return 188 | } 189 | } 190 | termios.Cflag |= flag 191 | // Stop bits 192 | switch c.StopBits { 193 | case 0, 1: 194 | // Default is one stop bit. 195 | // noop 196 | case 2: 197 | // CSTOPB: Set two stop bits. 198 | termios.Cflag |= syscall.CSTOPB 199 | default: 200 | err = fmt.Errorf("serial: unsupported stop bits %v", c.StopBits) 201 | return 202 | } 203 | switch c.Parity { 204 | case "N": 205 | // noop 206 | case "O": 207 | // PARODD: Parity is odd. 208 | termios.Cflag |= syscall.PARODD 209 | fallthrough 210 | case "", "E": 211 | // As mentioned in the modbus spec, the default parity mode must be Even parity 212 | // PARENB: Enable parity generation on output. 213 | termios.Cflag |= syscall.PARENB 214 | // INPCK: Enable input parity checking. 215 | termios.Iflag |= syscall.INPCK 216 | default: 217 | err = fmt.Errorf("serial: unsupported parity %v", c.Parity) 218 | return 219 | } 220 | // Control modes. 221 | // CREAD: Enable receiver. 222 | // CLOCAL: Ignore control lines. 223 | termios.Cflag |= syscall.CREAD | syscall.CLOCAL 224 | // Special characters. 225 | // VMIN: Minimum number of characters for noncanonical read. 226 | // VTIME: Time in deciseconds for noncanonical read. 227 | // Both are unused as NDELAY is we utilized when opening device. 228 | return 229 | } 230 | 231 | // enableRS485 enables RS485 functionality of driver via an ioctl if the config says so 232 | func enableRS485(fd int, config *RS485Config) error { 233 | if !config.Enabled { 234 | return nil 235 | } 236 | rs485 := rs485_ioctl_opts{ 237 | rs485Enabled, 238 | uint32(config.DelayRtsBeforeSend / time.Millisecond), 239 | uint32(config.DelayRtsAfterSend / time.Millisecond), 240 | [5]uint32{0, 0, 0, 0, 0}, 241 | } 242 | 243 | if config.RtsHighDuringSend { 244 | rs485.flags |= rs485RTSOnSend 245 | } 246 | if config.RtsHighAfterSend { 247 | rs485.flags |= rs485RTSAfterSend 248 | } 249 | if config.RxDuringTx { 250 | rs485.flags |= rs485RXDuringTX 251 | } 252 | 253 | r, _, errno := syscall.Syscall( 254 | syscall.SYS_IOCTL, 255 | uintptr(fd), 256 | uintptr(rs485Tiocs), 257 | uintptr(unsafe.Pointer(&rs485))) 258 | if errno != 0 { 259 | return os.NewSyscallError("SYS_IOCTL (RS485)", errno) 260 | } 261 | if r != 0 { 262 | return errors.New("serial: unknown error from SYS_IOCTL (RS485)") 263 | } 264 | return nil 265 | } 266 | -------------------------------------------------------------------------------- /serial_test.go: -------------------------------------------------------------------------------- 1 | package serial 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | ) 7 | 8 | const ( 9 | // socat -d -d pty,raw,echo=0 pty,raw,echo=0 10 | pty1 = "/dev/ttys009" 11 | pty2 = "/dev/ttys010" 12 | ) 13 | 14 | func TestReadWrite(t *testing.T) { 15 | checkPty(t) 16 | 17 | config1 := Config{Address: pty1} 18 | port1, err := Open(&config1) 19 | if err != nil { 20 | t.Fatal(err) 21 | } 22 | defer port1.Close() 23 | 24 | config2 := Config{ 25 | Address: pty2, 26 | BaudRate: 57600, 27 | DataBits: 7, 28 | Parity: "N", 29 | StopBits: 2, 30 | } 31 | port2, err := Open(&config2) 32 | if err != nil { 33 | t.Fatal(err) 34 | } 35 | defer port2.Close() 36 | 37 | message := "test serial" 38 | n, err := port1.Write([]byte(message)) 39 | if err != nil { 40 | t.Fatal(err) 41 | } 42 | if n != len(message) { 43 | t.Fatalf("unexpected write length %v", n) 44 | } 45 | var buf [16]byte 46 | n, err = port2.Read(buf[:]) 47 | if err != nil { 48 | t.Fatal(err) 49 | } 50 | if string(buf[:n]) != message { 51 | t.Fatalf("unexpected response %q (len: %d)", buf[:n], n) 52 | } 53 | } 54 | 55 | func checkPty(t *testing.T) { 56 | for _, p := range [...]string{pty1, pty2} { 57 | if _, err := os.Stat(p); err != nil { 58 | t.Skipf("%v does not exist", p) 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /serial_windows.go: -------------------------------------------------------------------------------- 1 | package serial 2 | 3 | import ( 4 | "fmt" 5 | "syscall" 6 | ) 7 | 8 | type port struct { 9 | handle syscall.Handle 10 | 11 | oldDCB c_DCB 12 | oldTimeouts c_COMMTIMEOUTS 13 | } 14 | 15 | // New allocates and returns a new serial port controller. 16 | func New() Port { 17 | return &port{ 18 | handle: syscall.InvalidHandle, 19 | } 20 | } 21 | 22 | // Open connects to the given serial port. 23 | func (p *port) Open(c *Config) (err error) { 24 | p.handle, err = newHandle(c) 25 | if err != nil { 26 | return 27 | } 28 | defer func() { 29 | if err != nil { 30 | syscall.CloseHandle(p.handle) 31 | p.handle = syscall.InvalidHandle 32 | } 33 | }() 34 | err = p.setSerialConfig(c) 35 | if err != nil { 36 | return 37 | } 38 | err = p.setTimeouts(c) 39 | return 40 | } 41 | 42 | func (p *port) Close() (err error) { 43 | if p.handle == syscall.InvalidHandle { 44 | return 45 | } 46 | err1 := SetCommTimeouts(p.handle, &p.oldTimeouts) 47 | err2 := SetCommState(p.handle, &p.oldDCB) 48 | err = syscall.CloseHandle(p.handle) 49 | if err == nil { 50 | if err1 == nil { 51 | err = err2 52 | } else { 53 | err = err1 54 | } 55 | } 56 | p.handle = syscall.InvalidHandle 57 | return 58 | } 59 | 60 | // Read reads from serial port. 61 | // It is blocked until data received or timeout after p.timeout. 62 | func (p *port) Read(b []byte) (n int, err error) { 63 | var done uint32 64 | if err = syscall.ReadFile(p.handle, b, &done, nil); err != nil { 65 | return 66 | } 67 | if done == 0 { 68 | err = ErrTimeout 69 | return 70 | } 71 | n = int(done) 72 | return 73 | } 74 | 75 | // Write writes data to the serial port. 76 | func (p *port) Write(b []byte) (n int, err error) { 77 | var done uint32 78 | if err = syscall.WriteFile(p.handle, b, &done, nil); err != nil { 79 | return 80 | } 81 | n = int(done) 82 | return 83 | } 84 | 85 | func (p *port) setTimeouts(c *Config) error { 86 | var timeouts c_COMMTIMEOUTS 87 | // Read and write timeout 88 | if c.Timeout > 0 { 89 | timeout := toDWORD(int(c.Timeout.Nanoseconds() / 1E6)) 90 | // wait until a byte arrived or time out 91 | timeouts.ReadIntervalTimeout = c_MAXDWORD 92 | timeouts.ReadTotalTimeoutMultiplier = c_MAXDWORD 93 | timeouts.ReadTotalTimeoutConstant = timeout 94 | timeouts.WriteTotalTimeoutConstant = timeout 95 | } 96 | err := GetCommTimeouts(p.handle, &p.oldTimeouts) 97 | if err != nil { 98 | return err 99 | } 100 | err = SetCommTimeouts(p.handle, &timeouts) 101 | if err != nil { 102 | // reset 103 | SetCommTimeouts(p.handle, &p.oldTimeouts) 104 | } 105 | return err 106 | } 107 | 108 | func (p *port) setSerialConfig(c *Config) error { 109 | var dcb c_DCB 110 | if c.BaudRate == 0 { 111 | dcb.BaudRate = 19200 112 | } else { 113 | dcb.BaudRate = toDWORD(c.BaudRate) 114 | } 115 | // Data bits 116 | if c.DataBits == 0 { 117 | dcb.ByteSize = 8 118 | } else { 119 | dcb.ByteSize = toBYTE(c.DataBits) 120 | } 121 | // Stop bits 122 | switch c.StopBits { 123 | case 0, 1: 124 | // Default is one stop bit. 125 | dcb.StopBits = c_ONESTOPBIT 126 | case 2: 127 | dcb.StopBits = c_TWOSTOPBITS 128 | default: 129 | return fmt.Errorf("serial: unsupported stop bits %v", c.StopBits) 130 | } 131 | // Parity 132 | switch c.Parity { 133 | case "", "E": 134 | // Default parity mode is Even. 135 | dcb.Parity = c_EVENPARITY 136 | dcb.Pad_cgo_0[0] |= 0x02 // fParity 137 | case "O": 138 | dcb.Parity = c_ODDPARITY 139 | dcb.Pad_cgo_0[0] |= 0x02 // fParity 140 | case "N": 141 | dcb.Parity = c_NOPARITY 142 | default: 143 | return fmt.Errorf("serial: unsupported parity %v", c.Parity) 144 | } 145 | dcb.Pad_cgo_0[0] |= 0x01 // fBinary 146 | 147 | err := GetCommState(p.handle, &p.oldDCB) 148 | if err != nil { 149 | return err 150 | } 151 | err = SetCommState(p.handle, &dcb) 152 | if err != nil { 153 | SetCommState(p.handle, &p.oldDCB) 154 | } 155 | return err 156 | } 157 | 158 | func newHandle(c *Config) (handle syscall.Handle, err error) { 159 | handle, err = syscall.CreateFile( 160 | syscall.StringToUTF16Ptr(c.Address), 161 | syscall.GENERIC_READ|syscall.GENERIC_WRITE, 162 | 0, // mode 163 | nil, // security 164 | syscall.OPEN_EXISTING, // create mode 165 | 0, // attributes 166 | 0) // templates 167 | return 168 | } 169 | -------------------------------------------------------------------------------- /syscall_windows.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | package serial 4 | 5 | // Windows api calls 6 | 7 | //go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go $GOFILE 8 | 9 | //sys GetCommState(handle syscall.Handle, dcb *c_DCB) (err error) 10 | //sys SetCommState(handle syscall.Handle, dcb *c_DCB) (err error) 11 | //sys GetCommTimeouts(handle syscall.Handle, timeouts *c_COMMTIMEOUTS) (err error) 12 | //sys SetCommTimeouts(handle syscall.Handle, timeouts *c_COMMTIMEOUTS) (err error) 13 | -------------------------------------------------------------------------------- /termios_bsd.go: -------------------------------------------------------------------------------- 1 | // +build freebsd netbsd 2 | 3 | package serial 4 | 5 | import ( 6 | "syscall" 7 | ) 8 | 9 | func cfSetIspeed(termios *syscall.Termios, speed uint32) { 10 | termios.Ispeed = speed 11 | } 12 | 13 | func cfSetOspeed(termios *syscall.Termios, speed uint32) { 14 | termios.Ospeed = speed 15 | } 16 | -------------------------------------------------------------------------------- /termios_darwin.go: -------------------------------------------------------------------------------- 1 | package serial 2 | 3 | import ( 4 | "syscall" 5 | ) 6 | 7 | func cfSetIspeed(termios *syscall.Termios, speed uint64) { 8 | termios.Ispeed = speed 9 | } 10 | 11 | func cfSetOspeed(termios *syscall.Termios, speed uint64) { 12 | termios.Ospeed = speed 13 | } 14 | -------------------------------------------------------------------------------- /termios_linux.go: -------------------------------------------------------------------------------- 1 | // +build !mips,!mipsle,!mips64,!mips64le 2 | 3 | package serial 4 | 5 | import ( 6 | "syscall" 7 | ) 8 | 9 | func cfSetIspeed(termios *syscall.Termios, speed uint32) { 10 | termios.Ispeed = speed 11 | } 12 | 13 | func cfSetOspeed(termios *syscall.Termios, speed uint32) { 14 | termios.Ospeed = speed 15 | } 16 | -------------------------------------------------------------------------------- /termios_mipsx.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | // +build mips mipsle mips64 mips64le 3 | 4 | package serial 5 | 6 | import ( 7 | "syscall" 8 | ) 9 | 10 | func cfSetIspeed(termios *syscall.Termios, speed uint32) { 11 | // MIPS has no Ispeed field in termios. 12 | } 13 | 14 | func cfSetOspeed(termios *syscall.Termios, speed uint32) { 15 | // MIPS has no Ospeed field in termios. 16 | } 17 | -------------------------------------------------------------------------------- /termios_openbsd.go: -------------------------------------------------------------------------------- 1 | package serial 2 | 3 | import ( 4 | "syscall" 5 | ) 6 | 7 | func cfSetIspeed(termios *syscall.Termios, speed uint32) { 8 | termios.Ispeed = int32(speed) 9 | } 10 | 11 | func cfSetOspeed(termios *syscall.Termios, speed uint32) { 12 | termios.Ospeed = int32(speed) 13 | } 14 | -------------------------------------------------------------------------------- /types_windows.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | package serial 4 | 5 | // #include 6 | import "C" 7 | 8 | const ( 9 | c_MAXDWORD = C.MAXDWORD 10 | c_ONESTOPBIT = C.ONESTOPBIT 11 | c_TWOSTOPBITS = C.TWOSTOPBITS 12 | c_EVENPARITY = C.EVENPARITY 13 | c_ODDPARITY = C.ODDPARITY 14 | c_NOPARITY = C.NOPARITY 15 | ) 16 | 17 | type c_COMMTIMEOUTS C.COMMTIMEOUTS 18 | 19 | type c_DCB C.DCB 20 | 21 | func toDWORD(val int) C.DWORD { 22 | return C.DWORD(val) 23 | } 24 | 25 | func toBYTE(val int) C.BYTE { 26 | return C.BYTE(val) 27 | } 28 | -------------------------------------------------------------------------------- /zsyscall_windows.go: -------------------------------------------------------------------------------- 1 | // MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT 2 | 3 | package serial 4 | 5 | import ( 6 | "syscall" 7 | "unsafe" 8 | ) 9 | 10 | var _ unsafe.Pointer 11 | 12 | var ( 13 | modkernel32 = syscall.NewLazyDLL("kernel32.dll") 14 | 15 | procGetCommState = modkernel32.NewProc("GetCommState") 16 | procSetCommState = modkernel32.NewProc("SetCommState") 17 | procGetCommTimeouts = modkernel32.NewProc("GetCommTimeouts") 18 | procSetCommTimeouts = modkernel32.NewProc("SetCommTimeouts") 19 | ) 20 | 21 | func GetCommState(handle syscall.Handle, dcb *c_DCB) (err error) { 22 | r1, _, e1 := syscall.Syscall(procGetCommState.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(dcb)), 0) 23 | if r1 == 0 { 24 | if e1 != 0 { 25 | err = error(e1) 26 | } else { 27 | err = syscall.EINVAL 28 | } 29 | } 30 | return 31 | } 32 | 33 | func SetCommState(handle syscall.Handle, dcb *c_DCB) (err error) { 34 | r1, _, e1 := syscall.Syscall(procSetCommState.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(dcb)), 0) 35 | if r1 == 0 { 36 | if e1 != 0 { 37 | err = error(e1) 38 | } else { 39 | err = syscall.EINVAL 40 | } 41 | } 42 | return 43 | } 44 | 45 | func GetCommTimeouts(handle syscall.Handle, timeouts *c_COMMTIMEOUTS) (err error) { 46 | r1, _, e1 := syscall.Syscall(procGetCommTimeouts.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(timeouts)), 0) 47 | if r1 == 0 { 48 | if e1 != 0 { 49 | err = error(e1) 50 | } else { 51 | err = syscall.EINVAL 52 | } 53 | } 54 | return 55 | } 56 | 57 | func SetCommTimeouts(handle syscall.Handle, timeouts *c_COMMTIMEOUTS) (err error) { 58 | r1, _, e1 := syscall.Syscall(procSetCommTimeouts.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(timeouts)), 0) 59 | if r1 == 0 { 60 | if e1 != 0 { 61 | err = error(e1) 62 | } else { 63 | err = syscall.EINVAL 64 | } 65 | } 66 | return 67 | } 68 | -------------------------------------------------------------------------------- /ztypes_windows.go: -------------------------------------------------------------------------------- 1 | // Created by cgo -godefs - DO NOT EDIT 2 | // cgo -godefs types_windows.go 3 | 4 | package serial 5 | 6 | const ( 7 | c_MAXDWORD = 0xffffffff 8 | c_ONESTOPBIT = 0x0 9 | c_TWOSTOPBITS = 0x2 10 | c_EVENPARITY = 0x2 11 | c_ODDPARITY = 0x1 12 | c_NOPARITY = 0x0 13 | ) 14 | 15 | type c_COMMTIMEOUTS struct { 16 | ReadIntervalTimeout uint32 17 | ReadTotalTimeoutMultiplier uint32 18 | ReadTotalTimeoutConstant uint32 19 | WriteTotalTimeoutMultiplier uint32 20 | WriteTotalTimeoutConstant uint32 21 | } 22 | 23 | type c_DCB struct { 24 | DCBlength uint32 25 | BaudRate uint32 26 | Pad_cgo_0 [4]byte 27 | WReserved uint16 28 | XonLim uint16 29 | XoffLim uint16 30 | ByteSize uint8 31 | Parity uint8 32 | StopBits uint8 33 | XonChar int8 34 | XoffChar int8 35 | ErrorChar int8 36 | EofChar int8 37 | EvtChar int8 38 | WReserved1 uint16 39 | } 40 | 41 | func toDWORD(val int) uint32 { 42 | return uint32(val) 43 | } 44 | 45 | func toBYTE(val int) uint8 { 46 | return uint8(val) 47 | } 48 | --------------------------------------------------------------------------------