diff options
author | Christian Pointner <equinox@helsinki.at> | 2016-11-17 01:50:42 (GMT) |
---|---|---|
committer | Christian Pointner <equinox@helsinki.at> | 2016-11-17 01:50:42 (GMT) |
commit | 1092cc471bbd73d3c0db4367106e5f706a549673 (patch) | |
tree | 8b6d2294981ad58158c1bfc258925923973b06b0 /serial_port.go |
Diffstat (limited to 'serial_port.go')
-rw-r--r-- | serial_port.go | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/serial_port.go b/serial_port.go new file mode 100644 index 0000000..3431965 --- /dev/null +++ b/serial_port.go @@ -0,0 +1,219 @@ +// +// rhctl +// +// Copyright (C) 2009-2016 Christian Pointner <equinox@helsinki.at> +// +// This file is part of rhctl. +// +// rhctl is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// rhctl is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with rhctl. If not, see <http://www.gnu.org/licenses/>. +// + +package goserial + +import ( + "bufio" + "errors" + "log" + "strconv" + "syscall" + + "github.com/schleibinger/sio" +) + +type Baudrate struct { + value uint32 + code uint32 +} + +func NewBaudrate(value uint32) (b *Baudrate, err error) { + b = &Baudrate{} + err = b.FromUint(value) + return +} + +func (b Baudrate) String() string { + return strconv.FormatUint(uint64(b.value), 10) +} + +func (b Baudrate) MarshalText() (data []byte, err error) { + data = []byte(b.String()) + return +} + +func (b Baudrate) MarshalJSON() (data []byte, err error) { + data = []byte(b.String()) + return +} + +func (b Baudrate) MarshalTOML() (data []byte, err error) { + data = []byte(b.String()) + return +} + +func (b Baudrate) MarshalYAML() (data []byte, err error) { + data = []byte(b.String()) + return +} + +func (b *Baudrate) FromUint(value uint32) error { + b.value = value + switch b.value { + case 50: + b.code = syscall.B50 + case 75: + b.code = syscall.B75 + case 110: + b.code = syscall.B110 + case 134: + b.code = syscall.B134 + case 150: + b.code = syscall.B150 + case 200: + b.code = syscall.B200 + case 300: + b.code = syscall.B300 + case 600: + b.code = syscall.B600 + case 1200: + b.code = syscall.B1200 + case 1800: + b.code = syscall.B1800 + case 2400: + b.code = syscall.B2400 + case 4800: + b.code = syscall.B4800 + case 9600: + b.code = syscall.B9600 + case 19200: + b.code = syscall.B19200 + case 38400: + b.code = syscall.B38400 + case 57600: + b.code = syscall.B57600 + case 115200: + b.code = syscall.B115200 + case 230400: + b.code = syscall.B230400 + case 460800: + b.code = syscall.B460800 + case 500000: + b.code = syscall.B500000 + case 576000: + b.code = syscall.B576000 + case 921600: + b.code = syscall.B921600 + case 1000000: + b.code = syscall.B1000000 + case 1152000: + b.code = syscall.B1152000 + case 1500000: + b.code = syscall.B1500000 + case 2000000: + b.code = syscall.B2000000 + case 2500000: + b.code = syscall.B2500000 + case 3000000: + b.code = syscall.B3000000 + case 3500000: + b.code = syscall.B3500000 + case 4000000: + b.code = syscall.B4000000 + default: + return errors.New("invalid baudrate") + } + return nil +} + +func (b *Baudrate) fromString(str string) error { + vuint, err := strconv.ParseUint(str, 10, 32) + if err != nil { + return err + } + return b.FromUint(uint32(vuint)) +} + +func (b *Baudrate) UnmarshalText(data []byte) error { + return b.fromString(string(data)) +} + +func (b *Baudrate) UnmarshalJSON(data []byte) error { + return b.fromString(string(data)) +} + +func (b *Baudrate) UnmarshalTOML(data []byte) error { + return b.fromString(string(data)) +} + +func (b *Baudrate) UnmarshalYAML(data []byte) error { + return b.fromString(string(data)) +} + +type Port struct { + port *sio.Port + RX <-chan string + TX chan<- string + newline string +} + +func serialReader(c chan<- string, port *sio.Port, stop chan<- bool) { + defer func() { + port.Close() + stop <- true + }() + + scanner := bufio.NewScanner(port) + scanner.Split(bufio.ScanLines) + for scanner.Scan() { + data := scanner.Text() + if len(data) == 0 { + continue + } + c <- data + } + if err := scanner.Err(); err != nil { + log.Printf("device(%s): read error: %s", port.LocalAddr(), err) // TODO: this needs to be configurable + } else { + log.Printf("device(%s): closed", port.LocalAddr()) // TODO: this needs to be configurable + } +} + +func serialWriter(c <-chan string, port *sio.Port, newline string, stop chan<- bool) { + defer func() { + port.Close() + stop <- true + }() + + for data := range c { + port.Write([]byte(data + newline)) + } +} + +func (port *Port) Run(stop chan<- bool) (err error) { + tx := make(chan string, 10) + rx := make(chan string, 20) + go serialReader(rx, port.port, stop) + go serialWriter(tx, port.port, port.newline, stop) + + port.RX = rx + port.TX = tx + return +} + +func Open(device string, rate Baudrate, newline string) (port *Port, err error) { + port = &Port{newline: newline} + if port.port, err = sio.Open(device, rate.code); err != nil { + return + } + return +} |