gyrogpsc/core/collectors.go

200 lines
4.5 KiB
Go

package core
import (
"fmt"
"git.timovolkmann.de/gyrogpsc/ublox"
"github.com/sirupsen/logrus"
"go.bug.st/serial"
"net"
"os"
"sync"
)
type Collector interface {
Collect()
Close()
}
type CollectorType uint8
const (
SERIAL CollectorType = iota
TCP
)
var tcpSingleton *tcpCollector
func NewCollector(typ CollectorType, proc Pusher, config *Configuration) Collector {
var coll Collector
switch typ {
case SERIAL:
coll = newSerial(proc, config)
case TCP:
if tcpSingleton == nil {
tcpSingleton = newTcp(proc, config)
} else {
tcpSingleton.SetProcessor(proc)
}
coll = tcpSingleton
default:
panic("selected collector type not implemented")
}
return coll
}
type serialCollector struct {
active bool
proc Pusher
config *Configuration
mu sync.RWMutex
}
func (s *serialCollector) isSerialCollActive() bool {
s.mu.RLock()
defer s.mu.RUnlock()
return s.active
}
func (s *serialCollector) Collect() {
s.mu.Lock()
s.active = true
s.mu.Unlock()
go func() {
logrus.Println("start serial collector")
mode := &serial.Mode{
BaudRate: 115200,
}
port, err := serial.Open(s.config.Collectors.SerialCollectorPort, mode)
if err != nil {
logrus.Fatalln("can't open serial port:", err.Error())
}
defer port.Close()
decoder := ublox.NewDecoder(port)
for s.isSerialCollActive() {
meas, err := decoder.Decode()
if err != nil {
if err.Error() == "NMEA not implemented" {
continue
}
logrus.Println("serial read err:", err)
break
}
sd, err := ConvertUbxToSensorData(meas)
if err != nil {
logrus.Println("convert err:", err, meas, sd)
continue
}
// skip irrelevant messages
if sd == nil {
continue
}
err = s.proc.Push(sd)
if err != nil {
logrus.Println("process err:", err, *sd)
continue
}
}
logrus.Println("serial collector stopped")
}()
}
func (s *serialCollector) Close() {
s.mu.Lock()
s.active = false
s.mu.Unlock()
}
func newSerial(proc Pusher, config *Configuration) *serialCollector {
return &serialCollector{
active: false,
proc: proc,
config: config,
}
}
type tcpCollector struct {
active bool
processor Pusher
//config *Configuration
}
func (t *tcpCollector) Collect() {
t.active = true
}
func (t *tcpCollector) Close() {
t.active = false
}
func (t *tcpCollector) SetProcessor(p Pusher) {
t.processor = p
}
func newTcp(proc Pusher, config *Configuration) *tcpCollector {
logrus.Println("start tcp collector")
listener, err := net.Listen("tcp", config.Collectors.TcpCollectorPort)
if err != nil {
fmt.Println("Error listening:", err)
//os.Exit(1)
}
coll := &tcpCollector{
active: false,
processor: proc,
}
go func() {
for {
// Listen for an incoming connection.
conn, err := listener.Accept()
if err != nil {
fmt.Println("Error accepting: ", err.Error())
os.Exit(1)
}
logrus.Println("...new incoming tcp connection...")
// Handle connections in a new goroutine.
go coll.jsonHandler(conn)
}
}()
return coll
}
// handles incoming tcp connections with json payload.
func (c *tcpCollector) jsonHandler(conn net.Conn) {
defer conn.Close()
// TRY reader := bufio.NewReader(conn) OR NewScanner(conn)
buf := make([]byte, 2048)
for {
// Read the incoming connection into the buffer.
n, err := conn.Read(buf)
if err != nil {
fmt.Println("TCP error - reading from connection:", n, err.Error())
break
}
//json := pretty.Pretty(buf[:n])
//fmt.Println(string(json))
//fmt.Println(string(buf[:n]))
sd, err := ConvertSensorDataPhone(buf[:n])
if err != nil {
logrus.Println(err)
continue
}
if !c.active {
//time.Sleep(50 * time.Millisecond)
continue
}
err = c.processor.Push(sd)
if err != nil {
logrus.Fatalln(err)
}
}
}