Skip to content

Commit

Permalink
Allow same serial port to be used as input and output
Browse files Browse the repository at this point in the history
  • Loading branch information
wlkh committed Feb 12, 2020
1 parent 8a6d79b commit 9c65193
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 83 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ BUILD_FOLDER=build
BINARY=${BUILD_FOLDER}/nmea_ugps

# Pass variables for version number, sha id and build number
VERSION=1.1.0
VERSION=1.1.1
SHA=$(shell git rev-parse --short HEAD)
# Set fallback build num if not set by environment variable
BUILDNUM?=local
Expand Down
38 changes: 2 additions & 36 deletions in.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"fmt"
"log"
"net"
"os"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -115,18 +114,7 @@ func inputUDPLoop(listen string, msg chan externalMaster, inStatsCh chan inputSt
}
}

func inputSerialLoop(port string, baudrate int, msg chan externalMaster, inStatsCh chan inputStats) {
if baudrate == 0 {
baudrate = 112500
}

c := &serial.Config{Name: port, Baud: baudrate}
s, err := serial.OpenPort(c)
if err != nil {
fmt.Printf("Error opening serial port: %v\n", err)
os.Exit(1)
}
defer s.Close()
func inputSerialLoop(s *serial.Port, msg chan externalMaster, inStatsCh chan inputStats) {

scanner := bufio.NewReader(s)
for {
Expand All @@ -153,29 +141,7 @@ func inputSerialLoop(port string, baudrate int, msg chan externalMaster, inStats
}
}

func inputLoop(listen string, inputStatusCh chan inputStats) {
masterCh := make(chan externalMaster, 1)

// Use ":" to decide if this is UDP address or serial device
if len(strings.Split(listen, ":")) > 1 {
// Start listening on UDP
go inputUDPLoop(listen, masterCh, inputStatusCh)
} else {
baudrate := 0
// Is the baudrate specified?
parts := strings.Split(listen, "@")
if len(parts) > 1 {
b, err := strconv.Atoi(parts[1])
if err != nil {
fmt.Printf("Unable to parse baudrate: %s as numeric value\n", parts[1])
os.Exit(1)
}
baudrate = b
listen = parts[0]
}
// Start listening on serial port
go inputSerialLoop(listen, baudrate, masterCh, inputStatusCh)
}
func inputLoop(masterCh chan externalMaster, inputStatusCh chan inputStats) {

for {
select {
Expand Down
108 changes: 104 additions & 4 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@ package main
import (
"flag"
"fmt"
"io"
"log"
"net"
"os"
"strconv"
"strings"
"time"

ui "github.com/gizak/termui/v3"
"github.com/gizak/termui/v3/widgets"
"github.com/tarm/serial"
)

var (
Expand All @@ -26,21 +32,109 @@ func debugPrintf(arguments string, a ...interface{}) {
}
}

// deviceIsUDP uses ":" to decide if this is UDP address or serial device
func deviceIsUDP(device string) bool {
return len(strings.Split(listen, ":")) > 1
}

func baudAndPortFromDevice(device string) (string, int) {
baudrate := 115200
port := device
// Is the baudrate specified?
parts := strings.Split(device, "@")
if len(parts) > 1 {
b, err := strconv.Atoi(parts[1])
if err != nil {
fmt.Printf("Unable to parse baudrate: %s as numeric value\n", parts[1])
os.Exit(1)
}
baudrate = b
port = parts[0]
}
return port, baudrate
}

func main() {
fmt.Printf("Water Linked NMEA UGPS bridge (v%s %s.%s)\n", Version, BuildNum, SHA)
flag.StringVar(&listen, "i", "0.0.0.0:7777", "UDP device and port (host:port) OR serial device (COM7 /dev/ttyUSB1@4800) to listen for NMEA input. ")
flag.StringVar(&output, "o", "127.0.0.1:2947", "UDP device and port (host:port) OR serial device (COM7 /dev/ttyUSB1) to send NMEA output. ")
flag.StringVar(&output, "o", "", "UDP device and port (host:port) OR serial device (COM7 /dev/ttyUSB1) to send NMEA output. ")
flag.StringVar(&baseURL, "url", "http://192.168.2.94", "URL of Underwater GPS")
//flag.BoolVar(&verbose, "v", false, "verbose")
flag.Parse()

// Same serial port for input and output?
sameInOut := (listen == output) && !deviceIsUDP(listen)
if sameInOut {
fmt.Println("Same port for input and output", listen)
}

// Channels
inStatusCh := make(chan inputStats, 1)
go inputLoop(listen, inStatusCh)
masterCh := make(chan externalMaster, 1)
outStatusCh := make(chan outStats, 1)
if output != "" {
go outputLoop(output, outStatusCh)

// Output
var writer io.Writer = nil

// Setup input
if deviceIsUDP(listen) {
// Input from UDP
go inputUDPLoop(listen, masterCh, inStatusCh)
} else {
// Input from serial port
port, baudrate := baudAndPortFromDevice(listen)

c := &serial.Config{Name: port, Baud: baudrate}
s, err := serial.OpenPort(c)
if err != nil {
fmt.Printf("Error opening serial port: %v\n", err)
os.Exit(1)
}
defer s.Close()

go inputSerialLoop(s, masterCh, inStatusCh)
if sameInOut {
// Output is to same serial port as input
writer = s
}
}
go inputLoop(masterCh, inStatusCh)

// Setup output
if output == "" {
// Output disabled
} else if deviceIsUDP(output) {
// Output to UDP
conn, err := net.Dial("udp", output)
if err != nil {
fmt.Printf("Error connecting to UDP: %v\n", err)
os.Exit(1)
}
defer conn.Close()
writer = conn

} else if !sameInOut {
// Output to different serial port
port, baudrate := baudAndPortFromDevice(listen)

c := &serial.Config{Name: port, Baud: baudrate}
s, err := serial.OpenPort(c)
if err != nil {
fmt.Printf("Error opening serial port: %v\n", err)
os.Exit(1)
}
defer s.Close()
writer = s
}

if writer != nil {
go outputLoop(writer, outStatusCh)
}

RunUI(inStatusCh, outStatusCh)
}

func RunUI(inStatusCh chan inputStats, outStatusCh chan outStats) {
// Let the goroutines initialize before starting GUI
time.Sleep(50 * time.Millisecond)
if err := ui.Init(); err != nil {
Expand Down Expand Up @@ -71,6 +165,9 @@ func main() {
outStatus := widgets.NewParagraph()
outStatus.Title = "Output status"
outStatus.Text = "Waiting for data"
if output == "" {
outStatus.Text = "Output not enabled"
}
height = 10
outStatus.SetRect(0, y, 80, y+height)
y += height
Expand All @@ -81,6 +178,9 @@ func main() {
ui.Render(p, inpStatus, outStatus)
}

// Intial draw before any events have occured
draw()

uiEvents := ui.PollEvents()

for {
Expand Down
43 changes: 1 addition & 42 deletions out.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,9 @@ import (
"fmt"
"io"
"math"
"net"
"os"
"strconv"
"strings"
"time"

"github.com/pilebones/go-nmea"
"github.com/tarm/serial"
)

type outStats struct {
Expand All @@ -24,48 +19,12 @@ type outStats struct {

const updateSeconds = 10

func outputLoop(output string, outStatusCh chan outStats) {
func outputLoop(writer io.Writer, outStatusCh chan outStats) {
var prevLat float64
var prevLon float64

var stats outStats

var writer io.Writer

// Use ":" to decide if this is UDP address or serial device
if len(strings.Split(output, ":")) > 1 {
conn, err := net.Dial("udp", output)
if err != nil {
fmt.Printf("Error connecting to UDP: %v\n", err)
os.Exit(1)
}
defer conn.Close()
writer = conn

} else {
baudrate := 115200
port := output
// Is the baudrate specified?
parts := strings.Split(output, "@")
if len(parts) > 1 {
b, err := strconv.Atoi(parts[1])
if err != nil {
fmt.Printf("Unable to parse baudrate: %s as numeric value\n", parts[1])
os.Exit(1)
}
baudrate = b
port = parts[0]
}
c := &serial.Config{Name: port, Baud: baudrate}
s, err := serial.OpenPort(c)
if err != nil {
fmt.Printf("Error opening serial port: %v\n", err)
os.Exit(1)
}
defer s.Close()
writer = s
}

for {
time.Sleep(100 * time.Millisecond)
pos, err := getGlobalPosition()
Expand Down

0 comments on commit 9c65193

Please sign in to comment.