summaryrefslogtreecommitdiff
path: root/serial_port.go
diff options
context:
space:
mode:
authorChristian Pointner <equinox@helsinki.at>2016-11-17 01:50:42 (GMT)
committerChristian Pointner <equinox@helsinki.at>2016-11-17 01:50:42 (GMT)
commit1092cc471bbd73d3c0db4367106e5f706a549673 (patch)
tree8b6d2294981ad58158c1bfc258925923973b06b0 /serial_port.go
inital commitHEADmaster
Diffstat (limited to 'serial_port.go')
-rw-r--r--serial_port.go219
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
+}