From 32d36b7e0a8cdfcbf98be3ac6e336816f48a088a Mon Sep 17 00:00:00 2001
From: talkkonnect <suvir@tallkkonnect.com>
Date: Mon, 3 Jan 2022 09:39:56 +0700
Subject: [PATCH] gps shaping up using channels

---
 client.go      |   4 +-
 commandkeys.go |   6 +-
 gps.go         | 180 ++++++++++++++++++++++++++++++++++++++++---------
 xmlparser.go   |   4 +-
 4 files changed, 157 insertions(+), 37 deletions(-)

diff --git a/client.go b/client.go
index 8169c5e..5f2ffa2 100644
--- a/client.go
+++ b/client.go
@@ -496,6 +496,8 @@ func (b *Talkkonnect) ClientStart() {
 		}
 	}()
 
+	go screenLogging()
+
 keyPressListenerLoop:
 	for {
 		switch ev := term.PollEvent(); ev.Type {
@@ -530,7 +532,7 @@ keyPressListenerLoop:
 			case term.KeyF11:
 				b.cmdPlayback()
 			case term.KeyF12:
-				b.cmdGPSPosition()
+				go b.cmdGPSPosition()
 			case term.KeyCtrlB:
 				b.cmdLiveReload()
 			case term.KeyCtrlC:
diff --git a/commandkeys.go b/commandkeys.go
index 2f508b0..f4857d7 100644
--- a/commandkeys.go
+++ b/commandkeys.go
@@ -368,7 +368,7 @@ func (b *Talkkonnect) cmdGPSPosition() {
 	var tries int = 10
 
 	for i = 0; i < tries; i++ {
-		goodGPSRead, err := getGpsPosition(true)
+		goodGPSRead, err := getGpsPosition(3)
 
 		if err != nil {
 			log.Println("error: GPS Function Returned Error Message", err)
@@ -419,7 +419,7 @@ func (b *Talkkonnect) cmdSendEmail() {
 	var tries int = 10
 
 	for i = 0; i < tries; i++ {
-		goodGPSRead, err := getGpsPosition(false)
+		goodGPSRead, err := getGpsPosition(3)
 
 		if err != nil {
 			log.Println("error: GPS Function Returned Error Message", err)
@@ -649,7 +649,7 @@ func (b *Talkkonnect) cmdPanicSimulation() {
 			var tries int = 10
 
 			for i = 0; i < tries; i++ {
-				goodGPSRead, err := getGpsPosition(false)
+				goodGPSRead, err := getGpsPosition(3)
 
 				if err != nil {
 					log.Println("error: GPS Function Returned Error Message", err)
diff --git a/gps.go b/gps.go
index e317caa..b64077f 100644
--- a/gps.go
+++ b/gps.go
@@ -34,13 +34,17 @@ import (
 	"encoding/hex"
 	"errors"
 	"fmt"
+	"io"
 	"io/ioutil"
 	"log"
+	"net"
 	"net/http"
+	"strings"
 	"time"
 
 	"github.com/adrianmo/go-nmea"
 	"github.com/jacobsa/go-serial/serial"
+	hd44780 "github.com/talkkonnect/go-hd44780"
 )
 
 type GSVDataStruct struct {
@@ -52,6 +56,7 @@ type GSVDataStruct struct {
 type GNSSDataStruct struct {
 	DateTime   time.Time
 	Date       string
+	Variation  float64
 	Time       string
 	Validity   string
 	Lattitude  float64
@@ -63,18 +68,39 @@ type GNSSDataStruct struct {
 	SatsInView int64
 	HDOP       float64
 	Altitude   float64
+	RMCRaw     string
 	GSVData    [4]GSVDataStruct
 }
 
+// move to config structure
+var (
+	GPSReadInterval         time.Duration = 10 * time.Second
+	GPSVerbosity            int           = 3
+	TraccarTrackEnabled     bool          = true
+	TracDeviceScreenEnabled bool          = true
+	TraccarProto            string        = "osmand" // "osmand" "opengts" "t55"
+	TraccarServerURL        string        = ""
+	TraccarPortOsmAnd       int           = 5055
+	TraccarClientId         string        = ""
+	TraccarServerIP         string        = ""
+	TraccarPortT55          int           = 5005
+)
+
+//global variables for gps
+var (
+	GNSSData       GNSSDataStruct
+	GNSSDataPublic = make(chan GNSSDataStruct)
+)
+
+//local variables for gps
 var (
 	RMCSentenceValid bool
 	GGASentenceValid bool
 	GSVSentenceValid bool
 	goodGPSRead      bool
-	GNSSData         GNSSDataStruct
 )
 
-func getGpsPosition(verbose bool) (bool, error) {
+func getGpsPosition(verbosity int) (bool, error) {
 	RMCSentenceValid = false
 	GGASentenceValid = false
 	GSVSentenceValid = false
@@ -128,14 +154,14 @@ func getGpsPosition(verbose bool) (bool, error) {
 				return false, errors.New("cannot decode hex data")
 			}
 
-			log.Println("Sending: ", hex.EncodeToString(txData_))
+			log.Println("info: Sending To Serial ", hex.EncodeToString(txData_))
 
 			count, err := f.Write(txData_)
 
 			if err != nil {
 				return false, errors.New("error writing to serial port")
 			} else {
-				log.Printf("Wrote %v bytes\n", count)
+				log.Printf("info: Wrote %v Bytes To Serial\n", count)
 			}
 
 		}
@@ -153,7 +179,6 @@ func getGpsPosition(verbose bool) (bool, error) {
 
 			for scanner.Scan() {
 				s, err := nmea.Parse(scanner.Text())
-
 				if err == nil {
 
 					switch s.DataType() {
@@ -171,6 +196,8 @@ func getGpsPosition(verbose bool) (bool, error) {
 								GNSSData.Longitude = m.Longitude
 								GNSSData.Speed = m.Speed
 								GNSSData.Course = m.Course
+								GNSSData.Variation = m.Variation
+								GNSSData.RMCRaw = m.Raw
 							}
 						}
 					case nmea.TypeGGA:
@@ -203,28 +230,12 @@ func getGpsPosition(verbose bool) (bool, error) {
 					}
 				}
 			}
+
 			if RMCSentenceValid && GGASentenceValid && GSVSentenceValid {
 				goodGPSRead = true
-				log.Println("info: RMC Date                    ", GNSSData.Date)
-				log.Println("info: RMC Time                    ", GNSSData.Time)
-				log.Println("info: OS  DateTime(UTC)           ", GNSSData.DateTime)
-				log.Println("info: RMC Validity                ", GNSSData.Validity)
-				log.Println("info: RMC Latitude DMS            ", GNSSData.Longitude)
-				log.Println("info: RMC Longitude DMS           ", GNSSData.Lattitude)
-				log.Println("info: RMC Speed                   ", GNSSData.Speed)
-				log.Println("info: RMC Course                  ", GNSSData.Course)
-				log.Println("info: GGA GPS Quality Indicator   ", GNSSData.FixQuality)
-				log.Println("info: GGA No of Satellites in Use ", GNSSData.SatsInUse)
-				log.Println("info: GGA HDOP                    ", GNSSData.HDOP)
-				log.Println("info: GGA Altitude                ", GNSSData.Altitude)
-				log.Println("info: GSV No of Satellites View   ", GNSSData.SatsInView)
-
-				for i := range GNSSData.GSVData {
-					log.Println("info: GSV SVPRNNumber Satellite   ", i, " ", GNSSData.GSVData[i].PRNNumber)
-					log.Println("info: GSV SNR         Satellite   ", i, " ", GNSSData.GSVData[i].SNR)
-					log.Println("info: GSV Azimuth     Satellite   ", i, " ", GNSSData.GSVData[i].Azimuth)
-				}
-				httpSendTraccar(GNSSData)
+				log.Println("debug: GPS Good Read")
+				GNSSDataPublic <- GNSSData
+				//time.Sleep(GPSReadInterval)
 			}
 
 		} else {
@@ -235,17 +246,16 @@ func getGpsPosition(verbose bool) (bool, error) {
 	return false, errors.New("gnss not enabled")
 }
 
-func httpSendTraccar(GNSSDataTraccar GNSSDataStruct) {
+func httpSendTraccar() {
+
+	GNSSDataTraccar := <-GNSSDataPublic
 
-	TraccarServerURL := "http://"
-	TraccarPortOsmAnd := 5055
-	TraccarClientId := "suvir"
 	TraccarDateTime := GNSSDataTraccar.DateTime.Format("2006-02-01") + "%20" + GNSSDataTraccar.DateTime.Format("15:04:05")
 
 	TraccarServerFullURL := (fmt.Sprint(TraccarServerURL) + ":" + fmt.Sprint(TraccarPortOsmAnd) + "/?" + "id=" + TraccarClientId + "&" +
 		"timestamp=" + TraccarDateTime + "&" + "lat=" + fmt.Sprintf("%f", GNSSDataTraccar.Lattitude) +
 		"&" + "lon=" + fmt.Sprintf("%f", GNSSDataTraccar.Longitude) + "&" + "speed=" + fmt.Sprintf("%f", GNSSDataTraccar.Speed) + "&" + "course=" +
-		fmt.Sprintf("%f", GNSSDataTraccar.Course) + "&" + "variation=" + fmt.Sprintf("%f", GNSSDataTraccar.HDOP))
+		fmt.Sprintf("%f", GNSSDataTraccar.Course) + "&" + "variation=" + fmt.Sprintf("%f", GNSSDataTraccar.Variation))
 
 	response, err := http.Get(TraccarServerFullURL)
 
@@ -262,9 +272,9 @@ func httpSendTraccar(GNSSDataTraccar GNSSDataStruct) {
 		if response.ContentLength == 0 {
 			log.Println("info: Empty Request Response Body")
 		} else {
-			//
 			log.Println("info: Traccar Web Server Response -->\n" + "-------------------------------------------------------------\n" + string(contents) + "-------------------------------------------------------------")
 		}
+
 		log.Println("info: HTTP Response Status from Traccar:", response.StatusCode, http.StatusText(response.StatusCode))
 		if response.StatusCode >= 200 && response.StatusCode <= 299 {
 			log.Println("info: HTTP Status Code from Traccar is in the 2xx range. This is OK.")
@@ -272,3 +282,111 @@ func httpSendTraccar(GNSSDataTraccar GNSSDataStruct) {
 		}
 	}
 }
+
+func tcpSendT55Traccar2() {
+
+	GNSSDataTraccar := <-GNSSDataPublic
+
+	PGID := "$PGID" + "," + TraccarClientId + "*0F" + "\r" + "\n"
+	GPRMC := GNSSDataTraccar.RMCRaw + "\r" + "\n"
+	log.Println("info: $GPRMC to send is: " + GNSSDataTraccar.RMCRaw)
+
+	CONN, _ := net.Dial("tcp", TraccarServerIP+":"+fmt.Sprint(TraccarPortT55)) // Use port 5005 for T55. Keep-alive.
+	err := CONN.(*net.TCPConn).SetKeepAlive(true)
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+	err = CONN.(*net.TCPConn).SetKeepAlivePeriod(60 * time.Second)
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+	err = CONN.(*net.TCPConn).SetNoDelay(false)
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+	err = CONN.(*net.TCPConn).SetLinger(0)
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+
+	log.Println("info: Traccar Client:", CONN.LocalAddr().String(), "Connected to Server:", CONN.RemoteAddr().String())
+
+	fmt.Fprint(CONN, PGID) // Send ID
+	time.Sleep(1 * time.Second)
+	fmt.Fprint(CONN, GPRMC) // send $GPRMC
+	log.Println("info: Sending position message to Traccar over Protocol: " + strings.Title(strings.ToLower(TraccarProto)))
+
+	notify := make(chan error)
+
+	go func() {
+		buf := make([]byte, 1024)
+		for {
+			n, err := CONN.Read(buf)
+			if err != nil {
+				notify <- err
+				if io.EOF == err {
+					close(notify)
+					return
+				}
+			}
+
+			if n > 0 {
+				log.Printf("Unexpected Data: %s", buf[:n])
+			}
+		}
+	}()
+
+	for {
+		select {
+		case err := <-notify:
+			log.Println("info: Traccar Server Connection dropped message", err)
+
+			if err == io.EOF {
+				log.Println("Connection to Traccar Server was closed")
+				return
+			}
+		case <-time.After(time.Second * 60):
+			log.Println("Traccar Server Connection Timeout 60. Still Alive")
+		}
+	}
+}
+
+func screenLogging() {
+
+	if GPSVerbosity < 3 && Config.Global.Hardware.TargetBoard != "rpi" {
+		return
+	}
+
+	for {
+		GNSSDataTraccar := <-GNSSDataPublic
+		if GPSVerbosity >= 3 {
+			log.Printf("debug: RMC Validity (%v), GGA GPS Quality Indicator (%v) %v/%v\n", GNSSDataTraccar.Validity, GNSSDataTraccar.FixQuality, GNSSDataTraccar.SatsInUse, GNSSDataTraccar.SatsInView)
+			log.Printf("debug: RMC Date Time              %v %v\n", GNSSDataTraccar.Date, GNSSDataTraccar.Time)
+			log.Printf("debug: OS  DateTime(UTC)          %v\n", GNSSDataTraccar.DateTime)
+			log.Printf("debug: RMC Latitude,Longitude DMS %v,%v\n", GNSSDataTraccar.Lattitude, GNSSDataTraccar.Longitude)
+			log.Printf("debug: RMC Speed, Course          %v,%v\n", GNSSDataTraccar.Speed, GNSSDataTraccar.Course)
+			log.Printf("debug: RMC Variation, GGA HDOP    %v,%v\n", GNSSDataTraccar.Variation, GNSSDataTraccar.HDOP)
+			log.Printf("debug: GGA Altitude               %v\n", GNSSDataTraccar.Altitude)
+			for i := range GNSSData.GSVData {
+				log.Printf("debug: GSV SVPRNNumber,SNR, Azimuth Sat(%v) %v,%v,%v\n", i, GNSSDataTraccar.GSVData[i].PRNNumber, GNSSDataTraccar.GSVData[i].SNR, GNSSDataTraccar.GSVData[i].Azimuth)
+			}
+		}
+		if Config.Global.Hardware.TargetBoard == "rpi" {
+			log.Println("debug: GPS on Device Screen " + "Lat: " + fmt.Sprint(GNSSDataTraccar.Lattitude) + " Long: " + fmt.Sprint(GNSSDataTraccar.Longitude))
+			if Config.Global.Hardware.LCD.Enabled {
+				LcdText = [4]string{"nil", "GPS OK " + GNSSDataTraccar.DateTime.Format("15:04:05"), "lat:" + fmt.Sprintf("%f", GNSSDataTraccar.Lattitude), "lon:" + fmt.Sprintf("%f", GNSSDataTraccar.Longitude) + " s:" + fmt.Sprintf("%.2f", GNSSDataTraccar.Speed*1.852)}
+				go hd44780.LcdDisplay(LcdText, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress)
+			}
+			if Config.Global.Hardware.OLED.Enabled {
+				oledDisplay(false, 4, 1, "GPS OK "+GNSSDataTraccar.DateTime.Format("15:04:05"))
+				oledDisplay(false, 5, 1, "lat: "+fmt.Sprintf("%f", GNSSDataTraccar.Lattitude))
+				oledDisplay(false, 6, 1, "lon: "+fmt.Sprintf("%f", GNSSDataTraccar.Longitude))
+				oledDisplay(false, 7, 1, "sp: "+fmt.Sprintf("%.2f", (GNSSDataTraccar.Speed*1.852)))
+			}
+		}
+	}
+}
diff --git a/xmlparser.go b/xmlparser.go
index 5ca0628..5450111 100644
--- a/xmlparser.go
+++ b/xmlparser.go
@@ -50,8 +50,8 @@ import (
 )
 
 const (
-	talkkonnectVersion  string = "2.07.08"
-	talkkonnectReleased string = "Jan 02 2022"
+	talkkonnectVersion  string = "2.07.09"
+	talkkonnectReleased string = "Jan 03 2022"
 )
 
 type ConfigStruct struct {