diff --git a/LICENSE b/LICENSE index 14e2f77..24e0e1a 100644 --- a/LICENSE +++ b/LICENSE @@ -39,7 +39,7 @@ Mozilla Public License Version 2.0 a separate file or files, that is not Covered Software. 1.8. "License" - means this document. + means this Config. 1.9. "Licensable" means having the right to grant, to the maximum extent possible, diff --git a/audio/66963c80200bdcfaab5c400c01eb8920.mp3 b/audio/66963c80200bdcfaab5c400c01eb8920.mp3 new file mode 100644 index 0000000..43bb11f Binary files /dev/null and b/audio/66963c80200bdcfaab5c400c01eb8920.mp3 differ diff --git a/autoprovision.go b/autoprovision.go index e44b474..b69c544 100644 --- a/autoprovision.go +++ b/autoprovision.go @@ -41,7 +41,7 @@ import ( ) func autoProvision() error { - if len(TkID) < 8 { + if len(Config.Global.Software.AutoProvisioning.TkID) < 8 { var err error var macaddress []string macaddress, err = getMacAddr() @@ -53,25 +53,25 @@ func autoProvision() error { if err != nil { FatalCleanUp(err.Error()) } - TkID = re.ReplaceAllString(a, "") + Config.Global.Software.AutoProvisioning.TkID = re.ReplaceAllString(a, "") } } - if string(TkID[len(TkID)-4]) != ".xml" { - TkID = TkID + ".xml" + if string(Config.Global.Software.AutoProvisioning.TkID[len(Config.Global.Software.AutoProvisioning.TkID)-4]) != ".xml" { + Config.Global.Software.AutoProvisioning.TkID = Config.Global.Software.AutoProvisioning.TkID + ".xml" } - if string(URL[len(URL)-1]) != "/" { - URL = URL + "/" + if string(Config.Global.Software.AutoProvisioning.URL[len(Config.Global.Software.AutoProvisioning.URL)-1]) != "/" { + Config.Global.Software.AutoProvisioning.URL = Config.Global.Software.AutoProvisioning.URL + "/" } - if string(SaveFilePath[len(SaveFilePath)-1]) != "/" { - SaveFilePath = SaveFilePath + "/" + if string(Config.Global.Software.AutoProvisioning.SaveFilePath[len(Config.Global.Software.AutoProvisioning.SaveFilePath)-1]) != "/" { + Config.Global.Software.AutoProvisioning.SaveFilePath = Config.Global.Software.AutoProvisioning.SaveFilePath + "/" } - fileURL := URL + TkID + fileURL := Config.Global.Software.AutoProvisioning.URL + Config.Global.Software.AutoProvisioning.TkID log.Println("info: Trying to Autoprovision with URL: ", fileURL) - err := downloadFile(SaveFilePath, SaveFilename, fileURL) + err := downloadFile(Config.Global.Software.AutoProvisioning.SaveFilePath, Config.Global.Software.AutoProvisioning.SaveFilePath, fileURL) if err != nil { return fmt.Errorf("error: DownloadFile Module Returned an Error: %q", err.Error()) } diff --git a/avrecord.go b/avrecord.go index 205ec5f..6dcc2ff 100644 --- a/avrecord.go +++ b/avrecord.go @@ -13,14 +13,13 @@ * * talkkonnect is the based on talkiepi and barnard by Daniel Chote and Tim Cooper * - * The Initial Developer of the Original Code is - * Suvir Kumar + * The Initial Developer of the Original Code is Zoran Dimitrijevic * Portions created by the Initial Developer are Copyright (C) Suvir Kumar. All Rights Reserved. * * Contributor(s): * - * Suvir Kumar * Zoran Dimitrijevic + * Suvir Kumar * My Blog is at www.talkkonnect.com * The source code is hosted at github.com/talkkonnect * @@ -60,22 +59,22 @@ func AudioRecordTraffic() { log.Println("debug: Old sox instance was Killed Before Running New") } - createDirIfNotExist(AudioRecordSavePath) - createDirIfNotExist(AudioRecordArchivePath) - emptydirchk, err := dirIsEmpty(AudioRecordSavePath) + createDirIfNotExist(Config.Global.Hardware.AudioRecordFunction.RecordSavePath) + createDirIfNotExist(Config.Global.Hardware.AudioRecordFunction.RecordArchivePath) + emptydirchk, err := dirIsEmpty(Config.Global.Hardware.AudioRecordFunction.RecordSavePath) if err == nil && !emptydirchk { filezip := time.Now().Format("20060102150405") + ".zip" - go zipit(AudioRecordSavePath+"/", AudioRecordArchivePath+"/"+filezip) - log.Println("debug: Archiving Old Audio Files to", AudioRecordArchivePath+"/"+filezip) + go zipit(Config.Global.Hardware.AudioRecordFunction.RecordSavePath+"/", Config.Global.Hardware.AudioRecordFunction.RecordArchivePath+"/"+filezip) + log.Println("debug: Archiving Old Audio Files to", Config.Global.Hardware.AudioRecordFunction.RecordArchivePath+"/"+filezip) time.Sleep(1 * time.Second) - cleardir(AudioRecordSavePath) + cleardir(Config.Global.Hardware.AudioRecordFunction.RecordSavePath) } else { log.Println("debug: Audio Recording Folder Is Empty. No Old Files to Archive") } time.Sleep(1 * time.Second) go audiorecordtraffic() - log.Println("debug: sox is Recording Traffic to", AudioRecordSavePath) + log.Println("debug: sox is Recording Traffic to", Config.Global.Hardware.AudioRecordFunction.RecordSavePath) } @@ -83,15 +82,15 @@ func AudioRecordTraffic() { func AudioRecordAmbient() { - createDirIfNotExist(AudioRecordSavePath) - createDirIfNotExist(AudioRecordArchivePath) - emptydirchk, err := dirIsEmpty(AudioRecordSavePath) + createDirIfNotExist(Config.Global.Hardware.AudioRecordFunction.RecordSavePath) + createDirIfNotExist(Config.Global.Hardware.AudioRecordFunction.RecordArchivePath) + emptydirchk, err := dirIsEmpty(Config.Global.Hardware.AudioRecordFunction.RecordSavePath) if err == nil && !emptydirchk { filezip := time.Now().Format("20060102150405") + ".zip" - go zipit(AudioRecordSavePath+"/", AudioRecordArchivePath+"/"+filezip) // path to end with "/" or not? - log.Println("info: Archiving Old Audio Files to", AudioRecordArchivePath+"/"+filezip) + go zipit(Config.Global.Hardware.AudioRecordFunction.RecordSavePath+"/", Config.Global.Hardware.AudioRecordFunction.RecordArchivePath+"/"+filezip) // path to end with "/" or not? + log.Println("info: Archiving Old Audio Files to", Config.Global.Hardware.AudioRecordFunction.RecordArchivePath+"/"+filezip) time.Sleep(1 * time.Second) - cleardir(AudioRecordSavePath) // Remove old files + cleardir(Config.Global.Hardware.AudioRecordFunction.RecordSavePath) // Remove old files } else { log.Println("debug: Audio Recording Folder Is Empty. No Old Files to Archive") } @@ -104,15 +103,15 @@ func AudioRecordAmbient() { func AudioRecordCombo() { - createDirIfNotExist(AudioRecordSavePath) - createDirIfNotExist(AudioRecordArchivePath) - emptydirchk, err := dirIsEmpty(AudioRecordSavePath) + createDirIfNotExist(Config.Global.Hardware.AudioRecordFunction.RecordSavePath) + createDirIfNotExist(Config.Global.Hardware.AudioRecordFunction.RecordArchivePath) + emptydirchk, err := dirIsEmpty(Config.Global.Hardware.AudioRecordFunction.RecordSavePath) if err == nil && !emptydirchk { filezip := time.Now().Format("20060102150405") + ".zip" - go zipit(AudioRecordSavePath+"/", AudioRecordArchivePath+"/"+filezip) - log.Println("info: Archiving Old Audio Files to", AudioRecordArchivePath+"/"+filezip) + go zipit(Config.Global.Hardware.AudioRecordFunction.RecordSavePath+"/", Config.Global.Hardware.AudioRecordFunction.RecordArchivePath+"/"+filezip) + log.Println("info: Archiving Old Audio Files to", Config.Global.Hardware.AudioRecordFunction.RecordArchivePath+"/"+filezip) time.Sleep(1 * time.Second) - cleardir(AudioRecordSavePath) + cleardir(Config.Global.Hardware.AudioRecordFunction.RecordSavePath) } else { log.Println("debug: Audio Recording Folder Is Empty. No Old Files to Archive") } @@ -131,24 +130,24 @@ func audiorecordtraffic() { log.Println("error: sox is Missing. Is the Package Installed?") } - audrecfile := time.Now().Format("20060102150405") + "." + AudioRecordFileFormat - log.Println("info: sox is Recording Traffic to", AudioRecordSavePath+"/"+audrecfile) - log.Println("info: Audio Recording Mode:", AudioRecordMode) + audrecfile := time.Now().Format("20060102150405") + "." + Config.Global.Hardware.AudioRecordFunction.RecordFileFormat + log.Println("info: sox is Recording Traffic to", Config.Global.Hardware.AudioRecordFunction.RecordSavePath+"/"+audrecfile) + log.Println("info: Audio Recording Mode:", Config.Global.Hardware.AudioRecordFunction.RecordMode) - if AudioRecordTimeout != 0 { // Record traffic, but stop it after timeout, if specified. "0" for no timeout. + if Config.Global.Hardware.AudioRecordFunction.RecordTimeout != 0 { // Record traffic, but stop it after timeout, if specified. "0" for no timeout. - args := []string{"-t", AudioRecordSystem, AudioRecordFromOutput, "-t", AudioRecordFileFormat, audrecfile, "trim", "0", AudioRecordChunkSize, ":", "newfile", ":", "restart"} + args := []string{"-t", Config.Global.Hardware.AudioRecordFunction.RecordSystem, Config.Global.Hardware.AudioRecordFunction.RecordFromOutput, "-t", Config.Global.Hardware.AudioRecordFunction.RecordFileFormat, audrecfile, "trim", "0", Config.Global.Hardware.AudioRecordFunction.RecordChunkSize, ":", "newfile", ":", "restart"} log.Println("debug: sox Arguments: " + fmt.Sprint(strings.Trim(fmt.Sprint(args), "[]"))) - log.Println("debug: Traffic Recording will Timeout After:", AudioRecordTimeout, "seconds") + log.Println("debug: Traffic Recording will Timeout After:", Config.Global.Hardware.AudioRecordFunction.RecordTimeout, "seconds") cmd := exec.Command("/usr/bin/sox", args...) - cmd.Dir = AudioRecordSavePath + cmd.Dir = Config.Global.Hardware.AudioRecordFunction.RecordSavePath err := cmd.Start() check(err) done := make(chan struct{}) - time.Sleep(time.Duration(AudioRecordTimeout) * time.Second) // let sox record for a time, then send kill signal + time.Sleep(time.Duration(Config.Global.Hardware.AudioRecordFunction.RecordTimeout) * time.Second) // let sox record for a time, then send kill signal go func() { err := cmd.Wait() status := cmd.ProcessState.Sys().(syscall.WaitStatus) @@ -163,27 +162,27 @@ func audiorecordtraffic() { } close(done) // Did sox close ? - log.Println("info: sox Stopped Recording Traffic to", AudioRecordSavePath) + log.Println("info: sox Stopped Recording Traffic to", Config.Global.Hardware.AudioRecordFunction.RecordSavePath) }() cmd.Process.Kill() <-done } else { // if AudioRecordTimeout is zero? Just keep recording until there is disk space on media. - audrecfile := time.Now().Format("20060102150405") + "." + AudioRecordFileFormat // mp3, wav + audrecfile := time.Now().Format("20060102150405") + "." + Config.Global.Hardware.AudioRecordFunction.RecordFileFormat // mp3, wav - args := []string{"-t", AudioRecordSystem, AudioRecordFromOutput, "-t", "mp3", audrecfile, "silence", "-l", "1", "1", "2%", "-1", "0.5", "2%", "trim", "0", AudioRecordChunkSize, ":", "newfile", ":", "restart"} + args := []string{"-t", Config.Global.Hardware.AudioRecordFunction.RecordSystem, Config.Global.Hardware.AudioRecordFunction.RecordFromOutput, "-t", "mp3", audrecfile, "silence", "-l", "1", "1", "2%", "-1", "0.5", "2%", "trim", "0", Config.Global.Hardware.AudioRecordFunction.RecordChunkSize, ":", "newfile", ":", "restart"} cmd := exec.Command("/usr/bin/sox", args...) - cmd.Dir = AudioRecordSavePath + cmd.Dir = Config.Global.Hardware.AudioRecordFunction.RecordSavePath err := cmd.Start() check(err) time.Sleep(2 * time.Second) - emptydirchk, err := dirIsEmpty(AudioRecordSavePath) // If sox didn't start recording for wrong parameters or any reason... No file. + emptydirchk, err := dirIsEmpty(Config.Global.Hardware.AudioRecordFunction.RecordSavePath) // If sox didn't start recording for wrong parameters or any reason... No file. if err == nil && !emptydirchk { - log.Println("info: sox is Recording Traffic to", AudioRecordSavePath) + log.Println("info: sox is Recording Traffic to", Config.Global.Hardware.AudioRecordFunction.RecordSavePath) log.Println("info: sox will Go On Recording, Until it Runs out of Space or is Interrupted") starttime := time.Now() @@ -238,22 +237,22 @@ func audiorecordambient() { //Need apt-get install sox libsox-fmt-mp3 (lame) - audrecfile := time.Now().Format("20060102150405") + "." + AudioRecordFileFormat // mp3, wav + audrecfile := time.Now().Format("20060102150405") + "." + Config.Global.Hardware.AudioRecordFunction.RecordFileFormat // mp3, wav - log.Println("info: sox is Recording Ambient Audio to", AudioRecordSavePath+"/"+audrecfile) - log.Println("info: sox Audio Recording will Stop After", fmt.Sprint(AudioRecordMicTimeout), "seconds") + log.Println("info: sox is Recording Ambient Audio to", Config.Global.Hardware.AudioRecordFunction.RecordSavePath+"/"+audrecfile) + log.Println("info: sox Audio Recording will Stop After", fmt.Sprint(Config.Global.Hardware.AudioRecordFunction.RecordMicTimeout), "seconds") - if AudioRecordMicTimeout != 0 { // Record ambient audio, but stop it after timeout, if specified. "0" no timeout. + if Config.Global.Hardware.AudioRecordFunction.RecordMicTimeout != 0 { // Record ambient audio, but stop it after timeout, if specified. "0" no timeout. - args := []string{"-t", AudioRecordSystem, AudioRecordFromInput, "-t", "mp3", audrecfile, "trim", "0", AudioRecordChunkSize, ":", "newfile", ":", "restart"} + args := []string{"-t", Config.Global.Hardware.AudioRecordFunction.RecordSystem, Config.Global.Hardware.AudioRecordFunction.RecordFromInput, "-t", "mp3", audrecfile, "trim", "0", Config.Global.Hardware.AudioRecordFunction.RecordChunkSize, ":", "newfile", ":", "restart"} cmd := exec.Command("/usr/bin/sox", args...) - cmd.Dir = AudioRecordSavePath // save audio recording + cmd.Dir = Config.Global.Hardware.AudioRecordFunction.RecordSavePath // save audio recording err := cmd.Start() check(err) done := make(chan struct{}) - time.Sleep(time.Duration(AudioRecordMicTimeout) * time.Second) // let sox record for a time, then signal kill + time.Sleep(time.Duration(Config.Global.Hardware.AudioRecordFunction.RecordMicTimeout) * time.Second) // let sox record for a time, then signal kill go func() { err := cmd.Wait() @@ -269,23 +268,23 @@ func audiorecordambient() { } close(done) // Did sox close ? - log.Println("info: sox Stopped Recording Traffic to", AudioRecordSavePath) + log.Println("info: sox Stopped Recording Traffic to", Config.Global.Hardware.AudioRecordFunction.RecordSavePath) }() cmd.Process.Kill() } else { - audrecfile := time.Now().Format("20060102150405") + "." + AudioRecordFileFormat // mp3, wav + audrecfile := time.Now().Format("20060102150405") + "." + Config.Global.Hardware.AudioRecordFunction.RecordFileFormat // mp3, wav - args := []string{"-t", AudioRecordSystem, AudioRecordFromInput, "-t", "mp3", audrecfile, "silence", "-l", "1", "1", `2%`, "-1", "0.5", `2%`, "trim", "0", AudioRecordChunkSize, ":", "newfile", ":", "restart"} // voice detect, trim silence with 5 min audio chunks + args := []string{"-t", Config.Global.Hardware.AudioRecordFunction.RecordSystem, Config.Global.Hardware.AudioRecordFunction.RecordFromInput, "-t", "mp3", audrecfile, "silence", "-l", "1", "1", `2%`, "-1", "0.5", `2%`, "trim", "0", Config.Global.Hardware.AudioRecordFunction.RecordChunkSize, ":", "newfile", ":", "restart"} // voice detect, trim silence with 5 min audio chunks cmd := exec.Command("/usr/bin/sox", args...) - cmd.Dir = AudioRecordSavePath // save audio recording to dir + cmd.Dir = Config.Global.Hardware.AudioRecordFunction.RecordSavePath // save audio recording to dir err := cmd.Start() check(err) - emptydirchk, err := dirIsEmpty(AudioRecordSavePath) // If sox didn't start recording for wrong parameters or any reason... No file. + emptydirchk, err := dirIsEmpty(Config.Global.Hardware.AudioRecordFunction.RecordSavePath) // If sox didn't start recording for wrong parameters or any reason... No file. if err == nil && !emptydirchk { - log.Println("info: sox is Recording Ambient Audio to", AudioRecordSavePath) + log.Println("info: sox is Recording Ambient Audio to", Config.Global.Hardware.AudioRecordFunction.RecordSavePath) log.Println("warn: sox will Go On Recording, Until it Runs out of Space or is Interrupted") starttime := time.Now() @@ -340,24 +339,24 @@ func audiorecordcombo() { //Need apt-get install sox libsox-fmt-mp3 (lame) - audrecfile := time.Now().Format("20060102150405") + "." + AudioRecordFileFormat - log.Println("info: sox is Recording Traffic to", AudioRecordSavePath+"/"+audrecfile) - log.Println("info: Audio Recording Mode:", AudioRecordMode) + audrecfile := time.Now().Format("20060102150405") + "." + Config.Global.Hardware.AudioRecordFunction.RecordFileFormat + log.Println("info: sox is Recording Traffic to", Config.Global.Hardware.AudioRecordFunction.RecordSavePath+"/"+audrecfile) + log.Println("info: Audio Recording Mode:", Config.Global.Hardware.AudioRecordFunction.RecordMode) - if AudioRecordTimeout != 0 { // Record traffic, but stop it after timeout, if specified. "0" no timeout. + if Config.Global.Hardware.AudioRecordFunction.RecordTimeout != 0 { // Record traffic, but stop it after timeout, if specified. "0" no timeout. - args := []string{"-m", "-t", AudioRecordSystem, AudioRecordFromOutput, "-t", AudioRecordSystem, AudioRecordFromInput, "-t", AudioRecordFileFormat, audrecfile, "silence", "-l", "1", "1", `2%`, "-1", "0.5", `2%`, "trim", "0", AudioRecordChunkSize, ":", "newfile", ":", "restart"} + args := []string{"-m", "-t", Config.Global.Hardware.AudioRecordFunction.RecordSystem, Config.Global.Hardware.AudioRecordFunction.RecordFromOutput, "-t", Config.Global.Hardware.AudioRecordFunction.RecordSystem, Config.Global.Hardware.AudioRecordFunction.RecordFromInput, "-t", Config.Global.Hardware.AudioRecordFunction.RecordFileFormat, audrecfile, "silence", "-l", "1", "1", `2%`, "-1", "0.5", `2%`, "trim", "0", Config.Global.Hardware.AudioRecordFunction.RecordChunkSize, ":", "newfile", ":", "restart"} log.Println("debug: sox Arguments: " + fmt.Sprint(strings.Trim(fmt.Sprint(args), "[]"))) - log.Println("info: Audio Combo Recording will Timeout After:", AudioRecordTimeout, "seconds") + log.Println("info: Audio Combo Recording will Timeout After:", Config.Global.Hardware.AudioRecordFunction.RecordTimeout, "seconds") cmd := exec.Command("/usr/bin/sox", args...) - cmd.Dir = AudioRecordSavePath + cmd.Dir = Config.Global.Hardware.AudioRecordFunction.RecordSavePath err := cmd.Start() check(err) done := make(chan struct{}) - time.Sleep(time.Duration(AudioRecordTimeout) * time.Second) // let sox record for a time, then send kill signal + time.Sleep(time.Duration(Config.Global.Hardware.AudioRecordFunction.RecordTimeout) * time.Second) // let sox record for a time, then send kill signal go func() { err := cmd.Wait() @@ -373,27 +372,27 @@ func audiorecordcombo() { } close(done) // Did sox close ? - log.Println("info: sox Stopped Recording Traffic to", AudioRecordSavePath) + log.Println("info: sox Stopped Recording Traffic to", Config.Global.Hardware.AudioRecordFunction.RecordSavePath) }() cmd.Process.Kill() <-done } else { // if AudioRecordTimeout is zero? Just keep recording until there is disk space on media. - audrecfile := time.Now().Format("20060102150405") + "." + AudioRecordFileFormat // mp3, wav + audrecfile := time.Now().Format("20060102150405") + "." + Config.Global.Hardware.AudioRecordFunction.RecordFileFormat // mp3, wav - args := []string{"-m", "-t", AudioRecordSystem, AudioRecordFromOutput, "-t", AudioRecordSystem, AudioRecordFromInput, "-t", "mp3", audrecfile, "silence", "-l", "1", "1", `2%`, "-1", "0.5", `2%`, "trim", "0", AudioRecordChunkSize, ":", "newfile", ":", "restart"} + args := []string{"-m", "-t", Config.Global.Hardware.AudioRecordFunction.RecordSystem, Config.Global.Hardware.AudioRecordFunction.RecordFromOutput, "-t", Config.Global.Hardware.AudioRecordFunction.RecordSystem, Config.Global.Hardware.AudioRecordFunction.RecordFromInput, "-t", "mp3", audrecfile, "silence", "-l", "1", "1", `2%`, "-1", "0.5", `2%`, "trim", "0", Config.Global.Hardware.AudioRecordFunction.RecordChunkSize, ":", "newfile", ":", "restart"} cmd := exec.Command("/usr/bin/sox", args...) - cmd.Dir = AudioRecordSavePath + cmd.Dir = Config.Global.Hardware.AudioRecordFunction.RecordSavePath err := cmd.Start() check(err) time.Sleep(2 * time.Second) - emptydirchk, err := dirIsEmpty(AudioRecordSavePath) // If sox didn't start recording for wrong parameters or any reason... No files. + emptydirchk, err := dirIsEmpty(Config.Global.Hardware.AudioRecordFunction.RecordSavePath) // If sox didn't start recording for wrong parameters or any reason... No files. if err == nil && !emptydirchk { - log.Println("info: sox is Recording Mixed Audio to", AudioRecordSavePath) + log.Println("info: sox is Recording Mixed Audio to", Config.Global.Hardware.AudioRecordFunction.RecordSavePath) log.Println("warn: sox will Go On Recording, Until it Runs out of Space or is Interrupted") starttime := time.Now() diff --git a/client.go b/client.go index 6b160bb..4b762a9 100644 --- a/client.go +++ b/client.go @@ -43,6 +43,7 @@ import ( "syscall" "time" + "github.com/allan-simon/go-singleinstance" "github.com/comail/colog" hd44780 "github.com/talkkonnect/go-hd44780" "github.com/talkkonnect/gumble/gumble" @@ -59,7 +60,7 @@ var ( prevParticipantCount int = 0 prevButtonPress string = "none" maxchannelid uint32 - message string + tmessage string isrepeattx bool = true m string ) @@ -76,7 +77,6 @@ type Talkkonnect struct { ConnectAttempts uint Stream *Stream ChannelName string - Daemonize bool IsTransmitting bool IsPlayStream bool GPIOEnabled bool @@ -100,21 +100,32 @@ func Init(file string, ServerIndex string) { colog.SetOutput(os.Stdout) ConfigXMLFile = file - err = readxmlconfig(ConfigXMLFile) + err = readxmlconfig(ConfigXMLFile, false) if err != nil { message := err.Error() FatalCleanUp(message) } - if Logging == "screen" { + if Config.Global.Software.Settings.SingleInstance { + lockFile, err := singleinstance.CreateLockFile("talkkonnect.lock") + if err != nil { + log.Println("error: Another Instance of talkkonnect is already running!!, Killing this Instance") + time.Sleep(5 * time.Second) + TTSEvent("quittalkkonnect") + CleanUp() + } + defer lockFile.Close() + } + + if Config.Global.Software.Settings.Logging == "screen" { colog.SetFlags(log.Ldate | log.Ltime) } - if Logging == "screenwithlineno" || Logging == "screenandfilewithlineno" { + if Config.Global.Software.Settings.Logging == "screenwithlineno" || Config.Global.Software.Settings.Logging == "screenandfilewithlineno" { colog.SetFlags(log.Ldate | log.Ltime | log.Lshortfile) } - switch Loglevel { + switch Config.Global.Software.Settings.Loglevel { case "trace": colog.SetMinLevel(colog.LTrace) log.Println("info: Loglevel Set to Trace") @@ -138,7 +149,7 @@ func Init(file string, ServerIndex string) { log.Println("info: Default Loglevel unset in XML config automatically loglevel to Info") } - if APEnabled { + if Config.Global.Software.AutoProvisioning.Enabled { log.Println("info: Contacting http Provisioning Server Pls Wait") err := autoProvision() time.Sleep(5 * time.Second) @@ -147,12 +158,12 @@ func Init(file string, ServerIndex string) { } else { log.Println("info: Loading XML Config") ConfigXMLFile = file - readxmlconfig(ConfigXMLFile) + readxmlconfig(ConfigXMLFile, false) } } - if NextServerIndex > 0 { - AccountIndex = NextServerIndex + if Config.Global.Software.Settings.NextServerIndex > 0 { + AccountIndex = Config.Global.Software.Settings.NextServerIndex } else { AccountIndex, _ = strconv.Atoi(ServerIndex) } @@ -164,31 +175,44 @@ func Init(file string, ServerIndex string) { Username: Username[AccountIndex], Ident: Ident[AccountIndex], ChannelName: Channel[AccountIndex], - Daemonize: Daemonize, } - if MQTTEnabled { + if Config.Global.Software.RemoteControl.MQTT.Enabled { log.Printf("info: Attempting to Contact MQTT Server") - log.Printf("info: MQTT Broker : %s\n", MQTTBroker) - log.Printf("info: Subscribed topic : %s\n", MQTTTopic) + log.Printf("info: MQTT Broker : %s\n", Config.Global.Software.RemoteControl.MQTT.Settings.MQTTBroker) + log.Printf("info: Subscribed topic : %s\n", Config.Global.Software.RemoteControl.MQTT.Settings.MQTTTopic) go b.mqttsubscribe() } else { log.Printf("info: MQTT Server Subscription Disabled in Config") } + MACName := "" if len(b.Username) == 0 { - buf := make([]byte, 6) - _, err := rand.Read(buf) + macaddress, err := getMacAddr() if err != nil { - FatalCleanUp("Cannot Generate Random Number Error " + err.Error()) + log.Println("error: Could Not Get Network Interface MAC Address") + } else { + for _, a := range macaddress { + tmacname := a + MACName = strings.Replace(tmacname, ":", "", -1) + } + } + if len(MACName) == 0 { + buf := make([]byte, 6) + _, err := rand.Read(buf) + if err != nil { + FatalCleanUp("Cannot Generate Random Number Error " + err.Error()) + } + buf[0] |= 2 + b.Config.Username = fmt.Sprintf("talkkonnect-%02x%02x%02x%02x%02x%02x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]) + } else { + b.Config.Username = fmt.Sprintf("talkkonnect-%v", MACName) } - - buf[0] |= 2 - b.Config.Username = fmt.Sprintf("talkkonnect-%02x%02x%02x%02x%02x%02x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]) } else { b.Config.Username = Username[AccountIndex] } + log.Printf("info: Connecting to Server %v Identified As %v With Username %v\n", Config.Accounts.Account[AccountIndex].ServerAndPort, Config.Accounts.Account[AccountIndex].Name, b.Config.Username) b.Config.Password = Password[AccountIndex] if Insecure[AccountIndex] { @@ -202,17 +226,17 @@ func Init(file string, ServerIndex string) { b.TLSConfig.Certificates = append(b.TLSConfig.Certificates, cert) } - if APIEnabled && !HTTPServRunning { + if Config.Global.Software.RemoteControl.HTTP.Enabled && !HTTPServRunning { go func() { http.HandleFunc("/", b.httpAPI) - - if err := http.ListenAndServe(":"+APIListenPort, nil); err != nil { + if err := http.ListenAndServe(":"+Config.Global.Software.RemoteControl.HTTP.ListenPort, nil); err != nil { FatalCleanUp("Problem Starting HTTP API Server " + err.Error()) } }() } b.ClientStart() + IsConnected = false sigs := make(chan os.Signal, 1) @@ -220,32 +244,32 @@ func Init(file string, ServerIndex string) { exitStatus := 0 <-sigs - b.CleanUp() + CleanUp() os.Exit(exitStatus) } func (b *Talkkonnect) ClientStart() { - f, err := os.OpenFile(LogFilenameAndPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) - log.Println("info: Trying to Open File ", LogFilenameAndPath) + f, err := os.OpenFile(Config.Global.Software.Settings.LogFilenameAndPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) + log.Println("info: Trying to Open File ", Config.Global.Software.Settings.LogFilenameAndPath) if err != nil { FatalCleanUp("Problem Opening talkkonnect.log file " + err.Error()) } - if TargetBoard == "rpi" { - if !LedStripEnabled { - LEDOffAll() + if Config.Global.Hardware.TargetBoard == "rpi" { + if !Config.Global.Hardware.LedStripEnabled { + GPIOOutAll("led/relay", "off") } } - if Logging == "screenandfile" { - log.Println("info: Logging is set to: ", Logging) + if Config.Global.Software.Settings.Logging == "screenandfile" { + log.Println("info: Logging is set to: ", Config.Global.Software.Settings.Logging) wrt := io.MultiWriter(os.Stdout, f) colog.SetFlags(log.Ldate | log.Ltime) colog.SetOutput(wrt) } - if Logging == "screenandfilewithlineno" { - log.Println("info: Logging is set to: ", Logging) + if Config.Global.Software.Settings.Logging == "screenandfilewithlineno" { + log.Println("info: Logging is set to: ", Config.Global.Software.Settings.Logging) wrt := io.MultiWriter(os.Stdout, f) colog.SetFlags(log.Ldate | log.Ltime | log.Lshortfile) colog.SetOutput(wrt) @@ -256,10 +280,10 @@ func (b *Talkkonnect) ClientStart() { log.Printf("info: [%d] Default Mumble Accounts Found in XML config\n", AccountCount) - if TargetBoard == "rpi" { + if Config.Global.Hardware.TargetBoard == "rpi" { log.Println("info: Target Board Set as RPI (gpio enabled) ") b.initGPIO() - if LedStripEnabled { + if Config.Global.Hardware.LedStripEnabled { MyLedStrip, _ = NewLedStrip() log.Printf("info: Led Strip %v %s\n", MyLedStrip.buf, MyLedStrip.display) } @@ -267,11 +291,11 @@ func (b *Talkkonnect) ClientStart() { log.Println("info: Target Board Set as PC (gpio disabled) ") } - if (TargetBoard == "rpi" && LCDBackLightTimerEnabled) && (OLEDEnabled || LCDEnabled) { + if (Config.Global.Hardware.TargetBoard == "rpi" && Config.Global.Hardware.LCD.BacklightTimerEnabled) && (OLEDEnabled || Config.Global.Hardware.LCD.Enabled) { log.Println("info: Backlight Timer Enabled by Config") BackLightTime = *BackLightTimePtr - BackLightTime = time.NewTicker(LCDBackLightTimeout * time.Second) + BackLightTime = time.NewTicker(time.Duration(Config.Global.Hardware.LCD.BackLightTimeoutSecs) * time.Second) go func() { for { @@ -279,7 +303,7 @@ func (b *Talkkonnect) ClientStart() { log.Printf("debug: LCD Backlight Ticker Timed Out After %d Seconds", LCDBackLightTimeout) LCDIsDark = true if LCDInterfaceType == "parallel" { - LEDOffFunc(BackLightLED) + GPIOOutPin("backlight", "off") } if LCDInterfaceType == "i2c" { lcd := hd44780.NewI2C4bit(LCDI2CAddress) @@ -301,7 +325,7 @@ func (b *Talkkonnect) ClientStart() { talkkonnectBanner("\u001b[44;1m") // add blue background to banner reference https://www.lihaoyi.com/post/BuildyourownCommandLinewithANSIescapecodes.html#background-colors - err = volume.Unmute(OutputDevice) + err = volume.Unmute(Config.Global.Software.Settings.OutputDevice) if err != nil { log.Println("error: Unable to Unmute ", err) @@ -309,28 +333,26 @@ func (b *Talkkonnect) ClientStart() { log.Println("debug: Speaker UnMuted Before Connect to Server") } - if TTSEnabled && TTSTalkkonnectLoaded { - localMediaPlayer(TTSTalkkonnectLoadedFilenameAndPath, TTSVolumeLevel, 0, 1) - } + TTSEvent("talkkonnectloaded") b.Connect() pstream = gumbleffmpeg.New(b.Client, gumbleffmpeg.SourceFile(""), 0) - if (HeartBeatEnabled) && (TargetBoard == "rpi") { - HeartBeat := time.NewTicker(time.Duration(PeriodmSecs) * time.Millisecond) + if (Config.Global.Hardware.HeartBeat.Enabled) && (Config.Global.Hardware.TargetBoard == "rpi") { + HeartBeat := time.NewTicker(time.Duration(Config.Global.Hardware.HeartBeat.Periodmsecs) * time.Millisecond) go func() { for range HeartBeat.C { - timer1 := time.NewTimer(time.Duration(LEDOnmSecs) * time.Millisecond) - timer2 := time.NewTimer(time.Duration(LEDOffmSecs) * time.Millisecond) + timer1 := time.NewTimer(time.Duration(Config.Global.Hardware.HeartBeat.LEDOnmsecs) * time.Millisecond) + timer2 := time.NewTimer(time.Duration(Config.Global.Hardware.HeartBeat.LEDOffmsecs) * time.Millisecond) <-timer1.C - if HeartBeatEnabled { - LEDOnFunc(HeartBeatLED) + if Config.Global.Hardware.HeartBeat.Enabled { + GPIOOutPin("heartbeat", "on") } <-timer2.C - if HeartBeatEnabled { - LEDOffFunc(HeartBeatLED) + if Config.Global.Hardware.HeartBeat.Enabled { + GPIOOutPin("heartbeat", "off") } if KillHeartBeat { HeartBeat.Stop() @@ -340,15 +362,15 @@ func (b *Talkkonnect) ClientStart() { }() } - if BeaconEnabled { - BeaconTicker := time.NewTicker(time.Duration(BeaconTimerSecs) * time.Second) + if Config.Global.Software.Beacon.Enabled { + BeaconTicker := time.NewTicker(time.Duration(Config.Global.Software.Beacon.BeaconTimerSecs) * time.Second) go func() { for range BeaconTicker.C { IsPlayStream = true - b.playIntoStream(BeaconFilenameAndPath, BVolume) + b.playIntoStream(Config.Global.Software.Beacon.BeaconFileAndPath, Config.Global.Software.Beacon.Volume) IsPlayStream = false - log.Println("info: Beacon Enabled and Timed Out Auto Played File ", BeaconFilenameAndPath, " Into Stream") + log.Println("info: Beacon Enabled and Timed Out Auto Played File ", Config.Global.Software.Beacon.BeaconFileAndPath, " Into Stream") } }() } @@ -356,7 +378,7 @@ func (b *Talkkonnect) ClientStart() { b.BackLightTimer() if LCDEnabled { - LEDOnFunc(BackLightLED) + GPIOOutPin("backlight", "on") LCDIsDark = false } @@ -365,16 +387,16 @@ func (b *Talkkonnect) ClientStart() { LCDIsDark = false } - if AudioRecordEnabled { + if Config.Global.Hardware.AudioRecordFunction.Enabled { - if AudioRecordOnStart { + if Config.Global.Hardware.AudioRecordFunction.RecordOnStart { - if AudioRecordMode != "" { + if Config.Global.Hardware.AudioRecordFunction.RecordMode != "" { - if AudioRecordMode == "traffic" { + if Config.Global.Hardware.AudioRecordFunction.RecordMode == "traffic" { log.Println("info: Incoming Traffic will be Recorded with sox") AudioRecordTraffic() - if TargetBoard == "rpi" { + if Config.Global.Hardware.TargetBoard == "rpi" { if LCDEnabled { LcdText = [4]string{"nil", "nil", "nil", "Traffic Recording ->"} // 4 LcdDisplay(LcdText, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress) @@ -384,10 +406,10 @@ func (b *Talkkonnect) ClientStart() { } } } - if AudioRecordMode == "ambient" { + if Config.Global.Hardware.AudioRecordFunction.RecordMode == "ambient" { log.Println("info: Ambient Audio from Mic will be Recorded with sox") AudioRecordAmbient() - if TargetBoard == "rpi" { + if Config.Global.Hardware.TargetBoard == "rpi" { if LCDEnabled { LcdText = [4]string{"nil", "nil", "nil", "Mic Recording ->"} // 4 LcdDisplay(LcdText, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress) @@ -397,10 +419,10 @@ func (b *Talkkonnect) ClientStart() { } } } - if AudioRecordMode == "combo" { + if Config.Global.Hardware.AudioRecordFunction.RecordMode == "combo" { log.Println("info: Both Incoming Traffic and Ambient Audio from Mic will be Recorded with sox") AudioRecordCombo() - if TargetBoard == "rpi" { + if Config.Global.Hardware.TargetBoard == "rpi" { if LCDEnabled { LcdText = [4]string{"nil", "nil", "nil", "Combo Recording ->"} // 4 LcdDisplay(LcdText, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress) @@ -416,7 +438,7 @@ func (b *Talkkonnect) ClientStart() { } } - if USBKeyboardEnabled && len(USBKeyboardPath) > 0 { + if Config.Global.Hardware.USBKeyboard.Enabled && len(Config.Global.Hardware.USBKeyboard.USBKeyboardPath) > 0 { go b.USBKeyboard() } @@ -424,17 +446,17 @@ func (b *Talkkonnect) ClientStart() { b.Client.Self.Register() log.Println("alert: Client Is Now Registered") } else { - log.Println("alert: Client Is Already Registered") + log.Println("info: Client Is Already Registered") } - if StreamOnStart { - time.Sleep(StreamOnStartAfter * time.Second) + if Config.Global.Software.Settings.StreamOnStart { + time.Sleep(Config.Global.Software.Settings.StreamOnStartAfter * time.Second) b.cmdPlayback() } - if TXOnStart { - time.Sleep(TXOnStartAfter * time.Second) + if Config.Global.Software.Settings.TXOnStart { + time.Sleep(Config.Global.Software.Settings.TXOnStartAfter * time.Second) b.cmdStartTransmitting() } @@ -473,6 +495,8 @@ keyPressListenerLoop: b.cmdPlayback() case term.KeyF12: b.cmdGPSPosition() + case term.KeyCtrlB: + b.cmdLiveReload() case term.KeyCtrlC: talkkonnectAcknowledgements("\u001b[44;1m") // add blue background to banner reference https://www.lihaoyi.com/post/BuildyourownCommandLinewithANSIescapecodes.html#background-colors b.cmdQuitTalkkonnect() @@ -482,6 +506,8 @@ keyPressListenerLoop: b.cmdSendEmail() case term.KeyCtrlF: b.cmdConnPreviousServer() + case term.KeyCtrlH: + cmdSanityCheck() case term.KeyCtrlI: // New. Audio Recording. Traffic b.cmdAudioTrafficRecord() case term.KeyCtrlJ: // New. Audio Recording. Mic @@ -503,10 +529,10 @@ keyPressListenerLoop: case term.KeyCtrlS: b.cmdScanChannels() case term.KeyCtrlT: - b.cmdThanks() - case term.KeyCtrlV: - b.cmdShowUptime() + cmdThanks() case term.KeyCtrlU: + b.cmdShowUptime() + case term.KeyCtrlV: b.cmdDisplayVersion() case term.KeyCtrlX: b.cmdDumpXMLConfig() @@ -534,7 +560,7 @@ keyPressListenerLoop: case "volumedown": b.cmdVolumeDown() case "setcomment": - if TTYKeyMap[ev.Ch].ParamName == "setcomment" { + if TTYKeyMap[ev.Ch].ParamValue == "setcomment" { log.Println("info: Set Commment ", TTYKeyMap[ev.Ch].ParamValue) b.Client.Self.SetComment(TTYKeyMap[ev.Ch].ParamValue) } @@ -545,13 +571,12 @@ keyPressListenerLoop: case "record": b.cmdAudioTrafficRecord() b.cmdAudioMicRecord() - case "setvoicetarget": - voicetarget, err := strconv.Atoi(TTYKeyMap[ev.Ch].ParamValue) + case "voicetargetset": + Paramvalue, err := strconv.Atoi(TTYKeyMap[ev.Ch].ParamValue) if err != nil { - log.Println("error: Target is Non-Numeric Value") - } else { - b.cmdSendVoiceTargets(uint32(voicetarget)) + log.Printf("error: Error Message %v, %v Is Not A Number", err, Paramvalue) } + b.cmdSendVoiceTargets(uint32(Paramvalue)) default: log.Println("Command Not Defined ", strings.ToLower(TTYKeyMap[ev.Ch].Command)) } diff --git a/clientcommands.go b/clientcommands.go index fefa3fc..8ee6741 100644 --- a/clientcommands.go +++ b/clientcommands.go @@ -51,9 +51,9 @@ func FatalCleanUp(message string) { os.Exit(1) } -func (b *Talkkonnect) CleanUp() { +func CleanUp() { - if TargetBoard == "rpi" { + if Config.Global.Hardware.TargetBoard == "rpi" { t := time.Now() if LCDEnabled { LcdText = [4]string{"talkkonnect stopped", t.Format("02-01-2006 15:04:05"), "Please Visit", "www.talkkonnect.com"} @@ -67,10 +67,10 @@ func (b *Talkkonnect) CleanUp() { oledDisplay(false, 6, 1, "Please Visit") oledDisplay(false, 7, 1, "www.talkkonnect.com") } - if !LedStripEnabled { - LEDOffAll() + if !Config.Global.Hardware.LedStripEnabled { + GPIOOutAll("led/relay", "off") } else { - MyLedStripLEDOffAll() + MyLedStripGPIOOutAll() } } @@ -111,7 +111,7 @@ func (b *Talkkonnect) ReConnect() { ConnectAttempts++ b.Connect() } else { - if TargetBoard == "rpi" { + if Config.Global.Hardware.TargetBoard == "rpi" { if LCDEnabled { LcdText = [4]string{"Failed to Connect!", "nil", "nil", "nil"} LcdDisplay(LcdText, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress) @@ -132,8 +132,8 @@ func (b *Talkkonnect) TransmitStart() { b.BackLightTimer() t := time.Now() - if SimplexWithMute { - err := volume.Mute(OutputDevice) + if Config.Global.Software.Settings.SimplexWithMute { + err := volume.Mute(Config.Global.Software.Settings.OutputDevice) if err != nil { log.Println("error: Unable to Mute ", err) } else { @@ -145,12 +145,21 @@ func (b *Talkkonnect) TransmitStart() { IsPlayStream = false NowStreaming = false time.Sleep(100 * time.Millisecond) - b.playIntoStream(StreamSoundFilenameAndPath, StreamSoundVolume) + + for _, sound := range Config.Global.Software.Sounds.Sound { + if sound.Enabled { + if sound.Event == "stream" { + if s, err := strconv.ParseFloat(sound.Volume, 32); err == nil { + b.playIntoStream(sound.File, float32(s)) + } + } + } + } } - if TargetBoard == "rpi" { - if !LedStripEnabled { - LEDOnFunc(TransmitLED) + if Config.Global.Hardware.TargetBoard == "rpi" { + if !Config.Global.Hardware.LedStripEnabled { + GPIOOutPin("transmit", "on") } else { MyLedStripTransmitLEDOn() } @@ -175,7 +184,7 @@ func (b *Talkkonnect) TransmitStart() { pstream.Stop() } - b.Stream.StartSource() + b.StartSource() } @@ -186,9 +195,9 @@ func (b *Talkkonnect) TransmitStop(withBeep bool) { b.BackLightTimer() - if TargetBoard == "rpi" { - if !LedStripEnabled { - LEDOffFunc(TransmitLED) + if Config.Global.Hardware.TargetBoard == "rpi" { + if !Config.Global.Hardware.LedStripEnabled { + GPIOOutPin("transmit", "off") } else { MyLedStripTransmitLEDOff() } @@ -202,10 +211,10 @@ func (b *Talkkonnect) TransmitStop(withBeep bool) { } b.IsTransmitting = false - b.Stream.StopSource() + b.StopSource() - if SimplexWithMute { - err := volume.Unmute(OutputDevice) + if Config.Global.Software.Settings.SimplexWithMute { + err := volume.Unmute(Config.Global.Software.Settings.OutputDevice) if err != nil { log.Println("error: Unable to Unmute ", err) } else { @@ -226,7 +235,7 @@ func (b *Talkkonnect) ChangeChannel(ChannelName string) { b.Client.Self.Move(channel) - if TargetBoard == "rpi" { + if Config.Global.Hardware.TargetBoard == "rpi" { if LCDEnabled { LcdText[1] = "Joined " + ChannelName LcdText[2] = Username[AccountIndex] @@ -255,19 +264,35 @@ func (b *Talkkonnect) ParticipantLEDUpdate(verbose bool) { var participantCount = len(b.Client.Self.Channel.Users) - if EventSoundEnabled { + var eventSound = EventSoundStruct{} + + eventSound = findEventSound("joinedchannel") + if eventSound.Enabled { if participantCount > prevParticipantCount { - localMediaPlayer(EventJoinedSoundFilenameAndPath, EventVolume, 0, 1) + if v, err := strconv.Atoi(eventSound.Volume); err == nil { + localMediaPlayer(eventSound.FileName, v, eventSound.Blocking, 0, 1) + } } + } + eventSound = findEventSound("leftchannel") + if eventSound.Enabled { if participantCount < prevParticipantCount { - localMediaPlayer(EventLeftSoundFilenameAndPath, EventVolume, 0, 1) + if v, err := strconv.Atoi(eventSound.Volume); err == nil { + localMediaPlayer(eventSound.FileName, v, eventSound.Blocking, 0, 1) + } } } - if participantCount > 1 && participantCount != prevParticipantCount { - if TTSEnabled && TTSParticipants { - b.Speak("There Are Currently "+strconv.Itoa(participantCount)+" Users in The Channel "+b.Client.Self.Channel.Name, "local", 1, 0, 1, TTSLanguage) + for _, tts := range Config.Global.Software.TTS.Sound { + if tts.Action == "participants" { + if tts.Enabled { + tempStatus := Config.Global.Software.TTSMessages.TTSTone.ToneEnabled + Config.Global.Software.TTSMessages.TTSTone.ToneEnabled = false + b.Speak("There Are Currently "+strconv.Itoa(participantCount)+" Users in The Channel "+b.Client.Self.Channel.Name, "local", 1, 0, 1, Config.Global.Software.TTSMessages.TTSLanguage) + Config.Global.Software.TTSMessages.TTSTone.ToneEnabled = tempStatus + } + } } prevParticipantCount = participantCount @@ -275,7 +300,7 @@ func (b *Talkkonnect) ParticipantLEDUpdate(verbose bool) { if verbose { log.Println("info: Current Channel ", b.Client.Self.Channel.Name, " has (", participantCount, ") participants") b.ListUsers() - if TargetBoard == "rpi" { + if Config.Global.Hardware.TargetBoard == "rpi" { if LCDEnabled { LcdText[0] = b.Address LcdText[1] = b.Client.Self.Channel.Name + " (" + strconv.Itoa(participantCount) + " Users)" @@ -293,10 +318,10 @@ func (b *Talkkonnect) ParticipantLEDUpdate(verbose bool) { } if participantCount > 1 { - if TargetBoard == "rpi" { - if !LedStripEnabled { - LEDOnFunc(ParticipantsLED) - LEDOnFunc(OnlineLED) + if Config.Global.Hardware.TargetBoard == "rpi" { + if !Config.Global.Hardware.LedStripEnabled { + GPIOOutPin("participants", "on") + GPIOOutPin("online", "on") } else { MyLedStripParticipantsLEDOn() MyLedStripOnlineLEDOn() @@ -306,16 +331,21 @@ func (b *Talkkonnect) ParticipantLEDUpdate(verbose bool) { } else { if verbose { - if TTSEnabled && TTSParticipants { - b.Speak("You are Currently Alone in The Channel "+b.Client.Self.Channel.Name, "local", 1, 0, 1, TTSLanguage) + for _, tts := range Config.Global.Software.TTS.Sound { + if tts.Action == "participants" { + if tts.Enabled { + b.Speak("You are Currently Alone in The Channel "+b.Client.Self.Channel.Name, "local", 1, 0, 1, Config.Global.Software.TTSMessages.TTSLanguage) + } + } } + log.Println("info: Channel ", b.Client.Self.Channel.Name, " has no other participants") prevParticipantCount = 0 - if TargetBoard == "rpi" { - if !LedStripEnabled { - LEDOffFunc(ParticipantsLED) + if Config.Global.Hardware.TargetBoard == "rpi" { + if !Config.Global.Hardware.LedStripEnabled { + GPIOOutPin("participants", "off") } else { MyLedStripParticipantsLEDOff() } @@ -361,7 +391,45 @@ func (b *Talkkonnect) ListChannels(verbose bool) { channelsList[counter].chanName = ch.Name channelsList[counter].chanParent = ch.Parent channelsList[counter].chanUsers = len(ch.Users) - + if verbose { + if ch.Permission() != nil { + if (*ch.Permission() & gumble.PermissionWrite) > 0 { + log.Printf("info: Channel %v Write Permissions\n", ch.Name) + } + if (*ch.Permission() & gumble.PermissionTraverse) > 0 { + log.Printf("info: Channel %v Transverse Permissions\n", ch.Name) + } + if (*ch.Permission() & gumble.PermissionEnter) > 0 { + log.Printf("info: Channel %v Enter Permissions\n", ch.Name) + } + if (*ch.Permission() & gumble.PermissionSpeak) > 0 { + log.Printf("info: Channel %v Speak Permissions\n", ch.Name) + } + if (*ch.Permission() & gumble.PermissionMuteDeafen) > 0 { + log.Printf("info: Channel %v MuteDefen Permissions\n", ch.Name) + } + if (*ch.Permission() & gumble.PermissionMove) > 0 { + log.Printf("info: Channel %v Move Permissions\n", ch.Name) + } + if (*ch.Permission() & gumble.PermissionMakeChannel) > 0 { + log.Printf("info: Channel %v Make Permissions\n", ch.Name) + } + if (*ch.Permission() & gumble.PermissionLinkChannel) > 0 { + log.Printf("info: Channel %v Link Permissions\n", ch.Name) + } + if (*ch.Permission() & gumble.PermissionWhisper) > 0 { + log.Printf("info: Channel %v Whisper Permissions\n", ch.Name) + } + if (*ch.Permission() & gumble.PermissionTextMessage) > 0 { + log.Printf("info: Channel %v Message Permissions\n", ch.Name) + } + if (*ch.Permission() & gumble.PermissionMakeTemporaryChannel) > 0 { + log.Printf("info: Channel %v Make Temp Channel Permissions\n", ch.Name) + } + } else { + log.Printf("info: Channel %v Nil Permissions\n", ch.Name) + } + } if ch.ID > maxchannelid { maxchannelid = ch.ID } @@ -392,9 +460,7 @@ func (b *Talkkonnect) ChannelUp() { prevChannelID = b.Client.Self.Channel.ID } - if TTSEnabled && TTSChannelUp { - localMediaPlayer(TTSChannelUpFilenameAndPath, EventVolume, 0, 1) - } + TTSEvent("channelup") prevButtonPress = "ChannelUp" @@ -402,17 +468,10 @@ func (b *Talkkonnect) ChannelUp() { // Set Upper Boundary if b.Client.Self.Channel.ID == maxchannelid { - log.Println("error: Can't Increment Channel Maximum Channel Reached") - if TargetBoard == "rpi" { - if LCDEnabled { - LcdText[2] = "Max Chan Reached" - LcdDisplay(LcdText, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress) - } - if OLEDEnabled { - oledDisplay(false, 1, 1, "Max Chan Reached") - } - - } + log.Println("alert: Max Channel Reached Rolling Back to Root Channel") + channel := b.Client.Channels.Find() + b.Client.Self.Move(channel) + prevChannelID = 0 return } @@ -429,7 +488,7 @@ func (b *Talkkonnect) ChannelUp() { b.Client.Self.Move(channel) //displaychannel time.Sleep(500 * time.Millisecond) - if TargetBoard == "rpi" { + if Config.Global.Hardware.TargetBoard == "rpi" { if len(b.Client.Self.Channel.Users) == 1 { LcdText[1] = "Alone in " + b.Client.Self.Channel.Name @@ -459,21 +518,17 @@ func (b *Talkkonnect) ChannelDown() { prevChannelID = b.Client.Self.Channel.ID } - if TTSEnabled && TTSChannelDown { - localMediaPlayer(TTSChannelDownFilenameAndPath, TTSVolumeLevel, 0, 1) - } + TTSEvent("channeldown") prevButtonPress = "ChannelDown" b.ListChannels(false) // Set Lower Boundary if int(b.Client.Self.Channel.ID) == 0 { - log.Println("error: Can't Decrement Channel Root Channel Reached") - channel := b.Client.Channels[uint32(AccountIndex)] - b.Client.Self.Move(channel) - //displaychannel - time.Sleep(500 * time.Millisecond) - if TargetBoard == "rpi" { + log.Println("error: Can't Decrement Channel Root Channel Reached Rolling Back to Highest Channel ID") + b.Client.Self.Move(b.Client.Channels[maxchannelid]) + prevChannelID = maxchannelid + if Config.Global.Hardware.TargetBoard == "rpi" { if len(b.Client.Self.Channel.Users) == 1 { LcdText[1] = "Alone in " + b.Client.Self.Channel.Name @@ -503,7 +558,7 @@ func (b *Talkkonnect) ChannelDown() { b.Client.Self.Move(channel) //displaychannel time.Sleep(500 * time.Millisecond) - if TargetBoard == "rpi" { + if Config.Global.Hardware.TargetBoard == "rpi" { if len(b.Client.Self.Channel.Users) == 1 { LcdText[1] = "Alone in " + b.Client.Self.Channel.Name @@ -572,7 +627,7 @@ func (b *Talkkonnect) SetComment(comment string) { b.BackLightTimer() b.Client.Self.SetComment(comment) t := time.Now() - if TargetBoard == "rpi" { + if Config.Global.Hardware.TargetBoard == "rpi" { if LCDEnabled { LcdText[2] = "Status at " + t.Format("15:04:05") time.Sleep(500 * time.Millisecond) @@ -590,12 +645,12 @@ func (b *Talkkonnect) SetComment(comment string) { func (b *Talkkonnect) BackLightTimer() { BackLightTime = *BackLightTimePtr - if TargetBoard != "rpi" || (!LCDBackLightTimerEnabled && !OLEDEnabled && !LCDEnabled) { + if Config.Global.Hardware.TargetBoard != "rpi" || (!LCDBackLightTimerEnabled && !OLEDEnabled && !LCDEnabled) { return } if LCDEnabled { - LEDOnFunc(BackLightLED) + GPIOOutPin("backlight", "on") } if OLEDEnabled { @@ -606,16 +661,16 @@ func (b *Talkkonnect) BackLightTimer() { } func (b *Talkkonnect) TxLockTimer() { - if PTxLockEnabled { - TxLockTicker := time.NewTicker(time.Duration(PTxlockTimeOutSecs) * time.Second) - log.Println("info: TX Locked for ", PTxlockTimeOutSecs, " seconds") + if Config.Global.Hardware.PanicFunction.TxLockEnabled { + TxLockTicker := time.NewTicker(time.Duration(Config.Global.Hardware.PanicFunction.TxLockTimeOutSecs) * time.Second) + log.Println("info: TX Locked for ", Config.Global.Hardware.PanicFunction.TxLockTimeOutSecs, " seconds") b.TransmitStop(false) b.TransmitStart() go func() { <-TxLockTicker.C b.TransmitStop(true) - log.Println("info: TX UnLocked After ", PTxlockTimeOutSecs, " seconds") + log.Println("info: TX UnLocked After ", Config.Global.Hardware.PanicFunction.TxLockTimeOutSecs, " seconds") }() } } @@ -649,13 +704,16 @@ func (b *Talkkonnect) pingServers() { } func (b *Talkkonnect) repeatTx() { - for i := 0; i < RepeatTXTimes; i++ { + if Config.Global.Software.Settings.RepeatTXTimes == 0 || Config.Global.Software.Settings.RepeatTXDelay == 0 { + return + } + for i := 0; i < Config.Global.Software.Settings.RepeatTXTimes; i++ { b.TransmitStart() b.IsTransmitting = true - time.Sleep(1 * time.Second) + time.Sleep(Config.Global.Software.Settings.RepeatTXDelay * time.Second) b.TransmitStop(true) b.IsTransmitting = false - time.Sleep(1 * time.Second) + time.Sleep(Config.Global.Software.Settings.RepeatTXDelay * time.Second) if i > 0 { log.Println("info: TX Cycle ", i) if isrepeattx { @@ -672,7 +730,7 @@ func (b *Talkkonnect) repeatTx() { func (b *Talkkonnect) cmdSendVoiceTargets(targetID uint32) { GenericCounter = 0 - for _, account := range Document.Accounts.Account { + for _, account := range Config.Accounts.Account { if account.Default { for _, vtvalue := range account.Voicetargets.ID { @@ -710,10 +768,10 @@ func (b *Talkkonnect) VoiceTargetUserSet(TargetID uint32, TargetUser string) { b.Client.VoiceTarget = vtarget if TargetID > 0 { log.Printf("debug: Added User %v to VT ID %v\n", TargetUser, TargetID) - LEDOnFunc(VoiceTargetLED) + GPIOOutPin("voicetarget", "on") } else { //b.VoiceTarget.Clear() - LEDOffFunc(VoiceTargetLED) + GPIOOutPin("voicetarget", "off") log.Println("debug: Cleared Voice Targets") } b.Client.Send(vtarget) @@ -748,7 +806,7 @@ func (b *Talkkonnect) VoiceTargetChannelSet(targetID uint32, targetChannelName s b.Client.VoiceTarget = vtarget b.Client.Send(vtarget) log.Printf("debug: Shouting to Root Channel %v to VT ID %v with recursive %v links %v group %v\n", vChannel.Name, targetID, recursive, links, group) - LEDOffFunc(VoiceTargetLED) + GPIOOutPin("voicetarget", "off") return } @@ -762,6 +820,6 @@ func (b *Talkkonnect) VoiceTargetChannelSet(targetID uint32, targetChannelName s b.Client.Send(vtarget) log.Printf("debug: Shouting to Child Channel %v to VT ID %v with recursive %v links %v group %v\n", vChannel.Name, targetID, recursive, links, group) if targetID > 0 { - LEDOnFunc(VoiceTargetLED) + GPIOOutPin("voicetarget", "on") } } diff --git a/commandkeys.go b/commandkeys.go index a0c586b..d4c4ae1 100644 --- a/commandkeys.go +++ b/commandkeys.go @@ -20,6 +20,7 @@ * Contributor(s): * * Suvir Kumar + * Zoran Dimitrijevic * * My Blog is at www.talkkonnect.com * The source code is hosted at github.com/talkkonnect @@ -44,10 +45,7 @@ import ( func (b *Talkkonnect) cmdDisplayMenu() { log.Println("debug: Delete Key Pressed Menu and Session Information Requested") - if TTSEnabled && TTSDisplayMenu { - localMediaPlayer(TTSDisplayMenuFilenameAndPath, TTSVolumeLevel, 0, 1) - } - + TTSEvent("displaymenu") b.talkkonnectMenu("\u001b[44;1m") // add blue background to banner reference https://www.lihaoyi.com/post/BuildyourownCommandLinewithANSIescapecodes.html#background-colors b.ParticipantLEDUpdate(true) } @@ -64,12 +62,8 @@ func (b *Talkkonnect) cmdChannelDown() { func (b *Talkkonnect) cmdMuteUnmute(subCommand string) { - log.Println("debug: F3 pressed Mute/Unmute Speaker Requested") - if TTSEnabled && TTSMuteUnMuteSpeaker { - localMediaPlayer(TTSMuteUnMuteSpeakerFilenameAndPath, TTSVolumeLevel, 0, 1) - } - - OrigMuted, err := volume.GetMuted(OutputDevice) + log.Printf("debug: F3 pressed %v Speaker Requested\n", subCommand) + OrigMuted, err := volume.GetMuted(Config.Global.Software.Settings.OutputDevice) if err != nil { log.Println("error: Unable to get current Muted/Unmuted State ", err) @@ -83,13 +77,14 @@ func (b *Talkkonnect) cmdMuteUnmute(subCommand string) { if subCommand == "toggle" { if OrigMuted { - err := volume.Unmute(OutputDevice) + err := volume.Unmute(Config.Global.Software.Settings.OutputDevice) if err != nil { log.Println("error: Unmuting Failed", err) return } + TTSEvent("unmutespeaker") log.Println("info: Output Device Unmuted") - if TargetBoard == "rpi" { + if Config.Global.Hardware.TargetBoard == "rpi" { if LCDEnabled { LcdText = [4]string{"nil", "nil", "nil", "UnMuted"} LcdDisplay(LcdText, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress) @@ -100,12 +95,13 @@ func (b *Talkkonnect) cmdMuteUnmute(subCommand string) { } return } else { - err = volume.Mute(OutputDevice) + TTSEvent("mutespeaker") + err = volume.Mute(Config.Global.Software.Settings.OutputDevice) if err != nil { log.Println("error: Muting Failed", err) } log.Println("info: Output Device Muted") - if TargetBoard == "rpi" { + if Config.Global.Hardware.TargetBoard == "rpi" { if LCDEnabled { LcdText = [4]string{"nil", "nil", "nil", "Muted"} LcdDisplay(LcdText, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress) @@ -120,13 +116,14 @@ func (b *Talkkonnect) cmdMuteUnmute(subCommand string) { //force mute if subCommand == "mute" { - err = volume.Mute(OutputDevice) + TTSEvent("mutespeaker") + err = volume.Mute(Config.Global.Software.Settings.OutputDevice) if err != nil { log.Println("error: Muting Failed ", err) return } log.Println("info: Output Device Muted") - if TargetBoard == "rpi" { + if Config.Global.Hardware.TargetBoard == "rpi" { if LCDEnabled { LcdText = [4]string{"nil", "nil", "nil", "Muted"} LcdDisplay(LcdText, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress) @@ -137,31 +134,30 @@ func (b *Talkkonnect) cmdMuteUnmute(subCommand string) { } return } - - //force unmute - if subCommand == "unmute" { - err := volume.Unmute(OutputDevice) - if err != nil { - log.Println("error: Unmute Failed ", err) - return + } + //force unmute + if subCommand == "unmute" { + err := volume.Unmute(Config.Global.Software.Settings.OutputDevice) + TTSEvent("unmutespeaker") + if err != nil { + log.Println("error: Unmute Failed ", err) + return + } + log.Println("info: Output Device Unmuted") + if Config.Global.Hardware.TargetBoard == "rpi" { + if LCDEnabled { + LcdText = [4]string{"nil", "nil", "nil", "UnMuted"} + LcdDisplay(LcdText, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress) } - log.Println("info: Output Device Unmuted") - if TargetBoard == "rpi" { - if LCDEnabled { - LcdText = [4]string{"nil", "nil", "nil", "UnMuted"} - LcdDisplay(LcdText, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress) - } - if OLEDEnabled { - oledDisplay(false, 6, 1, "Unmuted") - } + if OLEDEnabled { + oledDisplay(false, 6, 1, "Unmuted") } - return } - + return } } func (b *Talkkonnect) cmdCurrentVolume() { - OrigVolume, err := volume.GetVolume(OutputDeviceShort) + OrigVolume, err := volume.GetVolume(Config.Global.Software.Settings.OutputDevice) if err != nil { log.Printf("error: Unable to get current volume: %+v\n", err) } @@ -169,10 +165,8 @@ func (b *Talkkonnect) cmdCurrentVolume() { log.Println("debug: F4 pressed Volume Level Requested") log.Println("info: Volume Level is at", OrigVolume, "%") - if TTSEnabled && TTSCurrentVolumeLevel { - localMediaPlayer(TTSCurrentVolumeLevelFilenameAndPath, TTSVolumeLevel, 0, 1) - } - if TargetBoard == "rpi" { + TTSEvent("currentvolumelevel") + if Config.Global.Hardware.TargetBoard == "rpi" { if LCDEnabled { LcdText = [4]string{"nil", "nil", "nil", "Volume " + strconv.Itoa(OrigVolume)} LcdDisplay(LcdText, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress) @@ -185,20 +179,20 @@ func (b *Talkkonnect) cmdCurrentVolume() { } func (b *Talkkonnect) cmdVolumeUp() { - origVolume, err := volume.GetVolume(OutputDeviceShort) + origVolume, err := volume.GetVolume(Config.Global.Software.Settings.OutputDevice) if err != nil { log.Printf("warn: unable to get original volume: %+v\n", err) } if origVolume < 100 { - err := volume.IncreaseVolume(+1, OutputDeviceShort) + err := volume.IncreaseVolume(+1, Config.Global.Software.Settings.OutputDevice) if err != nil { log.Println("warn: F5 Increase Volume Failed! ", err) } log.Println("debug: F5 pressed Volume UP (+)") log.Println("info: Volume UP (+) Now At ", origVolume, "%") - if TargetBoard == "rpi" { + if Config.Global.Hardware.TargetBoard == "rpi" { if LCDEnabled { LcdText = [4]string{"nil", "nil", "nil", "Volume + " + strconv.Itoa(origVolume)} LcdDisplay(LcdText, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress) @@ -210,7 +204,7 @@ func (b *Talkkonnect) cmdVolumeUp() { } else { log.Println("debug: F5 Increase Volume") log.Println("info: Already at Maximum Possible Volume") - if TargetBoard == "rpi" { + if Config.Global.Hardware.TargetBoard == "rpi" { if LCDEnabled { LcdText = [4]string{"nil", "nil", "nil", "Max Vol"} LcdDisplay(LcdText, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress) @@ -221,27 +215,25 @@ func (b *Talkkonnect) cmdVolumeUp() { } } - if TTSEnabled && TTSDigitalVolumeUp { - localMediaPlayer(TTSDigitalVolumeUpFilenameAndPath, TTSVolumeLevel, 0, 1) - } + TTSEvent("digitalvolumeup") } func (b *Talkkonnect) cmdVolumeDown() { - origVolume, err := volume.GetVolume(OutputDeviceShort) + origVolume, err := volume.GetVolume(Config.Global.Software.Settings.OutputDevice) if err != nil { log.Printf("error: unable to get original volume: %+v\n", err) } if origVolume > 0 { origVolume-- - err := volume.IncreaseVolume(-1, OutputDeviceShort) + err := volume.IncreaseVolume(-1, Config.Global.Software.Settings.OutputDevice) if err != nil { log.Println("error: F6 Decrease Volume Failed! ", err) } log.Println("info: F6 pressed Volume Down (-)") log.Println("info: Volume Down (-) Now At ", origVolume, "%") - if TargetBoard == "rpi" { + if Config.Global.Hardware.TargetBoard == "rpi" { if LCDEnabled { LcdText = [4]string{"nil", "nil", "nil", "Volume - " + strconv.Itoa(origVolume)} LcdDisplay(LcdText, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress) @@ -254,7 +246,7 @@ func (b *Talkkonnect) cmdVolumeDown() { } else { log.Println("debug: F6 Increase Volume Already") log.Println("info: Already at Minimum Possible Volume") - if TargetBoard == "rpi" { + if Config.Global.Hardware.TargetBoard == "rpi" { if LCDEnabled { LcdText = [4]string{"nil", "nil", "nil", "Min Vol"} LcdDisplay(LcdText, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress) @@ -264,19 +256,13 @@ func (b *Talkkonnect) cmdVolumeDown() { } } } - - if TTSEnabled && TTSDigitalVolumeDown { - localMediaPlayer(TTSDigitalVolumeDownFilenameAndPath, TTSVolumeLevel, 0, 1) - } + TTSEvent("digitalvolumedown") } func (b *Talkkonnect) cmdListServerChannels() { log.Println("debug: F7 pressed Channel List Requested") - if TTSEnabled && TTSListServerChannels { - localMediaPlayer(TTSListServerChannelsFilenameAndPath, TTSVolumeLevel, 0, 1) - } - + TTSEvent("listserverchannels") b.ListChannels(true) b.ParticipantLEDUpdate(true) } @@ -285,15 +271,18 @@ func (b *Talkkonnect) cmdStartTransmitting() { log.Println("debug: F8 pressed TX Mode Requested (Start Transmitting)") log.Println("info: Start Transmitting") - if TTSEnabled && TTSStartTransmitting { - localMediaPlayer(TTSStartTransmittingFilenameAndPath, TTSVolumeLevel, 0, 1) - } + TTSEvent("starttransmitting") if IsPlayStream { IsPlayStream = false NowStreaming = false - b.playIntoStream(StreamSoundFilenameAndPath, StreamSoundVolume) + var eventSound EventSoundStruct = findEventSound("stream") + if eventSound.Enabled { + if s, err := strconv.ParseFloat(eventSound.Volume, 32); err == nil { + b.playIntoStream(eventSound.FileName, float32(s)) + } + } } if !b.IsTransmitting { @@ -308,15 +297,18 @@ func (b *Talkkonnect) cmdStopTransmitting() { log.Println("debug: F9 pressed RX Mode Request (Stop Transmitting)") log.Println("info: Stop Transmitting") - if TTSEnabled && TTSStopTransmitting { - localMediaPlayer(TTSStopTransmittingFilenameAndPath, TTSVolumeLevel, 0, 1) - } + TTSEvent("stoptransmitting") if IsPlayStream { IsPlayStream = false NowStreaming = false - b.playIntoStream(StreamSoundFilenameAndPath, StreamSoundVolume) + var eventSound EventSoundStruct = findEventSound("stream") + if eventSound.Enabled { + if s, err := strconv.ParseFloat(eventSound.Volume, 32); err == nil { + b.playIntoStream(eventSound.FileName, float32(s)) + } + } } if b.IsTransmitting { @@ -331,9 +323,7 @@ func (b *Talkkonnect) cmdListOnlineUsers() { log.Println("debug: F10 pressed Online User(s) in Current Channel Requested") log.Println("info: F10 Online User(s) in Current Channel") - if TTSEnabled && TTSListOnlineUsers { - localMediaPlayer(TTSListOnlineUsersFilenameAndPath, TTSVolumeLevel, 0, 1) - } + TTSEvent("listonlineusers") log.Println(fmt.Sprintf("info: Channel %#v Has %d Online User(s)", b.Client.Self.Channel.Name, len(b.Client.Self.Channel.Users))) b.ListUsers() @@ -346,9 +336,7 @@ func (b *Talkkonnect) cmdPlayback() { b.BackLightTimer() - if TTSEnabled && TTSPlayStream { - localMediaPlayer(TTSPlayStreamFilenameAndPath, TTSVolumeLevel, 0, 1) - } + TTSEvent("playstream") if b.IsTransmitting { log.Println("alert: talkkonnect was already transmitting will now stop transmitting and start the stream") @@ -358,21 +346,23 @@ func (b *Talkkonnect) cmdPlayback() { IsPlayStream = !IsPlayStream NowStreaming = IsPlayStream - if IsPlayStream { + if IsPlayStream && Config.Global.Software.Settings.StreamSendMessage { b.SendMessage(fmt.Sprintf("%s Streaming", b.Username), false) } - go b.playIntoStream(StreamSoundFilenameAndPath, StreamSoundVolume) - + var eventSound EventSoundStruct = findEventSound("stream") + if eventSound.Enabled { + if s, err := strconv.ParseFloat(eventSound.Volume, 32); err == nil { + go b.playIntoStream(eventSound.FileName, float32(s)) + } + } } func (b *Talkkonnect) cmdGPSPosition() { log.Println("debug: F12 pressed") log.Println("info: GPS details requested") - if TTSEnabled && TTSRequestGpsPosition { - localMediaPlayer(TTSRequestGpsPositionFilenameAndPath, TTSVolumeLevel, 0, 1) - } + TTSEvent("requestgpsposition") var i int = 0 var tries int = 10 @@ -401,11 +391,8 @@ func (b *Talkkonnect) cmdQuitTalkkonnect() { log.Println("debug: Ctrl-C Terminate Program Requested") duration := time.Since(StartTime) log.Printf("info: Talkkonnect Now Running For %v \n", secondsToHuman(int(duration.Seconds()))) - - if TTSEnabled && TTSQuitTalkkonnect { - localMediaPlayer(TTSQuitTalkkonnectFilenameAndPath, TTSVolumeLevel, 0, 1) - } - b.CleanUp() + TTSEvent("quittalkkonnect") + CleanUp() } func (b *Talkkonnect) cmdDebugStacktrace() { @@ -421,6 +408,7 @@ func (b *Talkkonnect) cmdDebugStacktrace() { log.Printf("debug: line: %d %s\n", line, scanner.Text()) line++ } + goStreamStats() } func (b *Talkkonnect) cmdSendEmail() { @@ -449,29 +437,27 @@ func (b *Talkkonnect) cmdSendEmail() { return } - if TTSEnabled && TTSSendEmail { - localMediaPlayer(TTSSendEmailFilenameAndPath, TTSVolumeLevel, 0, 1) - } + TTSEvent("sendemail") - if EmailEnabled { + if Config.Global.Software.SMTP.Enabled { - emailMessage := fmt.Sprintf(EmailMessage + "\n") + emailMessage := fmt.Sprintf(Config.Global.Software.SMTP.Message + "\n") emailMessage = emailMessage + fmt.Sprintf("Ident: %s \n", b.Ident) emailMessage = emailMessage + fmt.Sprintf("Mumble Username: %s \n", b.Username) - if EmailGpsDateTime { + if Config.Global.Software.SMTP.GpsDateTime { emailMessage = emailMessage + fmt.Sprintf("Date "+GPSDate+" UTC Time "+GPSTime+"\n") } - if EmailGpsLatLong { + if Config.Global.Software.SMTP.GpsLatLong { emailMessage = emailMessage + fmt.Sprintf("Latitude "+strconv.FormatFloat(GPSLatitude, 'f', 6, 64)+" Longitude "+strconv.FormatFloat(GPSLongitude, 'f', 6, 64)+"\n") } - if EmailGoogleMapsURL { + if Config.Global.Software.SMTP.GoogleMapsURL { emailMessage = emailMessage + "http://www.google.com/maps/place/" + strconv.FormatFloat(GPSLatitude, 'f', 6, 64) + "," + strconv.FormatFloat(GPSLongitude, 'f', 6, 64) } - err := sendviagmail(EmailUsername, EmailPassword, EmailReceiver, EmailSubject, emailMessage) + err := sendviagmail(Config.Global.Software.SMTP.Username, Config.Global.Software.SMTP.Password, Config.Global.Software.SMTP.Receiver, Config.Global.Software.SMTP.Subject, emailMessage) if err != nil { log.Println("error: Error from Email Module: ", err) } @@ -484,27 +470,22 @@ func (b *Talkkonnect) cmdConnPreviousServer() { log.Println("debug: Ctrl-F Pressed") log.Println("info: Previous Server Requested") - if TTSEnabled && TTSPreviousServer { - localMediaPlayer(TTSPreviousServerFilenameAndPath, TTSVolumeLevel, 0, 1) - } + TTSEvent("previousserver") if AccountCount > 1 { - if AccountIndex > 0 { AccountIndex-- } else { AccountIndex = AccountCount - 1 } - modifyXMLTagServerHopping(ConfigXMLFile, AccountIndex) } - } func (b *Talkkonnect) cmdClearScreen() { reset() log.Println("debug: Ctrl-L Pressed Cleared Screen") - if TargetBoard == "rpi" { + if Config.Global.Hardware.TargetBoard == "rpi" { if LCDEnabled { LcdText = [4]string{"nil", "nil", "nil", "nil"} LcdDisplay(LcdText, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress) @@ -521,11 +502,7 @@ func (b *Talkkonnect) cmdClearScreen() { func (b *Talkkonnect) cmdPingServers() { log.Println("debug: Ctrl-O Pressed") log.Println("info: Ping Servers") - - if TTSEnabled && TTSPingServers { - localMediaPlayer(TTSPingServersFilenameAndPath, TTSVolumeLevel, 0, 1) - } - + TTSEvent("pingservers") b.pingServers() } @@ -533,9 +510,7 @@ func (b *Talkkonnect) cmdConnNextServer() { log.Println("debug: Ctrl-N Pressed") log.Println("info: Next Server Requested Killing This Session, talkkonnect should be restarted by systemd") - if TTSEnabled && TTSNextServer { - localMediaPlayer(TTSNextServerFilenameAndPath, TTSVolumeLevel, 0, 1) - } + TTSEvent("nextserver") if AccountCount > 1 { if AccountIndex < AccountCount-1 { @@ -543,7 +518,6 @@ func (b *Talkkonnect) cmdConnNextServer() { } else { AccountIndex = 0 } - modifyXMLTagServerHopping(ConfigXMLFile, AccountIndex) } @@ -552,19 +526,19 @@ func (b *Talkkonnect) cmdConnNextServer() { func (b *Talkkonnect) cmdAudioTrafficRecord() { log.Println("debug: Ctrl-I Pressed") log.Println("info: Traffic Recording Requested") - if !AudioRecordEnabled { + if !Config.Global.Hardware.AudioRecordFunction.Enabled { log.Println("warn: Audio Recording Function Not Enabled") } - if AudioRecordMode != "traffic" { + if Config.Global.Hardware.AudioRecordFunction.RecordMode != "traffic" { log.Println("warn: Traffic Recording Not Enabled") } - if AudioRecordEnabled { - if AudioRecordMode == "traffic" { - if AudioRecordFromOutput != "" { - if AudioRecordSoft == "sox" { + if Config.Global.Hardware.AudioRecordFunction.Enabled { + if Config.Global.Hardware.AudioRecordFunction.RecordMode == "traffic" { + if Config.Global.Hardware.AudioRecordFunction.RecordFromOutput != "" { + if Config.Global.Hardware.AudioRecordFunction.RecordSoft == "sox" { go AudioRecordTraffic() - if TargetBoard == "rpi" { + if Config.Global.Hardware.TargetBoard == "rpi" { if LCDEnabled { LcdText = [4]string{"nil", "nil", "Traffic Audio Rec ->", "nil"} // 4 or 3 LcdDisplay(LcdText, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress) @@ -584,19 +558,19 @@ func (b *Talkkonnect) cmdAudioTrafficRecord() { func (b *Talkkonnect) cmdAudioMicRecord() { log.Println("debug: Ctrl-J Pressed") log.Println("info: Ambient (Mic) Recording Requested") - if !AudioRecordEnabled { + if !Config.Global.Hardware.AudioRecordFunction.Enabled { log.Println("warn: Audio Recording Function Not Enabled") } - if AudioRecordMode != "ambient" { + if Config.Global.Hardware.AudioRecordFunction.RecordMode != "ambient" { log.Println("warn: Ambient (Mic) Recording Not Enabled") } - if AudioRecordEnabled { - if AudioRecordMode == "ambient" { - if AudioRecordFromInput != "" { - if AudioRecordSoft == "sox" { + if Config.Global.Hardware.AudioRecordFunction.Enabled { + if Config.Global.Hardware.AudioRecordFunction.RecordMode == "ambient" { + if Config.Global.Hardware.AudioRecordFunction.RecordFromInput != "" { + if Config.Global.Hardware.AudioRecordFunction.RecordSoft == "sox" { go AudioRecordAmbient() - if TargetBoard == "rpi" { + if Config.Global.Hardware.TargetBoard == "rpi" { if LCDEnabled { LcdText = [4]string{"nil", "nil", "Mic Audio Rec ->", "nil"} // 4 or 3 LcdDisplay(LcdText, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress) @@ -616,19 +590,19 @@ func (b *Talkkonnect) cmdAudioMicRecord() { func (b *Talkkonnect) cmdAudioMicTrafficRecord() { log.Println("debug: Ctrl-K Pressed") log.Println("info: Recording (Traffic and Mic) Requested") - if !AudioRecordEnabled { + if !Config.Global.Hardware.AudioRecordFunction.Enabled { log.Println("warn: Audio Recording Function Not Enabled") } - if AudioRecordMode != "combo" { + if Config.Global.Hardware.AudioRecordFunction.RecordMode != "combo" { log.Println("warn: Combo Recording (Traffic and Mic) Not Enabled") } - if AudioRecordEnabled { - if AudioRecordMode == "combo" { - if AudioRecordFromInput != "" { - if AudioRecordSoft == "sox" { + if Config.Global.Hardware.AudioRecordFunction.Enabled { + if Config.Global.Hardware.AudioRecordFunction.RecordMode == "combo" { + if Config.Global.Hardware.AudioRecordFunction.RecordFromInput != "" { + if Config.Global.Hardware.AudioRecordFunction.RecordSoft == "sox" { go AudioRecordCombo() - if TargetBoard == "rpi" { + if Config.Global.Hardware.TargetBoard == "rpi" { if LCDEnabled { LcdText = [4]string{"nil", "nil", "Combo Audio Rec ->", "nil"} // 4 or 3 LcdDisplay(LcdText, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress) @@ -653,25 +627,23 @@ func (b *Talkkonnect) cmdPanicSimulation() { log.Println("debug: Ctrl-P Pressed") log.Println("info: Panic Button Start/Stop Simulation Requested") - if TTSEnabled && TTSPanicSimulation { - localMediaPlayer(TTSPanicSimulationFilenameAndPath, TTSVolumeLevel, 0, 1) - } + TTSEvent("panicsimulation") - if PEnabled { + if Config.Global.Hardware.PanicFunction.Enabled { if b.IsTransmitting { b.TransmitStop(false) } else { b.IsTransmitting = true - b.SendMessage(PMessage, PRecursive) + b.SendMessage(Config.Global.Hardware.PanicFunction.Message, Config.Global.Hardware.PanicFunction.RecursiveSendMessage) } - if PSendIdent { - b.SendMessage(fmt.Sprintf("My Username is %s and Ident is %s", b.Username, b.Ident), PRecursive) + if Config.Global.Hardware.PanicFunction.SendIdent { + b.SendMessage(fmt.Sprintf("My Username is %s and Ident is %s", b.Username, b.Ident), Config.Global.Hardware.PanicFunction.RecursiveSendMessage) } - if PSendGpsLocation { + if Config.Global.Hardware.PanicFunction.SendGpsLocation { var i int = 0 var tries int = 10 @@ -696,12 +668,12 @@ func (b *Talkkonnect) cmdPanicSimulation() { if goodGPSRead && i != tries { log.Println("info: Sending GPS Info My Message") gpsMessage := "My GPS Coordinates are " + fmt.Sprintf(" Latitude "+strconv.FormatFloat(GPSLatitude, 'f', 6, 64)) + fmt.Sprintf(" Longitude "+strconv.FormatFloat(GPSLongitude, 'f', 6, 64)) - b.SendMessage(gpsMessage, PRecursive) + b.SendMessage(gpsMessage, Config.Global.Hardware.PanicFunction.RecursiveSendMessage) } IsPlayStream = true - b.playIntoStream(PFilenameAndPath, PVolume) - if TargetBoard == "rpi" { + b.playIntoStream(Config.Global.Hardware.PanicFunction.FilenameAndPath, Config.Global.Hardware.PanicFunction.Volume) + if Config.Global.Hardware.TargetBoard == "rpi" { if LCDEnabled { LcdText = [4]string{"nil", "nil", "nil", "Panic Message Sent!"} LcdDisplay(LcdText, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress) @@ -710,19 +682,19 @@ func (b *Talkkonnect) cmdPanicSimulation() { oledDisplay(false, 6, 1, "Panic Message Sent!") } } - if PTxLockEnabled && PTxlockTimeOutSecs > 0 { + if Config.Global.Hardware.PanicFunction.TxLockEnabled && Config.Global.Hardware.PanicFunction.TxLockTimeOutSecs > 0 { b.TxLockTimer() } // New. Send email after Panic Event // - if PMailEnabled { + if Config.Global.Hardware.PanicFunction.PMailEnabled { b.cmdSendEmail() log.Println("info: Sending Panic Alert Email To Predefined Email Address") } // // New. Record ambient audio on Panic Event if recording is enabled - if AudioRecordEnabled { + if Config.Global.Hardware.AudioRecordFunction.Enabled { log.Println("info: Running sox for Audio Recording...") AudioRecordAmbient() } @@ -734,8 +706,8 @@ func (b *Talkkonnect) cmdPanicSimulation() { IsPlayStream = false b.IsTransmitting = false - if PLowProfile { - LEDOffAll() + if Config.Global.Hardware.PanicFunction.PLowProfile { + GPIOOutAll("led/relay", "off") log.Println("info: Low Profile Lights Option is Enabled. Turning All Leds Off During Panic Event") if LCDEnabled { log.Println("info: Low Profile Lights is Enabled. Turning Off Display During Panic Event") @@ -760,40 +732,33 @@ func (b *Talkkonnect) cmdScanChannels() { log.Println("debug: Ctrl-S Pressed") log.Println("info: Scanning Channels") - if TTSEnabled && TTSScan { - localMediaPlayer(TTSScanFilenameAndPath, TTSVolumeLevel, 0, 1) - } - + TTSEvent("startscanning") b.Scan() } -func (b *Talkkonnect) cmdThanks() { +func cmdThanks() { log.Println("debug: Ctrl-T Pressed") log.Println("info: Thanks and Acknowledgements Screen Request ") talkkonnectAcknowledgements("\u001b[44;1m") // add blue background to banner reference https://www.lihaoyi.com/post/BuildyourownCommandLinewithANSIescapecodes.html#background-colors } func (b *Talkkonnect) cmdShowUptime() { - log.Println("debug: Ctrl-V Pressed") - log.Println("info: Ctrl-V Version Request") - log.Printf("info: Talkkonnect Version %v Released %v\n", talkkonnectVersion, talkkonnectReleased) -} - -func (b *Talkkonnect) cmdDisplayVersion() { log.Println("debug: Ctrl-U Pressed") log.Println("info: Talkkonnect Uptime Request ") duration := time.Since(StartTime) log.Printf("info: Talkkonnect Now Running For %v \n", secondsToHuman(int(duration.Seconds()))) } +func (b *Talkkonnect) cmdDisplayVersion() { + log.Println("debug: Ctrl-V Pressed") + log.Println("info: Talkkonnect Version Request ") + log.Printf("info: Talkkonnect Version %v Released %v\n", talkkonnectVersion, talkkonnectReleased) +} + func (b *Talkkonnect) cmdDumpXMLConfig() { log.Println("debug: Ctrl-X Pressed") log.Println("info: Print XML Config " + ConfigXMLFile) - - if TTSEnabled && TTSPrintXmlConfig { - localMediaPlayer(TTSPrintXmlConfigFilenameAndPath, TTSVolumeLevel, 0, 1) - } - + TTSEvent("printxmlconfig") printxmlconfig() } @@ -802,10 +767,27 @@ func (b *Talkkonnect) cmdPlayRepeaterTone() { log.Println("info: Play Repeater Tone on Speaker and Simulate RX Signal") b.BackLightTimer() - if RepeaterToneEnabled { - b.PlayTone(RepeaterToneFrequencyHz, RepeaterToneDurationSec, "local", true) + + if Config.Global.Software.Sounds.RepeaterTone.Enabled { + b.PlayTone(Config.Global.Software.Sounds.RepeaterTone.ToneFrequencyHz, Config.Global.Software.Sounds.RepeaterTone.ToneDurationSec, "local", true) } else { log.Println("warn: Repeater Tone Disabled by Config") } } + +func (b *Talkkonnect) cmdLiveReload() { + log.Println("debug: Ctrl-B Pressed") + log.Println("info: XML Config Live Reload") + err := readxmlconfig(ConfigXMLFile, true) + if err != nil { + message := err.Error() + FatalCleanUp(message) + } +} + +func cmdSanityCheck() { + log.Println("debug: Ctrl-H Pressed") + log.Println("info: XML Sanity Checker") + CheckConfigSanity(false) +} diff --git a/go.mod b/go.mod index d84ffe6..d1b8539 100644 --- a/go.mod +++ b/go.mod @@ -1,32 +1,46 @@ module github.com/talkkonnect/talkkonnect -go 1.16 +go 1.17 require ( + github.com/allan-simon/go-singleinstance v0.0.0-20210120080615-d0997106ab37 github.com/comail/colog v0.0.0-20160416085026-fba8e7b1f46c github.com/eclipse/paho.mqtt.golang v1.3.5 - github.com/glendc/go-external-ip v0.0.0-20200601212049-c872357d968e - github.com/golang/glog v1.0.0 // indirect - github.com/golang/protobuf v1.5.2 // indirect + github.com/glendc/go-external-ip v0.1.0 github.com/gvalkov/golang-evdev v0.0.0-20191114124502-287e62b94bcb github.com/jacobsa/go-serial v0.0.0-20180131005756-15cf729a72d4 github.com/kennygrant/sanitize v1.2.4 - github.com/mattn/go-runewidth v0.0.13 // indirect - github.com/stianeikeland/go-rpio v4.2.0+incompatible // indirect - github.com/stianeikeland/go-rpio/v4 v4.5.0 - github.com/talkkonnect/embd v0.0.0-20210824124053-e127c37e1577 // indirect + github.com/stianeikeland/go-rpio v4.2.0+incompatible + github.com/stianeikeland/go-rpio/v4 v4.5.1 github.com/talkkonnect/go-hd44780 v0.0.0-20210824123606-f3398c777f39 - github.com/talkkonnect/go-i2c v0.0.0-20190316095740-e326afb7fdb1 // indirect - github.com/talkkonnect/go-logger v0.0.0-20190316101244-635f8e12dd6c // indirect + github.com/talkkonnect/go-mcp23017 v0.0.0-20210831103122-1c46ab6c8c82 github.com/talkkonnect/go-nmea v0.0.0-20210719131409-1f6a4b9c6894 github.com/talkkonnect/go-oled-i2c v0.0.0-20190324002809-c9178f9ccd23 github.com/talkkonnect/go-openal v0.0.0-20181013102444-59f5b1d30aff - github.com/talkkonnect/gopus v0.0.0-20200617161709-292e80cbfafd // indirect github.com/talkkonnect/gpio v0.0.0-20181225144829-9b8a2de8e6fe - github.com/talkkonnect/gumble v0.0.0-20210525051103-0ece99f819cc + github.com/talkkonnect/gumble v0.0.0-20211002133403-8965a63155bf + github.com/talkkonnect/max7219 v0.0.0-20211028104259-8b131029f2b7 github.com/talkkonnect/termbox-go v0.0.0-20181013101158-0ee46dd7ddac github.com/talkkonnect/volume-go v0.0.0-20210720063739-bb23887b7601 github.com/xackery/gomail v0.0.0-20150929200936-cc84600edc17 - golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf + golang.org/x/sys v0.0.0-20211113001501-0c823b97ae02 periph.io/x/periph v3.6.8+incompatible ) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fulr/spidev v0.0.0-20150210165549-524e13e3fac2 // indirect + github.com/go-ole/go-ole v1.2.4 // indirect + github.com/golang/glog v1.0.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/gorilla/websocket v1.4.2 // indirect + github.com/mattn/go-runewidth v0.0.13 // indirect + github.com/moutend/go-wca v0.2.0 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + github.com/talkkonnect/embd v0.0.0-20210824124053-e127c37e1577 // indirect + github.com/talkkonnect/go-i2c v0.0.0-20190316095740-e326afb7fdb1 // indirect + github.com/talkkonnect/go-logger v0.0.0-20190316101244-635f8e12dd6c // indirect + github.com/talkkonnect/gopus v0.0.0-20200617161709-292e80cbfafd // indirect + golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0 // indirect + google.golang.org/protobuf v1.26.0 // indirect +) diff --git a/go.sum b/go.sum index d630881..ac8b68e 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,15 @@ +github.com/allan-simon/go-singleinstance v0.0.0-20210120080615-d0997106ab37 h1:28uU3TtuvQ6KRndxg9TrC868jBWmSKgh0GTXkACCXmA= +github.com/allan-simon/go-singleinstance v0.0.0-20210120080615-d0997106ab37/go.mod h1:6AXRstqK+32jeFmw89QGL2748+dj34Av4xc/I9oo9BY= github.com/comail/colog v0.0.0-20160416085026-fba8e7b1f46c h1:bzYQ6WpR+t35/y19HUkolcg7SYeWZ15IclC9Z4naGHI= github.com/comail/colog v0.0.0-20160416085026-fba8e7b1f46c/go.mod h1:1WwgAwMKQLYG5I2FBhpVx94YTOAuB2W59IZ7REjSE6Y= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/eclipse/paho.mqtt.golang v1.3.5 h1:sWtmgNxYM9P2sP+xEItMozsR3w0cqZFlqnNN1bdl41Y= github.com/eclipse/paho.mqtt.golang v1.3.5/go.mod h1:eTzb4gxwwyWpqBUHGQZ4ABAV7+Jgm1PklsYT/eo8Hcc= -github.com/glendc/go-external-ip v0.0.0-20200601212049-c872357d968e h1:gLpAlmoGqnW3a3GCkOe+Ic8hZoSCfi0PdA0B8j7d6uw= -github.com/glendc/go-external-ip v0.0.0-20200601212049-c872357d968e/go.mod h1:o9OoDQyE1WHvYVUH1FdFapy1/rCZHHq3O5wS4VA83ig= +github.com/fulr/spidev v0.0.0-20150210165549-524e13e3fac2 h1:Bpecy8A24LtdIGkRUQTzoWf2mR0zkvxzAgTN5iP2iXM= +github.com/fulr/spidev v0.0.0-20150210165549-524e13e3fac2/go.mod h1:bMLIIHSjkThym5s6mFw/1rkPjtUDvbxSK4xTe/ai2AM= +github.com/glendc/go-external-ip v0.1.0 h1:iX3xQ2Q26atAmLTbd++nUce2P5ht5P4uD4V7caSY/xg= +github.com/glendc/go-external-ip v0.1.0/go.mod h1:CNx312s2FLAJoWNdJWZ2Fpf5O4oLsMFwuYviHjS4uJE= github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= @@ -34,8 +38,8 @@ github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/stianeikeland/go-rpio v4.2.0+incompatible h1:CUOlIxdJdT+H1obJPsmg8byu7jMSECLfAN9zynm5QGo= github.com/stianeikeland/go-rpio v4.2.0+incompatible/go.mod h1:Sh81rdJwD96E2wja2Gd7rrKM+XZ9LrwvN2w4IXrqLR8= -github.com/stianeikeland/go-rpio/v4 v4.5.0 h1:9jkc3cQor8gd40GeXVfcWI4mlZTTyXG6yROZCpKdV0c= -github.com/stianeikeland/go-rpio/v4 v4.5.0/go.mod h1:A3GvHxC1Om5zaId+HqB3HKqx4K/AqeckxB7qRjxMK7o= +github.com/stianeikeland/go-rpio/v4 v4.5.1 h1:sLzl5w1HS+4726C5kfvpIgjXULrLCCM82vDpAFefGQI= +github.com/stianeikeland/go-rpio/v4 v4.5.1/go.mod h1:A3GvHxC1Om5zaId+HqB3HKqx4K/AqeckxB7qRjxMK7o= github.com/stretchr/testify v1.2.1 h1:52QO5WkIUcHGIR7EnGagH88x1bUzqGXTC5/1bDTUQ7U= github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/talkkonnect/embd v0.0.0-20210824124053-e127c37e1577 h1:bihz9UL2bBgp4WQpbXjFtcQj5q7iOtmRELXcxM4bPlQ= @@ -46,6 +50,8 @@ github.com/talkkonnect/go-i2c v0.0.0-20190316095740-e326afb7fdb1 h1:fC+EirjlVNx/ github.com/talkkonnect/go-i2c v0.0.0-20190316095740-e326afb7fdb1/go.mod h1:6OAIGFvCa/a/PwfmcctAw2N5T+XHy2qesz7LiZvYcgE= github.com/talkkonnect/go-logger v0.0.0-20190316101244-635f8e12dd6c h1:kbjUEvovC9JxkO3MQCRHZ2oAP/yg+ggmUe+CjwdUqAs= github.com/talkkonnect/go-logger v0.0.0-20190316101244-635f8e12dd6c/go.mod h1:RgJ9bxHte2cnbimoMDr7NNLOxYWiBgYAnf67OzucsMw= +github.com/talkkonnect/go-mcp23017 v0.0.0-20210831103122-1c46ab6c8c82 h1:VgA8XaXnDBytA2zVv94AXp3WAyQOBW/SNaTXjZco1Qc= +github.com/talkkonnect/go-mcp23017 v0.0.0-20210831103122-1c46ab6c8c82/go.mod h1:9+q2vdqRNwz4tVg3K77nwUT2ePfkrrRWX+xy8u7lE6A= github.com/talkkonnect/go-nmea v0.0.0-20210719131409-1f6a4b9c6894 h1:G1nlV2WxU5Q1tkqIRpAM7QdGCxdnbgD8HH+zCBZbEU4= github.com/talkkonnect/go-nmea v0.0.0-20210719131409-1f6a4b9c6894/go.mod h1:d/3MpsW0wdx2ZXQVxj92RRr1YnuJ9bVPengVHw2QKEw= github.com/talkkonnect/go-oled-i2c v0.0.0-20190324002809-c9178f9ccd23 h1:zlIQLLPf2w5EOMm2hO9i7z+QZ6paAKCfW8C/7IqHti0= @@ -56,8 +62,10 @@ github.com/talkkonnect/gopus v0.0.0-20200617161709-292e80cbfafd h1:zPWCIlacGpNrd github.com/talkkonnect/gopus v0.0.0-20200617161709-292e80cbfafd/go.mod h1:zMs0TkqDtyJ3CaPSyqhhW2VRnd/L1mSL11vQ6DG5Ovc= github.com/talkkonnect/gpio v0.0.0-20181225144829-9b8a2de8e6fe h1:ac77K8YD3YD8Mn5P95fb7Vbq/2nKCECVfaTxMb0bDj0= github.com/talkkonnect/gpio v0.0.0-20181225144829-9b8a2de8e6fe/go.mod h1:SpblZEdL1bFf8DR4xGDPN7G1XvXCQj/eDYtYuG+Xmd0= -github.com/talkkonnect/gumble v0.0.0-20210525051103-0ece99f819cc h1:owE0vkre6CUFE31HBp2j14SNjIb5BU91RX9XKOEb6JQ= -github.com/talkkonnect/gumble v0.0.0-20210525051103-0ece99f819cc/go.mod h1:noOPjJie+0MkL38lno8zFRbzL/zVN8oRETIRXzo19NI= +github.com/talkkonnect/gumble v0.0.0-20211002133403-8965a63155bf h1:ddWRNyq82+QwESvtVc+iiSX2YqXGluUYIw+bwNqs9NE= +github.com/talkkonnect/gumble v0.0.0-20211002133403-8965a63155bf/go.mod h1:noOPjJie+0MkL38lno8zFRbzL/zVN8oRETIRXzo19NI= +github.com/talkkonnect/max7219 v0.0.0-20211028104259-8b131029f2b7 h1:+GsgGTbtHSzXSixTmY3d3c6cmoCpTRPQ8kKyd+b0kN0= +github.com/talkkonnect/max7219 v0.0.0-20211028104259-8b131029f2b7/go.mod h1:RYVyiuHwl28P8BIi66n5eFSY6+hvKI6lkov8GXlm08Y= github.com/talkkonnect/termbox-go v0.0.0-20181013101158-0ee46dd7ddac h1:bD5cKn2ng8K7RFKrKSrI5g5gaLgKxdK6xhRSH5309hc= github.com/talkkonnect/termbox-go v0.0.0-20181013101158-0ee46dd7ddac/go.mod h1:5AtlTmjScae7BcatAlDngj6A2YvKEArvjNy4DcZWdvA= github.com/talkkonnect/volume-go v0.0.0-20210720063739-bb23887b7601 h1:mB8XFaHrc9FzRt+DWPPs7HKxsliTTFQW7kF45qh6bxY= @@ -69,8 +77,8 @@ golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0 h1:Jcxah/M+oLZ/R4/z5RzfPzGbP golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211113001501-0c823b97ae02 h1:7NCfEGl0sfUojmX78nK9pBJuUlSZWEJA/TwASvfiPLo= +golang.org/x/sys v0.0.0-20211113001501-0c823b97ae02/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/gpio.go b/gpio.go index eaac757..26f0468 100644 --- a/gpio.go +++ b/gpio.go @@ -33,13 +33,61 @@ import ( "log" "time" - "github.com/stianeikeland/go-rpio/v4" + "github.com/stianeikeland/go-rpio" + "github.com/talkkonnect/go-mcp23017" "github.com/talkkonnect/gpio" + "github.com/talkkonnect/max7219" ) +//Variables for Input Buttons/Switches +var ( + TxButtonUsed bool + TxButton gpio.Pin + TxButtonPin uint + TxButtonState uint + + TxToggleUsed bool + TxToggle gpio.Pin + TxTogglePin uint + TxToggleState uint + + UpButtonUsed bool + UpButton gpio.Pin + UpButtonPin uint + UpButtonState uint + + DownButtonUsed bool + DownButton gpio.Pin + DownButtonPin uint + DownButtonState uint + + PanicUsed bool + PanicButton gpio.Pin + PanicButtonPin uint + PanicButtonState uint + + StreamToggleUsed bool + StreamButton gpio.Pin + StreamButtonPin uint + StreamButtonState uint + + CommentUsed bool + CommentButton gpio.Pin + CommentButtonPin uint + CommentButtonState uint + + RotaryUsed bool + RotaryA gpio.Pin + RotaryB gpio.Pin + RotaryAPin uint + RotaryBPin uint +) + +var D [8]*mcp23017.Device + func (b *Talkkonnect) initGPIO() { - if TargetBoard != "rpi" { + if Config.Global.Hardware.TargetBoard != "rpi" { return } @@ -50,65 +98,129 @@ func (b *Talkkonnect) initGPIO() { } b.GPIOEnabled = true - if TxButtonPin > 0 { - TxButtonPinPullUp := rpio.Pin(TxButtonPin) - TxButtonPinPullUp.PullUp() - } - - if TxTogglePin > 0 { - TxTogglePinPullUp := rpio.Pin(TxTogglePin) - TxTogglePinPullUp.PullUp() - } - - if UpButtonPin > 0 { - UpButtonPinPullUp := rpio.Pin(UpButtonPin) - UpButtonPinPullUp.PullUp() - } - - if DownButtonPin > 0 { - DownButtonPinPullUp := rpio.Pin(DownButtonPin) - DownButtonPinPullUp.PullUp() - } - - if PanicButtonPin > 0 { - PanicButtonPinPullUp := rpio.Pin(PanicButtonPin) - PanicButtonPinPullUp.PullUp() - } - - if CommentButtonPin > 0 { - CommentButtonPinPullUp := rpio.Pin(CommentButtonPin) - CommentButtonPinPullUp.PullUp() + // Handle GPIO Expander Pins As Outputs if Enabled + if Config.Global.Hardware.IO.GPIOExpander.Enabled { + for _, gpioExpander := range Config.Global.Hardware.IO.GPIOExpander.Chip { + if Config.Global.Hardware.IO.GPIOExpander.Chip[gpioExpander.ID].Enabled { + log.Printf("debug: Setting up MCP23017 GPIO Expander on IC2 Bus %v Device No %v\n", gpioExpander.I2Cbus, gpioExpander.MCP23017Device) + var err error + D[gpioExpander.MCP23017Device], err = mcp23017.Open(gpioExpander.I2Cbus, gpioExpander.MCP23017Device) + if err != nil { + // log.Println("error: Unable To Setup Expander GPIO Chip On I2C Bus " + strconv.Itoa(int(gpioExpander.I2Cbus)) + " Device " + strconv.Itoa(int(gpioExpander.MCP23017Device)) + " With " + err.Error()) + return + } + for y := 0; y < 16; y++ { + if Config.Global.Hardware.IO.Pins.Pin[y].Enabled && Config.Global.Hardware.IO.Pins.Pin[y].Direction == "output" && Config.Global.Hardware.IO.Pins.Pin[y].Type == "mcp23017" { + log.Printf("debug: Pin %v Enabled as Output\n", y) + err := D[gpioExpander.MCP23017Device].PinMode(uint8(y), mcp23017.OUTPUT) + if err != nil { + log.Printf("error: Cannot Set Pin %v as Output With Error %v\n", y, err) + } + } + if Config.Global.Hardware.IO.Pins.Pin[y].Enabled && Config.Global.Hardware.IO.Pins.Pin[y].Direction == "input" && Config.Global.Hardware.IO.Pins.Pin[y].Type == "mcp23017" { + log.Printf("debug: Pin %v Enabled as Input\n", y) + err := D[gpioExpander.MCP23017Device].PinMode(uint8(y), mcp23017.INPUT) + if err != nil { + log.Printf("error: Cannot Set Pin %v as Input With Error %v\n", y, err) + } + } + } + } + } } - if StreamButtonPin > 0 { - StreamButtonPinPullUp := rpio.Pin(StreamButtonPin) - StreamButtonPinPullUp.PullUp() + //handle inputs on RPI GPIO + for _, io := range Config.Global.Hardware.IO.Pins.Pin { + if io.Enabled && io.Direction == "input" && io.Type == "gpio" { + if io.Name == "txptt" && io.PinNo > 0 { + log.Printf("debug: GPIO Setup Input Device %v Name %v PinNo %v", io.Device, io.Name, io.PinNo) + TxButtonPinPullUp := rpio.Pin(io.PinNo) + TxButtonPinPullUp.PullUp() + TxButtonUsed = true + TxButtonPin = io.PinNo + } + if io.Name == "txtoggle" && io.PinNo > 0 { + log.Printf("debug: GPIO Setup Input Device %v Name %v PinNo %v", io.Device, io.Name, io.PinNo) + TxTogglePinPullUp := rpio.Pin(io.PinNo) + TxTogglePinPullUp.PullUp() + TxToggleUsed = true + TxTogglePin = io.PinNo + } + if io.Name == "channelup" && io.PinNo > 0 { + log.Printf("debug: GPIO Setup Input Device %v Name %v PinNo %v", io.Device, io.Name, io.PinNo) + ChannelUpPinPullUp := rpio.Pin(io.PinNo) + ChannelUpPinPullUp.PullUp() + UpButtonUsed = true + UpButtonPin = io.PinNo + } + if io.Name == "channeldown" && io.PinNo > 0 { + log.Printf("debug: GPIO Setup Input Device %v Name %v PinNo %v", io.Device, io.Name, io.PinNo) + ChannelDownPinPullUp := rpio.Pin(io.PinNo) + ChannelDownPinPullUp.PullUp() + DownButtonUsed = true + DownButtonPin = io.PinNo + } + if io.Name == "panic" && io.PinNo > 0 { + log.Printf("debug: GPIO Setup Input Device %v Name %v PinNo %v", io.Device, io.Name, io.PinNo) + PanicPinPullUp := rpio.Pin(io.PinNo) + PanicPinPullUp.PullUp() + PanicUsed = true + PanicButtonPin = io.PinNo + } + if io.Name == "streamtoggle" && io.PinNo > 0 { + log.Printf("debug: GPIO Setup Input Device %v Name %v PinNo %v", io.Device, io.Name, io.PinNo) + StreamTogglePinPullUp := rpio.Pin(io.PinNo) + StreamTogglePinPullUp.PullUp() + StreamToggleUsed = true + StreamButtonPin = io.PinNo + } + if io.Name == "comment" && io.PinNo > 0 { + log.Printf("debug: GPIO Setup Input Device %v Name %v PinNo %v", io.Device, io.Name, io.PinNo) + CommentPinPullUp := rpio.Pin(io.PinNo) + CommentPinPullUp.PullUp() + CommentUsed = true + CommentButtonPin = io.PinNo + } + if io.Name == "rotarya" && io.PinNo > 0 { + log.Printf("debug: GPIO Setup Input Device %v Name %v PinNo %v", io.Device, io.Name, io.PinNo) + RotaryAPinPullUp := rpio.Pin(io.PinNo) + RotaryAPinPullUp.PullUp() + RotaryUsed = true + RotaryAPin = io.PinNo + } + if io.Name == "rotaryb" && io.PinNo > 0 { + log.Printf("debug: GPIO Setup Input Device %v Name %v PinNo %v", io.Device, io.Name, io.PinNo) + RotaryBPinPullUp := rpio.Pin(io.PinNo) + RotaryBPinPullUp.PullUp() + RotaryUsed = true + RotaryBPin = io.PinNo + } + } } - if TxButtonPin > 0 || TxTogglePin > 0 || UpButtonPin > 0 || DownButtonPin > 0 || PanicButtonPin > 0 || CommentButtonPin > 0 { + if TxButtonUsed || TxToggleUsed || UpButtonUsed || DownButtonUsed || PanicUsed || StreamToggleUsed || CommentUsed || RotaryUsed { rpio.Close() } - if TxButtonPin > 0 { + if TxButtonUsed { TxButton = gpio.NewInput(TxButtonPin) go func() { for { if IsConnected { - time.Sleep(200 * time.Millisecond) + time.Sleep(150 * time.Millisecond) currentState, err := TxButton.Read() if currentState != TxButtonState && err == nil { TxButtonState = currentState - if b.Stream != nil { if TxButtonState == 1 { if isTx { isTx = false b.TransmitStop(true) - time.Sleep(250 * time.Millisecond) - if TxCounter { + time.Sleep(150 * time.Millisecond) + if Config.Global.Software.Settings.TxCounter { txcounter++ log.Println("debug: Tx Button Count ", txcounter) } @@ -119,7 +231,7 @@ func (b *Talkkonnect) initGPIO() { if !isTx { isTx = true b.TransmitStart() - time.Sleep(250 * time.Millisecond) + time.Sleep(150 * time.Millisecond) } } } @@ -132,7 +244,7 @@ func (b *Talkkonnect) initGPIO() { } - if TxTogglePin > 0 { + if TxToggleUsed { TxToggle = gpio.NewInput(TxTogglePin) go func() { var prevState uint = 1 @@ -160,7 +272,7 @@ func (b *Talkkonnect) initGPIO() { } } prevState = 1 - time.Sleep(200 * time.Millisecond) + time.Sleep(150 * time.Millisecond) } if !isTx { @@ -174,7 +286,7 @@ func (b *Talkkonnect) initGPIO() { } prevState = 1 log.Println("debug: Toggle Started Transmitting") - time.Sleep(200 * time.Millisecond) + time.Sleep(150 * time.Millisecond) } } } else { @@ -184,14 +296,14 @@ func (b *Talkkonnect) initGPIO() { }() } - if UpButtonPin > 0 { + if UpButtonUsed { UpButton = gpio.NewInput(UpButtonPin) go func() { for { if IsConnected { currentState, err := UpButton.Read() - time.Sleep(200 * time.Millisecond) + time.Sleep(150 * time.Millisecond) if currentState != UpButtonState && err == nil { UpButtonState = currentState @@ -201,7 +313,7 @@ func (b *Talkkonnect) initGPIO() { } else { log.Println("debug: UP Button is pressed") b.ChannelUp() - time.Sleep(200 * time.Millisecond) + time.Sleep(150 * time.Millisecond) } } @@ -212,14 +324,14 @@ func (b *Talkkonnect) initGPIO() { }() } - if DownButtonPin > 0 { + if DownButtonUsed { DownButton = gpio.NewInput(DownButtonPin) go func() { for { if IsConnected { currentState, err := DownButton.Read() - time.Sleep(200 * time.Millisecond) + time.Sleep(150 * time.Millisecond) if currentState != DownButtonState && err == nil { DownButtonState = currentState @@ -229,7 +341,7 @@ func (b *Talkkonnect) initGPIO() { } else { log.Println("debug: Ch Down Button is pressed") b.ChannelDown() - time.Sleep(200 * time.Millisecond) + time.Sleep(150 * time.Millisecond) } } } else { @@ -239,7 +351,7 @@ func (b *Talkkonnect) initGPIO() { }() } - if PanicButtonPin > 0 { + if PanicUsed { PanicButton = gpio.NewInput(PanicButtonPin) go func() { @@ -247,7 +359,7 @@ func (b *Talkkonnect) initGPIO() { if IsConnected { currentState, err := PanicButton.Read() - time.Sleep(200 * time.Millisecond) + time.Sleep(150 * time.Millisecond) if currentState != PanicButtonState && err == nil { PanicButtonState = currentState @@ -257,7 +369,7 @@ func (b *Talkkonnect) initGPIO() { } else { log.Println("debug: Panic Button is pressed") b.cmdPanicSimulation() - time.Sleep(200 * time.Millisecond) + time.Sleep(150 * time.Millisecond) } } } else { @@ -267,7 +379,7 @@ func (b *Talkkonnect) initGPIO() { }() } - if CommentButtonPin > 0 { + if CommentUsed { CommentButton = gpio.NewInput(CommentButtonPin) go func() { @@ -275,19 +387,19 @@ func (b *Talkkonnect) initGPIO() { if IsConnected { currentState, err := CommentButton.Read() - time.Sleep(200 * time.Millisecond) + time.Sleep(150 * time.Millisecond) if currentState != CommentButtonState && err == nil { CommentButtonState = currentState if CommentButtonState == 1 { - log.Println("debug: Comment Button State 1 setting comment to State 1 Message") - b.SetComment(CommentMessageOff) + log.Println("debug: Comment Button State 1 setting comment to State 1 Message ", Config.Global.Hardware.Comment.CommentMessageOff) + b.SetComment(Config.Global.Hardware.Comment.CommentMessageOff) } else { - log.Println("debug: Comment Button State 2 setting comment to State 2 Message") - b.SetComment(CommentMessageOn) + log.Println("debug: Comment Button State 2 setting comment to State 2 Message ", Config.Global.Hardware.Comment.CommentMessageOn) + b.SetComment(Config.Global.Hardware.Comment.CommentMessageOn) } - time.Sleep(200 * time.Millisecond) + time.Sleep(150 * time.Millisecond) } } else { time.Sleep(1 * time.Second) @@ -297,7 +409,7 @@ func (b *Talkkonnect) initGPIO() { } - if StreamButtonPin > 0 { + if StreamToggleUsed { StreamButton = gpio.NewInput(StreamButtonPin) go func() { @@ -305,7 +417,7 @@ func (b *Talkkonnect) initGPIO() { if IsConnected { currentState, err := StreamButton.Read() - time.Sleep(200 * time.Millisecond) + time.Sleep(150 * time.Millisecond) if currentState != StreamButtonState && err == nil { StreamButtonState = currentState @@ -315,7 +427,7 @@ func (b *Talkkonnect) initGPIO() { } else { log.Println("debug: Stream Button is pressed") b.cmdPlayback() - time.Sleep(200 * time.Millisecond) + time.Sleep(150 * time.Millisecond) } } } else { @@ -325,89 +437,156 @@ func (b *Talkkonnect) initGPIO() { }() } - if OnlineLEDPin > 0 { - OnlineLED = gpio.NewOutput(OnlineLEDPin, false) - } - - if ParticipantsLEDPin > 0 { - ParticipantsLED = gpio.NewOutput(ParticipantsLEDPin, false) - } - - if TransmitLEDPin > 0 { - TransmitLED = gpio.NewOutput(TransmitLEDPin, false) - } - - if HeartBeatLEDPin > 0 { - HeartBeatLED = gpio.NewOutput(HeartBeatLEDPin, false) - } - - if AttentionLEDPin > 0 { - AttentionLED = gpio.NewOutput(AttentionLEDPin, false) - } - - if LCDBackLightLEDPin > 0 { - BackLightLED = gpio.NewOutput(uint(LCDBackLightLEDPin), false) + if RotaryUsed { + RotaryA = gpio.NewInput(RotaryAPin) + RotaryB = gpio.NewInput(RotaryBPin) + go func() { + var LastStateA uint = 0 + for { + if IsConnected { + time.Sleep(5 * time.Millisecond) + currentStateA, err0 := RotaryA.Read() + if currentStateA != LastStateA && err0 == nil { + currentStateB, err1 := RotaryB.Read() + if currentStateB != currentStateA && err1 == nil { + b.cmdChannelUp() + log.Println("debug: Rotating Clockwise") + } else { + log.Println("debug: Rotating CounterClockwise") + b.cmdChannelDown() + } + } + LastStateA = currentStateA + } else { + time.Sleep(1 * time.Second) + } + } + }() } +} - if VoiceActivityLEDPin > 0 { - VoiceActivityLED = gpio.NewOutput(VoiceActivityLEDPin, false) +func GPIOOutPin(name string, command string) { + if Config.Global.Hardware.TargetBoard != "rpi" { + return } - if VoiceTargetLEDPin > 0 { - VoiceTargetLED = gpio.NewOutput(VoiceTargetLEDPin, false) - } + for _, io := range Config.Global.Hardware.IO.Pins.Pin { -} + if io.Enabled && io.Direction == "output" && io.Name == name { + if command == "on" { + switch io.Type { + case "gpio": + log.Printf("debug: Turning On %v at pin %v Output GPIO\n", io.Name, io.PinNo) + gpio.NewOutput(io.PinNo, true) + case "mcp23017": + log.Printf("debug: Turning On %v at pin %v Output mcp23017\n", io.Name, io.PinNo) + err := D[io.ID].DigitalWrite(uint8(io.PinNo), mcp23017.LOW) + if err != nil { + log.Printf("error: Error Turning On %v at pin %v Output mcp23017 with error %v\n", io.Name, io.PinNo, err) + } + default: + log.Println("error: GPIO Types Currently Supported are gpio or mcp23017 only!") + } + break + } -func LEDOnFunc(LED gpio.Pin) { - if TargetBoard != "rpi" { - return - } - LED.High() -} + if command == "off" { + switch io.Type { + case "gpio": + log.Printf("debug: Turning Off %v at pin %v Output GPIO\n", io.Name, io.PinNo) + gpio.NewOutput(io.PinNo, false) + case "mcp23017": + log.Printf("debug: Turning Off %v at pin %v Output mcp23017\n", io.Name, io.PinNo) + err := D[io.ID].DigitalWrite(uint8(io.PinNo), mcp23017.HIGH) + if err != nil { + log.Printf("error: Error Turning Off %v at pin %v Output mcp23017 with error %v\n", io.Name, io.PinNo, err) + } + default: + log.Println("error: GPIO Types Currently Supported are gpio or mcp23017 only!") + } + break + } -func LEDOffFunc(LED gpio.Pin) { - if TargetBoard != "rpi" { - return + if command == "pulse" { + switch io.Type { + case "gpio": + log.Printf("debug: Pulsing %v at pin %v Output GPIO\n", io.Name, io.PinNo) + gpio.NewOutput(io.PinNo, false) + time.Sleep(Config.Global.Hardware.IO.Pulse.Leading * time.Millisecond) + gpio.NewOutput(io.PinNo, true) + time.Sleep(Config.Global.Hardware.IO.Pulse.Pulse * time.Millisecond) + gpio.NewOutput(io.PinNo, false) + time.Sleep(Config.Global.Hardware.IO.Pulse.Trailing * time.Millisecond) + case "mcp23017": + log.Printf("debug: Pulsing %v at pin %v Output mcp23017\n", io.Name, io.PinNo) + err := D[io.ID].DigitalWrite(uint8(io.PinNo), mcp23017.HIGH) + if err != nil { + log.Printf("error: Error Turning Off %v at pin %v Output mcp23017\n", io.Name, io.PinNo) + } + time.Sleep(Config.Global.Hardware.IO.Pulse.Leading * time.Millisecond) + err = D[io.ID].DigitalWrite(uint8(io.PinNo), mcp23017.LOW) + if err != nil { + log.Printf("error: Error Turning On %v at pin %v Output mcp23017\n", io.Name, io.PinNo) + } + time.Sleep(Config.Global.Hardware.IO.Pulse.Pulse * time.Millisecond) + err = D[io.ID].DigitalWrite(uint8(io.PinNo), mcp23017.HIGH) + if err != nil { + log.Printf("error: Error Turning Off %v at pin %v Output mcp23017\n", io.Name, io.PinNo) + } + time.Sleep(Config.Global.Hardware.IO.Pulse.Trailing * time.Millisecond) + default: + log.Println("error: GPIO Types Currently Supported are gpio or mcp23017 only!") + } + break + } + } } - LED.Low() } -func LEDOffAll() { - if TargetBoard != "rpi" { +func GPIOOutAll(name string, command string) { + if Config.Global.Hardware.TargetBoard != "rpi" { return } - log.Println("debug: Turning Off All LEDS!") - if OnlineLEDPin > 0 { - LEDOffFunc(OnlineLED) - } - if ParticipantsLEDPin > 0 { - LEDOffFunc(ParticipantsLED) - } - if TransmitLEDPin > 0 { - LEDOffFunc(TransmitLED) - } - if HeartBeatLEDPin > 0 { - LEDOffFunc(HeartBeatLED) - } - if AttentionLEDPin > 0 { - LEDOffFunc(AttentionLED) - } - if LCDBackLightLEDPin > 0 { - LEDOffFunc(BackLightLED) - } - if VoiceActivityLEDPin > 0 { - LEDOffFunc(VoiceActivityLED) - } - - if VoiceTargetLEDPin > 0 { - LEDOffFunc(VoiceTargetLED) + for _, io := range Config.Global.Hardware.IO.Pins.Pin { + if io.Enabled && io.Direction == "output" && io.Device == "led/relay" { + switch io.Type { + case "gpio": + if command == "on" { + log.Printf("debug: Turning On %v Output GPIO\n", io.Name) + gpio.NewOutput(io.PinNo, true) + } + if command == "off" { + log.Printf("debug: Turning Off %v Output GPIO\n", io.Name) + gpio.NewOutput(io.PinNo, false) + } + case "mcp23017": + if command == "on" { + log.Printf("debug: Turning On %v Output mcp23017\n", io.Name) + if D[io.ID] != nil { + err := D[io.ID].DigitalWrite(uint8(io.PinNo), mcp23017.LOW) + if err != nil { + log.Printf("error: Error Turning On %v at pin %v Output mcp23017\n", io.Name, io.PinNo) + } + } + } + if command == "off" { + log.Printf("debug: Turning Off %v Output mcp23017\n", io.Name) + if D[io.ID] != nil { + err := D[io.ID].DigitalWrite(uint8(io.PinNo), mcp23017.HIGH) + if err != nil { + log.Printf("error: Error Turning Off %v at pin %v Output mcp23017\n", io.Name, io.PinNo) + } + } + } + default: + log.Println("error: GPIO Types Currently Supported are gpio or mcp23017 only!") + } + } } - } -func MyLedStripLEDOffAll() { +func MyLedStripGPIOOutAll() { MyLedStrip.ledCtrl(SOnlineLED, OffCol) MyLedStrip.ledCtrl(SParticipantsLED, OffCol) MyLedStrip.ledCtrl(STransmitLED, OffCol) @@ -437,44 +616,15 @@ func MyLedStripTransmitLEDOff() { MyLedStrip.ledCtrl(STransmitLED, OffCol) } -func relayCommand(relayNo int, command string) { - // all relays (0) - if relayNo == 0 { - for i := 1; i <= int(TotalRelays); i++ { - if command == "on" { - log.Println("info: Relay ", i, "On") - gpio.NewOutput(RelayPins[i], false) - - } - if command == "off" { - log.Println("info: Relay ", i, "Off") - gpio.NewOutput(RelayPins[i], true) - } - if command == "pulse" { - log.Println("info: Relay ", i, "Pulse") - gpio.NewOutput(RelayPins[i], false) - time.Sleep(RelayPulseMills * time.Millisecond) - gpio.NewOutput(RelayPins[i], true) - } - } - return - } +func Max7219(max7219Cascaded int, spiBus int, spiDevice int, brightness byte, toDisplay string) { + if Config.Global.Hardware.IO.Max7219.Enabled { + mtx := max7219.NewMatrix(max7219Cascaded) + err := mtx.Open(spiBus, spiDevice, brightness) + if err != nil { + log.Fatal(err) - //specific relay (Number Between 1 and TotalRelays) - if relayNo >= 0 && relayNo <= int(TotalRelays) { - if command == "on" { - log.Println("info: Relay ", relayNo, "On") - gpio.NewOutput(RelayPins[relayNo], false) - } - if command == "off" { - log.Println("info: Relay ", relayNo, "Off") - gpio.NewOutput(RelayPins[relayNo], true) - } - if command == "pulse" { - log.Println("info: Relay ", relayNo, "Pulse") - gpio.NewOutput(RelayPins[relayNo], false) - time.Sleep(RelayPulseMills * time.Millisecond) - gpio.NewOutput(RelayPins[relayNo], true) } + mtx.Device.SevenSegmentDisplay(toDisplay) + defer mtx.Close() } } diff --git a/gps.go b/gps.go index ef7cdae..9fef335 100644 --- a/gps.go +++ b/gps.go @@ -52,55 +52,69 @@ import ( "github.com/talkkonnect/go-nmea" ) +//GPS Related Global Variables +var ( + TraccarPortT55 string = "5005" // Old Traccar Client port 5005 for working with T55 Protocol + TraccarPortOpenGTS string = "5159" // Traccar Client port 5159 for for working OpenGTS Protocol + TraccarPortOsmAnd string = "5055" // Traccar Client port 5055 for working with OsmAnd Protocol + GPSTime string + GPSDate string + GPSLatitude float64 + GPSLongitude float64 + GPSSpeed float64 + GPSCourse float64 + GPSVariation float64 +) + var goodGPSRead bool = false func getGpsPosition(verbose bool) (bool, error) { - if GpsEnabled { + if Config.Global.Hardware.GPS.Enabled { - if Port == "" { + if Config.Global.Hardware.GPS.Port == "" { return false, errors.New("you must specify port") } - if Even && Odd { + if Config.Global.Hardware.GPS.Even && Config.Global.Hardware.GPS.Odd { return false, errors.New("cant specify both even and odd parity") } parity := serial.PARITY_NONE - if Even { + if Config.Global.Hardware.GPS.Even { parity = serial.PARITY_EVEN - } else if Odd { + } else if Config.Global.Hardware.GPS.Odd { parity = serial.PARITY_ODD } options := serial.OpenOptions{ - PortName: Port, - BaudRate: Baud, - DataBits: DataBits, - StopBits: StopBits, - MinimumReadSize: MinRead, - InterCharacterTimeout: CharTimeOut, + PortName: Config.Global.Hardware.GPS.Port, + BaudRate: Config.Global.Hardware.GPS.Baud, + DataBits: Config.Global.Hardware.GPS.DataBits, + StopBits: Config.Global.Hardware.GPS.StopBits, + MinimumReadSize: Config.Global.Hardware.GPS.MinRead, + InterCharacterTimeout: Config.Global.Hardware.GPS.CharTimeOut, ParityMode: parity, - Rs485Enable: Rs485, - Rs485RtsHighDuringSend: Rs485HighDuringSend, - Rs485RtsHighAfterSend: Rs485HighAfterSend, + Rs485Enable: Config.Global.Hardware.GPS.Rs485, + Rs485RtsHighDuringSend: Config.Global.Hardware.GPS.Rs485HighDuringSend, + Rs485RtsHighAfterSend: Config.Global.Hardware.GPS.Rs485HighAfterSend, } f, err := serial.Open(options) if err != nil { - GpsEnabled = false + Config.Global.Hardware.GPS.Enabled = false return false, errors.New("cannot open serial port") } else { defer f.Close() } - if TxData != "" { - txData, err := hex.DecodeString(TxData) + if Config.Global.Hardware.GPS.TxData != "" { + txData, err := hex.DecodeString(Config.Global.Hardware.GPS.TxData) if err != nil { - GpsEnabled = false + Config.Global.Hardware.GPS.Enabled = false return false, errors.New("cannot decode hex data") } @@ -116,7 +130,7 @@ func getGpsPosition(verbose bool) (bool, error) { } - if Rx { + if Config.Global.Hardware.GPS.Rx { serialPort, err := serial.Open(options) if err != nil { log.Println("warn: Unable to Open Serial Port Error ", err) @@ -138,11 +152,11 @@ func getGpsPosition(verbose bool) (bool, error) { if m.Latitude != 0 && m.Longitude != 0 { goodGPSRead = true - FreqReport := float64(TraccarReportFrequency) // Reporting Frequency - FreqReports := (time.Duration(TraccarReportFrequency) * time.Second) // Frequency of GPS Reporting. Minutes, Seconds or hours? + FreqReport := float64(Config.Global.Hardware.GPSTrackingFunction.TraccarReportFrequency) // Reporting Frequency + FreqReports := (time.Duration(Config.Global.Hardware.GPSTrackingFunction.TraccarReportFrequency) * time.Second) // Frequency of GPS Reporting. Minutes, Seconds or hours? - if TrackEnabled && TraccarSendTo { - if TraccarProto == "t55" { + if Config.Global.Hardware.GPSTrackingFunction.TrackEnabled && Config.Global.Hardware.GPSTrackingFunction.TraccarSendTo { + if Config.Global.Hardware.GPSTrackingFunction.TraccarProto == "t55" { go tcpSendT55Traccar2() // Initial Send GPS position to Traccar with old T55 client protocol. No keep-alive. } else { go httpSendTraccar() // Initial Send GPS position to Traccar over http function for both OsmAnd or OpenGTS protocol. @@ -154,8 +168,8 @@ func getGpsPosition(verbose bool) (bool, error) { var TraccarCounter = 1 go func() { for range PositionReporter.C { - if TrackEnabled && TraccarSendTo { - if TraccarProto == "t55" { + if Config.Global.Hardware.GPSTrackingFunction.TrackEnabled && Config.Global.Hardware.GPSTrackingFunction.TraccarSendTo { + if Config.Global.Hardware.GPSTrackingFunction.TraccarProto == "t55" { tcpSendT55Traccar2() // Send GPS position to Traccar with old T55 client protocol. No keep-alive. } else { httpSendTraccar() // Send GPS position to Traccar over http function for both OsmAnd or OpenGTS protocol. @@ -164,21 +178,21 @@ func getGpsPosition(verbose bool) (bool, error) { TraccarCounter++ if verbose { - if TrackEnabled && TraccarSendTo { - if TraccarProto == "osmand" { - log.Println("info: OsmAnd: ", TraccarServerURL+":"+fmt.Sprint(TraccarPortOsmAnd)+"?"+"id="+TraccarClientId+"&"+"timestamp="+date2()+"%20"+time2()+"&"+"lat="+fmt.Sprint(m.Latitude)+"&"+"lon="+fmt.Sprint(m.Longitude)+"&"+"speed="+fmt.Sprint(m.Speed)+"&"+"course="+fmt.Sprint(m.Course)+"&"+"variation="+fmt.Sprint(m.Variation)) - } else if TraccarProto == "t55" { - log.Println("info: T55: " + "Sending " + fmt.Sprint(m) + " to " + TraccarServerURL + ":" + fmt.Sprint(TraccarPortT55)) - } else if TraccarProto == "opengts" { - log.Println("info: OpenGTS: ", TraccarServerURL+":"+fmt.Sprint(TraccarPortOpenGTS)+"/?"+"id="+TraccarClientId+"&"+fmt.Sprint(m)) + if Config.Global.Hardware.GPSTrackingFunction.TrackEnabled && Config.Global.Hardware.GPSTrackingFunction.TraccarSendTo { + if Config.Global.Hardware.GPSTrackingFunction.TraccarProto == "osmand" { + log.Println("info: OsmAnd: ", Config.Global.Hardware.GPSTrackingFunction.TraccarServerURL+":"+fmt.Sprint(TraccarPortOsmAnd)+"?"+"id="+Config.Global.Hardware.GPSTrackingFunction.TraccarClientId+"&"+"timestamp="+date2()+"%20"+time2()+"&"+"lat="+fmt.Sprint(m.Latitude)+"&"+"lon="+fmt.Sprint(m.Longitude)+"&"+"speed="+fmt.Sprint(m.Speed)+"&"+"course="+fmt.Sprint(m.Course)+"&"+"variation="+fmt.Sprint(m.Variation)) + } else if Config.Global.Hardware.GPSTrackingFunction.TraccarProto == "t55" { + log.Println("info: T55: " + "Sending " + fmt.Sprint(m) + " to " + Config.Global.Hardware.GPSTrackingFunction.TraccarServerURL + ":" + fmt.Sprint(TraccarPortT55)) + } else if Config.Global.Hardware.GPSTrackingFunction.TraccarProto == "opengts" { + log.Println("info: OpenGTS: ", Config.Global.Hardware.GPSTrackingFunction.TraccarServerURL+":"+fmt.Sprint(TraccarPortOpenGTS)+"/?"+"id="+Config.Global.Hardware.GPSTrackingFunction.TraccarClientId+"&"+fmt.Sprint(m)) } log.Println("info: GPS Position Report Nr " + "(" + fmt.Sprint(TraccarCounter) + ")" + " Sent to Traccar Server. Next Position Report in " + fmt.Sprintf("%.2f", FreqReport/60) + " minute(s)") } } - if TargetBoard == "rpi" { - if TrackEnabled { - if TrackGPSShowLCD { + if Config.Global.Hardware.TargetBoard == "rpi" { + if Config.Global.Hardware.GPSTrackingFunction.TrackEnabled { + if Config.Global.Hardware.GPSTrackingFunction.TrackGPSShowLCD { log.Println("info: Showing GPS Info in LCD: " + "Lat: " + fmt.Sprint(m.Latitude) + " Long: " + fmt.Sprint(m.Longitude)) time.Sleep(5 * time.Second) t := time.Now() @@ -219,8 +233,8 @@ func getGpsPosition(verbose bool) (bool, error) { GPSCourse = m.Course GPSVariation = m.Variation - Date1 := fmt.Sprint(gpsdatereorder()) // Reformatted date for Tracar - Time1 := fmt.Sprintf("%s", truncateString(GPSTime, 8)) // Truncate time for Traccar + Date1 := fmt.Sprint(gpsdatereorder()) // Reformatted date for Tracar + Time1 := truncateString(GPSTime, 8) // Truncate time for Traccar currentTime := time.Now() //Date2 := fmt.Sprintf(currentTime.Format("2006-01-02")) @@ -247,25 +261,25 @@ func getGpsPosition(verbose bool) (bool, error) { log.Println("info: Speed: ", m.Speed) // Is this knots? log.Println("info: Course: ", m.Course) log.Println("info: Variation: ", m.Variation) - log.Println("info: Traccar Cmd Osmand: " + fmt.Sprint(TraccarServerFullURL)) + log.Println("info: Traccar Cmd Osmand: " + fmt.Sprint(Config.Global.Hardware.GPSTrackingFunction.TraccarServerFullURL)) log.Println("info: Traccar $GPRMC Sentence for T55/OpenGTS: " + fmt.Sprint(m)) - if TrackEnabled { + if Config.Global.Hardware.GPSTrackingFunction.TrackEnabled { //log.Println("info: GPS Tracking Enabled: " + fmt.Sprint(TrackEnabled)) - if TraccarSendTo { + if Config.Global.Hardware.GPSTrackingFunction.TraccarSendTo { log.Println("info: Sending GPS Position to Traccar Server Enabled") - log.Println("info: Traccar Protocol: " + strings.Title(strings.ToLower(TraccarProto)) + "; " + "Reporting Frequency: " + fmt.Sprintf("%.2f", FreqReport/60) + " minutes;") + log.Println("info: Traccar Protocol: " + strings.Title(strings.ToLower(Config.Global.Hardware.GPSTrackingFunction.TraccarProto)) + "; " + "Reporting Frequency: " + fmt.Sprintf("%.2f", FreqReport/60) + " minutes;") //Print GPS message format for sending to Traccar depending on tracking protocol. - switch TraccarProto { + switch Config.Global.Hardware.GPSTrackingFunction.TraccarProto { case "osmand": - log.Println("info: OsmAnd: ", TraccarServerFullURL) + log.Println("info: OsmAnd: ", Config.Global.Hardware.GPSTrackingFunction.TraccarServerFullURL) case "opengts": - log.Println("info: OpenGTS: ", TraccarServerIP) + log.Println("info: OpenGTS: ", Config.Global.Hardware.GPSTrackingFunction.TraccarServerIP) case "t55": - log.Println("info: T55:", fmt.Sprint(m), "...", TraccarServerURL+":"+TraccarPortT55) + log.Println("info: T55:", fmt.Sprint(m), "...", Config.Global.Hardware.GPSTrackingFunction.TraccarServerURL+":"+TraccarPortT55) default: - log.Println("info: OsmAnd: ", TraccarServerFullURL) + log.Println("info: OsmAnd: ", Config.Global.Hardware.GPSTrackingFunction.TraccarServerFullURL) } } } @@ -296,12 +310,12 @@ func getGpsPosition(verbose bool) (bool, error) { func tcpSendT55Traccar2() { - pgid := "$PGID" + "," + TraccarClientId + "*0F" + "\r" + "\n" // Unique Client ID (e.g. 12345). Follow with carriage return and line feed $ + pgid := "$PGID" + "," + Config.Global.Hardware.GPSTrackingFunction.TraccarClientId + "*0F" + "\r" + "\n" // Unique Client ID (e.g. 12345). Follow with carriage return and line feed $ gprmc := fmt.Sprint(m) + "\r" + "\n" log.Println("info: $GPRMC to send is: " + fmt.Sprint(m)) fmt.Println(m) - conn, _ := net.Dial("tcp", TraccarServerIP+":"+fmt.Sprint(TraccarPortT55)) // Use port 5005 for T55. Keep-alive. + conn, _ := net.Dial("tcp", Config.Global.Hardware.GPSTrackingFunction.TraccarServerIP+":"+fmt.Sprint(TraccarPortT55)) // Use port 5005 for T55. Keep-alive. err := conn.(*net.TCPConn).SetKeepAlive(true) if err != nil { fmt.Println(err) @@ -328,7 +342,7 @@ func tcpSendT55Traccar2() { fmt.Fprintf(conn, pgid) // Send ID time.Sleep(1 * time.Second) fmt.Fprintf(conn, gprmc) // send $GPRMC - log.Println("info: Sending position message to Traccar over Protocol: " + strings.Title(strings.ToLower(TraccarProto))) + log.Println("info: Sending position message to Traccar over Protocol: " + strings.Title(strings.ToLower(Config.Global.Hardware.GPSTrackingFunction.TraccarProto))) notify := make(chan error) @@ -367,26 +381,26 @@ func tcpSendT55Traccar2() { func httpSendTraccar() { - if TrackEnabled { - if TraccarSendTo { - if TraccarProto == "osmand" { - TraccarServerFullURL = (fmt.Sprint(TraccarServerURL) + ":" + fmt.Sprint(TraccarPortOsmAnd) + "?" + "id=" + TraccarClientId + "&" + "timestamp=" + date2() + "%20" + time2() + "&" + "lat=" + fmt.Sprintf("%f", GPSLatitude) + "&" + "lon=" + fmt.Sprintf("%f", GPSLongitude) + "&" + "speed=" + fmt.Sprintf("%f", GPSSpeed) + "&" + "course=" + fmt.Sprintf("%f", GPSCourse) + "&" + "variation=" + fmt.Sprintf("%f", GPSVariation)) - } else if TraccarProto == "opengts" { - TraccarServerFullURL = fmt.Sprint(TraccarServerURL) + ":" + fmt.Sprint(TraccarPortOpenGTS) + "/" + "?" + "id=" + TraccarClientId + "&" + "gprmc=" + fmt.Sprint(m) + if Config.Global.Hardware.GPSTrackingFunction.TrackEnabled { + if Config.Global.Hardware.GPSTrackingFunction.TraccarSendTo { + if Config.Global.Hardware.GPSTrackingFunction.TraccarProto == "osmand" { + Config.Global.Hardware.GPSTrackingFunction.TraccarServerFullURL = (fmt.Sprint(Config.Global.Hardware.GPSTrackingFunction.TraccarServerURL) + ":" + fmt.Sprint(TraccarPortOsmAnd) + "?" + "id=" + Config.Global.Hardware.GPSTrackingFunction.TraccarClientId + "&" + "timestamp=" + date2() + "%20" + time2() + "&" + "lat=" + fmt.Sprintf("%f", GPSLatitude) + "&" + "lon=" + fmt.Sprintf("%f", GPSLongitude) + "&" + "speed=" + fmt.Sprintf("%f", GPSSpeed) + "&" + "course=" + fmt.Sprintf("%f", GPSCourse) + "&" + "variation=" + fmt.Sprintf("%f", GPSVariation)) + } else if Config.Global.Hardware.GPSTrackingFunction.TraccarProto == "opengts" { + Config.Global.Hardware.GPSTrackingFunction.TraccarServerFullURL = fmt.Sprint(Config.Global.Hardware.GPSTrackingFunction.TraccarServerURL) + ":" + fmt.Sprint(TraccarPortOpenGTS) + "/" + "?" + "id=" + Config.Global.Hardware.GPSTrackingFunction.TraccarClientId + "&" + "gprmc=" + fmt.Sprint(m) } } } - response, err := http.Get(TraccarServerFullURL) + response, err := http.Get(Config.Global.Hardware.GPSTrackingFunction.TraccarServerFullURL) if err != nil { log.Println("error: Cannot Establish Connection with Traccar Server! Error ", err) currentTime := time.Now() - if TargetBoard == "rpi" { - if TrackEnabled { - if TrackGPSShowLCD { + if Config.Global.Hardware.TargetBoard == "rpi" { + if Config.Global.Hardware.GPSTrackingFunction.TrackEnabled { + if Config.Global.Hardware.GPSTrackingFunction.TrackGPSShowLCD { if LCDEnabled { LcdText = [4]string{"nil", "TRACK ERR1 " + currentTime.Format("15:04:05"), "nil", "nil"} go hd44780.LcdDisplay(LcdText, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress) @@ -418,9 +432,9 @@ func httpSendTraccar() { log.Println("info: HTTP Status Code from Traccar is in the 2xx range. This is OK.") currentTime := time.Now() - if TargetBoard == "rpi" { - if TrackEnabled { - if TrackGPSShowLCD { + if Config.Global.Hardware.TargetBoard == "rpi" { + if Config.Global.Hardware.GPSTrackingFunction.TrackEnabled { + if Config.Global.Hardware.GPSTrackingFunction.TrackGPSShowLCD { if LCDEnabled { LcdText = [4]string{"nil", "TRACK OK " + currentTime.Format("15:04:05"), "nil", "nil"} go hd44780.LcdDisplay(LcdText, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress) @@ -433,9 +447,9 @@ func httpSendTraccar() { } } else { currentTime := time.Now() - if TargetBoard == "rpi" { - if TrackEnabled { - if TrackGPSShowLCD { + if Config.Global.Hardware.TargetBoard == "rpi" { + if Config.Global.Hardware.GPSTrackingFunction.TrackEnabled { + if Config.Global.Hardware.GPSTrackingFunction.TrackGPSShowLCD { if LCDEnabled { LcdText = [4]string{"nil", "TRACK ERR2 " + currentTime.Format("15:04:05"), "nil", "nil"} go hd44780.LcdDisplay(LcdText, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress) @@ -470,13 +484,13 @@ func gpsdatereorder() string { func time2() string { currentTime := time.Now() - Time2 := fmt.Sprintf("%s", currentTime.Format("15:04:05")) + Time2 := currentTime.Format("15:04:05") return Time2 } // current date system func date2() string { currentTime := time.Now() - Date2 := fmt.Sprintf("%s", currentTime.Format("2006-01-02")) + Date2 := currentTime.Format("2006-01-02") return Date2 } diff --git a/htgotts.go b/htgotts.go index 005606b..e67b98c 100644 --- a/htgotts.go +++ b/htgotts.go @@ -28,20 +28,21 @@ package talkkonnect import ( "log" + "time" ) -func (b *Talkkonnect) Speak(text string, destination string, playBackVolume float32, duration float32, loop int, language string) { +func (b *Talkkonnect) Speak(text string, destination string, playBackVolume int, duration float32, loop int, language string) { generatedHashName := generateHashName(text) - fileNameWithPath := TTSSoundDirectory + "/" + generatedHashName + ".mp3" + fileNameWithPath := Config.Global.Software.TTSMessages.TTSSoundDirectory + "/" + generatedHashName + ".mp3" - createFolderIfNotExists(TTSSoundDirectory) + createFolderIfNotExists(Config.Global.Software.TTSMessages.TTSSoundDirectory) downloadIfNotExists(fileNameWithPath, text, language) if destination == "local" { - if FileExists(TTSAnnouncementTone) { - localMediaPlayer(TTSAnnouncementTone, playBackVolume, 10, 1) + if Config.Global.Software.TTSMessages.Enabled && FileExists(Config.Global.Software.TTSMessages.TTSTone.ToneFile) { + localMediaPlayer(Config.Global.Software.TTSMessages.TTSTone.ToneFile, Config.Global.Software.TTSMessages.TTSTone.ToneVolume, Config.Global.Software.TTSMessages.Blocking, 0, 1) } - localMediaPlayer(fileNameWithPath, playBackVolume, duration, loop) + localMediaPlayer(fileNameWithPath, playBackVolume, true, duration, loop) } if destination == "intostream" { @@ -56,30 +57,74 @@ func (b *Talkkonnect) Speak(text string, destination string, playBackVolume floa NowStreaming = IsPlayStream log.Println("info: Playing Recieved Text Message Into Stream as ", fileNameWithPath) - if FileExists(TTSAnnouncementTone) { - b.playIntoStream(TTSAnnouncementTone, StreamSoundVolume) + if Config.Global.Software.TTSMessages.TTSTone.ToneEnabled && FileExists(Config.Global.Software.TTSMessages.TTSTone.ToneFile) { + b.playIntoStream(Config.Global.Software.TTSMessages.TTSTone.ToneFile, float32(Config.Global.Software.TTSMessages.TTSTone.ToneVolume)) } - b.playIntoStream(fileNameWithPath, StreamSoundVolume) + b.playIntoStream(fileNameWithPath, Config.Global.Software.TTSMessages.PlayVolumeIntoStream) IsPlayStream = false NowStreaming = IsPlayStream + } + +} +func (b *Talkkonnect) TTSPlayerMessage(ttsMessage string, ttsLocalPlay bool, ttsPlayIntoStream bool) { + + if ttsLocalPlay { + if Config.Global.Software.TTSMessages.GPIO.Enabled { + GPIOOutPin(Config.Global.Software.TTSMessages.GPIO.Name, "on") + } + if Config.Global.Software.TTSMessages.PreDelay.Value.Seconds() > 0 { + time.Sleep(time.Duration(Config.Global.Software.TTSMessages.PreDelay.Value.Seconds())) + } + b.Speak(ttsMessage, "local", Config.Global.Software.TTS.Volumelevel, 0, 1, Config.Global.Software.TTSMessages.TTSLanguage) + if Config.Global.Software.TTSMessages.PostDelay.Value.Seconds() > 0 { + time.Sleep(time.Duration(Config.Global.Software.TTSMessages.PostDelay.Value.Seconds())) + } + if Config.Global.Software.TTSMessages.GPIO.Enabled { + GPIOOutPin(Config.Global.Software.TTSMessages.GPIO.Name, "off") + } } + if ttsPlayIntoStream { + b.Speak(ttsMessage, "intostream", Config.Global.Software.TTSMessages.SpeakVolumeIntoStream, 0, 1, Config.Global.Software.TTSMessages.TTSLanguage) + } } -func (b *Talkkonnect) TTSPlayer(ttsMessage string, ttsLocalPlay bool, ttsLocalPlayRXLed bool, ttlPlayIntoStream bool) { +func (b *Talkkonnect) TTSPlayerAPI(ttsMessage string, ttsLocalPlay bool, ttsPlayIntoStream bool, gpioEnabled bool, gpioName string, preDelay time.Duration, postDelay time.Duration, TTSLanguage string) { if ttsLocalPlay { - if ttsLocalPlayRXLed { - LEDOnFunc(VoiceActivityLED) + if gpioEnabled { + GPIOOutPin(gpioName, "on") } - b.Speak(ttsMessage, "local", 1, 0, 1, TTSLanguage) - if ttsLocalPlayRXLed { - LEDOffFunc(VoiceActivityLED) + if preDelay > 0 { + time.Sleep(preDelay) + } + b.Speak(ttsMessage, "local", Config.Global.Software.TTSMessages.SpeakVolumeIntoStream, 0, 1, TTSLanguage) + if postDelay > 0 { + time.Sleep(postDelay) + } + if gpioEnabled { + GPIOOutPin(gpioName, "off") } } - if ttlPlayIntoStream { - b.Speak(ttsMessage, "intostream", 1, 0, 1, TTSLanguage) + if ttsPlayIntoStream { + b.Speak(ttsMessage, "intostream", Config.Global.Software.TTSMessages.SpeakVolumeIntoStream, 0, 1, TTSLanguage) + } +} + +func TTSEvent(name string) { + if !Config.Global.Software.TTS.Enabled { + return + } + + for _, tts := range Config.Global.Software.TTS.Sound { + + if tts.Action == name { + if tts.Enabled { + localMediaPlayer(tts.File, Config.Global.Software.TTS.Volumelevel, tts.Blocking, 0, 1) + return + } + } } } diff --git a/httpapi.go b/httpapi.go index 1c17931..faf9568 100644 --- a/httpapi.go +++ b/httpapi.go @@ -30,244 +30,218 @@ package talkkonnect import ( + "errors" "fmt" "log" "net/http" + "reflect" "strconv" "strings" + "time" ) func (b *Talkkonnect) httpAPI(w http.ResponseWriter, r *http.Request) { - Commands, ok := r.URL.Query()["command"] - if !ok || len(Commands) < 1 { - log.Println("error: URL Param 'command' is missing example http api commands should be of the format http://a.b.c.d/?command=starttransmitting") - fmt.Fprintf(w, "error: API should be of the format http://a.b.c.d:"+APIListenPort+"/?command=StartTransmitting or of the format http://a.b.c.d:"+APIListenPort+"?command=setvoicetarget&id=0\n") + + funcs := map[string]interface{}{ + "displaymenu": b.cmdDisplayMenu, + "channelup": b.cmdChannelUp, + "channeldown": b.cmdChannelDown, + "mute-toggle": b.cmdMuteUnmute, + "mute": b.cmdMuteUnmute, + "unmute": b.cmdMuteUnmute, + "currentvolume": b.cmdCurrentVolume, + "volumeup": b.cmdVolumeUp, + "volumedown": b.cmdVolumeDown, + "listserverchannels": b.cmdListServerChannels, + "starttransmitting": b.cmdStartTransmitting, + "stoptransmitting": b.cmdStopTransmitting, + "listonlineusers": b.cmdListOnlineUsers, + "playback": b.cmdPlayback, + "gpsposition": b.cmdGPSPosition, + "sendemail": b.cmdSendEmail, + "previousserver": b.cmdConnPreviousServer, + "connnextserver": b.cmdConnNextServer, + "clearscreen": b.cmdClearScreen, + "pingservers": b.cmdPingServers, + "panicsimulation": b.cmdPanicSimulation, + "repeattxloop": b.cmdRepeatTxLoop, + "scanchannels": b.cmdScanChannels, + "thanks": cmdThanks, + "showuptime": b.cmdShowUptime, + "showversion": b.cmdDisplayVersion, + "dumpxmlconfig": b.cmdDumpXMLConfig, + "ttsannouncement": b.TTSPlayerAPI, + "voicetargetset": b.cmdSendVoiceTargets, + "listapi": listAPI} + + APICommands, ok := r.URL.Query()["command"] + + if !ok || len(APICommands[0]) < 1 { + log.Println("error: URL Param 'command' is missing example http API commands should be of the format http://a.b.c.d/?command=listapi") + fmt.Fprintf(w, "error: API should be of the format http://a.b.c.d:"+Config.Global.Software.RemoteControl.HTTP.ListenPort+"/?command=StartTransmitting or of the format http://a.b.c.d:"+Config.Global.Software.RemoteControl.HTTP.ListenPort+"?command=setvoicetarget&id=0\n") return } - var Command string - var ID int + var APIID int + var APITTSMessage string + var APITTSLocalPlay bool + var APITTSPlayIntoStream bool + var APIGPIOEnabled bool + var APIGPIOName string + var APIPreDelay int + var APIPostDelay int + var APILanguage string var err error + APICommand := strings.ToLower(APICommands[0]) + APIDefined := false + for _, apicommand := range Config.Global.Software.RemoteControl.HTTP.Command { + if APICommand == "listapi" && apicommand.Enabled { + fmt.Fprintf(w, "200 OK: API Command %v for %v Control Available\n", apicommand.Action, apicommand.Message) + } + if apicommand.Action == APICommand { + APIDefined = true + } + } + + if !APIDefined { + log.Printf("error: API Command %v Not A Valid Defined Command\n", APICommand) + fmt.Fprintf(w, "404 error: API Command %v Not A Valid Defined Command\n", APICommand) + return + } + for key, values := range r.URL.Query() { if strings.ToLower(key) == "command" { - Command = values[0] + APICommand = values[0] } + if strings.ToLower(key) == "id" { - ID, err = strconv.Atoi(values[0]) + APIID, err = strconv.Atoi(values[0]) if err != nil { log.Println("error: Target ID is not Number") - fmt.Fprintf(w, "API VoiceTarget ID is not Number\n") + fmt.Fprintf(w, "404 error: API VoiceTarget ID is not Number\n") return } } - } - log.Println("debug: http command " + string(Command)) - log.Println("debug: http parameters ", ID) - - b.BackLightTimer() - - switch string(strings.ToLower(Command)) { - case "displaymenu": - if APIDisplayMenu { - b.cmdDisplayMenu() - fmt.Fprintf(w, "API Display Menu Request Processed Successfully\n") - } else { - fmt.Fprintf(w, "API Display Menu Request Denied\n") - } - case "channelup": - if APIChannelUp { - b.cmdChannelUp() - fmt.Fprintf(w, "API Channel Up Request Processed Successfully\n") - } else { - fmt.Fprintf(w, "API Channel Up Request Denied\n") - } - case "channeldown": - if APIChannelDown { - b.cmdChannelDown() - fmt.Fprintf(w, "API Channel Down Request Processed Successfully\n") - } else { - fmt.Fprintf(w, "API Channel Down Request Denied\n") - } - case "mute-toggle": - if APIMute { - b.cmdMuteUnmute("toggle") - fmt.Fprintf(w, "API Mute/UnMute Speaker Request Processed Successfully\n") - } else { - fmt.Fprintf(w, "API Mute/Unmute Speaker Request Denied\n") - } - case "mute": - if APIMute { - b.cmdMuteUnmute("mute") - fmt.Fprintf(w, "API Mute/UnMute Speaker Request Processed Successfully\n") - } else { - fmt.Fprintf(w, "API Mute/Unmute Speaker Request Denied\n") - } - case "unmute": - if APIMute { - b.cmdMuteUnmute("unmute") - fmt.Fprintf(w, "API Mute/UnMute Speaker Request Processed Successfully\n") - } else { - fmt.Fprintf(w, "API Mute/Unmute Speaker Request Denied\n") - } - case "currentvolume": - if APICurrentVolumeLevel { - b.cmdCurrentVolume() - fmt.Fprintf(w, "API Current Volume Level Request Processed Successfully\n") - } else { - fmt.Fprintf(w, "API Current Volume Level Request Denied\n") - } - case "volumeup": - if APIDigitalVolumeUp { - b.cmdVolumeUp() - fmt.Fprintf(w, "API Digital Volume Up Request Processed Successfully\n") - } else { - fmt.Fprintf(w, "API Digital Volume Up Request Denied\n") - } - case "volumedown": - if APIDigitalVolumeDown { - b.cmdVolumeDown() - fmt.Fprintf(w, "API Digital Volume Down Request Processed Successfully\n") - } else { - fmt.Fprintf(w, "API Digital Volume Down Request Denied\n") - } - case "listchannels": - if APIListServerChannels { - b.cmdListServerChannels() - fmt.Fprintf(w, "API List Server Channels Request Processed Successfully\n") - } else { - fmt.Fprintf(w, "API List Server Channels Request Denied\n") - } - case "starttransmitting": - if APIStartTransmitting { - b.cmdStartTransmitting() - fmt.Fprintf(w, "API Start Transmitting Request Processed Successfully\n") - } else { - fmt.Fprintf(w, "API Start Transmitting Request Denied\n") - } - case "stoptransmitting": - if APIStopTransmitting { - b.cmdStopTransmitting() - fmt.Fprintf(w, "API Stop Transmitting Request Processed Successfully\n") - } else { - fmt.Fprintf(w, "API Stop Transmitting Request Denied\n") - } - case "listonlineusers": - if APIListOnlineUsers { - b.cmdListOnlineUsers() - fmt.Fprintf(w, "API List Online Users Request Processed Successfully\n") - } else { - fmt.Fprintf(w, "API List Online Users Request Denied\n") - } - case "stream-toggle": - if APIPlayStream { - b.cmdPlayback() - fmt.Fprintf(w, "API Play/Stop Stream Request Processed Successfully\n") - } else { - fmt.Fprintf(w, "API Play/Stop Stream Request Denied\n") - } - case "gpsposition": - if APIRequestGpsPosition { - b.cmdGPSPosition() - fmt.Fprintf(w, "API Request GPS Position Processed Successfully\n") - } else { - fmt.Fprintf(w, "API Request GPS Position Denied\n") + if strings.ToLower(key) == "ttsmessage" { + APITTSMessage = values[0] } - case "sendemail": - if APIEmailEnabled { - b.cmdSendEmail() - fmt.Fprintf(w, "API Send Email Processed Successfully\n") - } else { - fmt.Fprintf(w, "API Send Email Config Denied\n") - } - case "connpreviousserver": - if APINextServer { - b.cmdConnPreviousServer() - fmt.Fprintf(w, "API Previous Server Processed Successfully\n") - } else { - fmt.Fprintf(w, "API Previous Server Denied\n") - } - case "connnextserver": - if APINextServer { - b.cmdConnNextServer() - fmt.Fprintf(w, "API Next Server Processed Successfully\n") - } else { - fmt.Fprintf(w, "API Next Server Denied\n") + if strings.ToLower(key) == "ttslocalplay" { + var temp string = values[0] + if strings.ToLower(temp) == "true" { + APITTSLocalPlay = true + } + if strings.ToLower(temp) == "false" { + APITTSLocalPlay = false + } } - case "clearscreen": - if APIClearScreen { - b.cmdClearScreen() - fmt.Fprintf(w, "API Clear Screen Processed Successfully\n") - } else { - fmt.Fprintf(w, "API Clear Screen Denied\n") - } - case "pingservers": - if APIEmailEnabled { - b.cmdPingServers() - fmt.Fprintf(w, "API Ping Servers Processed Successfully\n") - } else { - fmt.Fprintf(w, "API Ping Servers Denied\n") - } - case "panicsimulation": - if APIPanicSimulation { - b.cmdPanicSimulation() - fmt.Fprintf(w, "API Request Panic Simulation Processed Successfully\n") - } else { - fmt.Fprintf(w, "API Request Panic Simulation Denied\n") - } - case "repeattxloop": - if APIRepeatTxLoopTest { - b.cmdRepeatTxLoop() - fmt.Fprintf(w, "API Request Repeat Tx Loop Test Processed Successfully\n") - } else { - fmt.Fprintf(w, "API Request Repeat Tx Loop Test Denied\n") + if strings.ToLower(key) == "playintostream" { + var temp string = values[0] + if strings.ToLower(temp) == "true" { + APITTSPlayIntoStream = true + } + if strings.ToLower(temp) == "false" { + APITTSPlayIntoStream = false + } } - case "scanchannels": - if APIScanChannels { - b.cmdScanChannels() - fmt.Fprintf(w, "API Request Scan Processed Successfully\n") - } else { - fmt.Fprintf(w, "API Request Scan Denied\n") + + if strings.ToLower(key) == "gpioenabled" { + var temp string = values[0] + if strings.ToLower(temp) == "true" { + APIGPIOEnabled = true + } + if strings.ToLower(temp) == "false" { + APIGPIOEnabled = false + } } - case "thanks": - if true { - b.cmdThanks() - fmt.Fprintf(w, "API Request Show Acknowledgements Processed Successfully\n") - } else { - fmt.Fprintf(w, "API Request Show Acknowledgements Denied\n") + + if strings.ToLower(key) == "gpioname" { + APIGPIOName = values[0] } - case "showuptime": - if APIDisplayVersion { - b.cmdShowUptime() - fmt.Fprintf(w, "API Request Current Version Successfully\n") - } else { - fmt.Fprintf(w, "API Request Current Version Denied\n") + + if strings.ToLower(key) == "predelay" { + APIPreDelay, err = strconv.Atoi(values[0]) + if err != nil { + log.Println("error: PreDelay is not Number") + fmt.Fprintf(w, "404 error: API PreDelay is not Number\n") + return + } } - case "dumpxmlconfig": - if APIPrintXmlConfig { - b.cmdDumpXMLConfig() - fmt.Fprintf(w, "API Print XML Config Processed Successfully\n") - } else { - fmt.Fprintf(w, "API Print XML Config Denied\n") + + if strings.ToLower(key) == "postdelay" { + APIPostDelay, err = strconv.Atoi(values[0]) + if err != nil { + log.Println("error: PostDelay is not Number") + fmt.Fprintf(w, "404 error: API PostDelay is not Number\n") + return + } } - case "playrepeatertone": - if APIPlayRepeaterTone { - b.cmdPlayRepeaterTone() - fmt.Fprintf(w, "API Play Repeater Tone Processed Successfully\n") - } else { - fmt.Fprintf(w, "API Play Repeater Tone Denied\n") + + if strings.ToLower(key) == "language" { + APILanguage = values[0] } - case "setvoicetarget": - if APISetVoiceTarget { - fmt.Fprintf(w, "API Set Voice Target to ID %v Processed Successfully\n", ID) - b.cmdSendVoiceTargets(uint32(ID)) - } else { - fmt.Fprintf(w, "API Set Voice Target Denied\n") + + } + + for _, apicommand := range Config.Global.Software.RemoteControl.HTTP.Command { + if apicommand.Action == APICommand { + if len(apicommand.Funcparamname) == 0 { + _, err := b.Call(funcs, apicommand.Action) + if err != nil { + log.Println("error: Wrong Parameters to Call Function") + } else { + fmt.Fprintf(w, "200 OK: http command %v OK \n", APICommand) + } + } else { + if apicommand.Funcparamname != "value" { + _, err := b.Call(funcs, apicommand.Action, apicommand.Funcparamname) + if err != nil { + log.Println("error: Wrong Parameters to Call Function") + } else { + fmt.Fprintf(w, "200 OK: http command %v For %v Control\n", apicommand.Action, apicommand.Message) + } + } else { + switch APICommand { + case "voicetargetset": + _, err := b.Call(funcs, apicommand.Action, uint32(APIID)) + if err != nil { + log.Println("error: Wrong Parameters to Call Function") + } else { + fmt.Fprintf(w, "200 OK: http command %v OK \n", APICommand) + } + case "ttsannouncement": + _, err := b.Call(funcs, apicommand.Action, APITTSMessage, APITTSLocalPlay, APITTSPlayIntoStream, APIGPIOEnabled, APIGPIOName, time.Duration(APIPreDelay*int(time.Second)), time.Duration(APIPostDelay)*time.Second, APILanguage) + if err != nil { + log.Println("error: Wrong Parameters to Call Function") + } else { + fmt.Fprintf(w, "200 OK: http command %v OK \n", APICommand) + } + } + } + } } - default: - fmt.Fprintf(w, "API Command Not Defined\n") + } +} + +func (b *Talkkonnect) Call(m map[string]interface{}, name string, params ...interface{}) (result []reflect.Value, err error) { + f := reflect.ValueOf(m[name]) + if len(params) != f.Type().NumIn() { + err = errors.New("the number of params is not adapted") + return + } + in := make([]reflect.Value, len(params)) + for k, param := range params { + in[k] = reflect.ValueOf(param) + } + result = f.Call(in) + return +} + +func listAPI() { + for _, apicommand := range Config.Global.Software.RemoteControl.HTTP.Command { + log.Printf("info: API Command %v for %v Control Available\n", apicommand.Action, apicommand.Message) } } diff --git a/ledstrip.go b/ledstrip.go index a6a4f5e..90e726b 100644 --- a/ledstrip.go +++ b/ledstrip.go @@ -31,6 +31,7 @@ package talkkonnect import ( + "errors" "log" "strconv" @@ -104,6 +105,9 @@ func NewLedStrip() (*LedStrip, error) { } func (ls *LedStrip) ledCtrl(num int, color string) error { + if !Config.Global.Hardware.LedStripEnabled { + return errors.New("LedStrip Not Enabled in Config") + } rgb, err := strconv.ParseUint(color, 16, 32) if err != nil { return err diff --git a/media.go b/media.go index 31cd2b9..f3e2920 100644 --- a/media.go +++ b/media.go @@ -33,15 +33,14 @@ package talkkonnect import ( "bytes" - "errors" "fmt" "log" "os/exec" "strconv" - - "github.com/talkkonnect/gumble/gumbleffmpeg" + "time" ) +/* func aplayLocal(filepath string, playbackvolume float32) error { var player string @@ -65,53 +64,32 @@ func aplayLocal(filepath string, playbackvolume float32) error { return nil } +*/ -func localMediaPlayer(fileNameWithPath string, playbackvolume float32, duration float32, loop int) { +func localMediaPlayer(fileNameWithPath string, playbackvolume int, blocking bool, duration float32, loop int) { if loop == 0 || loop > 3 { log.Println("warn: Infinite Loop or more than 3 loops not allowed") return } - CmdArguments := []string{fileNameWithPath, "-af", "volume=" + fmt.Sprintf("%1.1f", playbackvolume), "-autoexit", "-loop", strconv.Itoa(loop), "-autoexit", "-nodisp"} + CmdArguments := []string{fileNameWithPath, "-volume", strconv.Itoa(playbackvolume), "-autoexit", "-loop", strconv.Itoa(loop), "-autoexit", "-nodisp"} if duration > 0 { - CmdArguments = []string{fileNameWithPath, "-af", "volume=" + fmt.Sprintf("%1.1f", playbackvolume), "-autoexit", "-t", fmt.Sprintf("%.1f", duration), "-loop", strconv.Itoa(loop), "-autoexit", "-nodisp"} + CmdArguments = []string{fileNameWithPath, "-volume", strconv.Itoa(playbackvolume), "-autoexit", "-t", fmt.Sprintf("%.1f", duration), "-loop", strconv.Itoa(loop), "-autoexit", "-nodisp"} } cmd := exec.Command("/usr/bin/ffplay", CmdArguments...) - cmd.Run() - -} -func (b *Talkkonnect) playIntoStream(filepath string, vol float32) { - if !IsPlayStream { - log.Println(fmt.Sprintf("info: File %s Stopped!", filepath)) - pstream.Stop() - LEDOffFunc(TransmitLED) - return - } - - if StreamSoundEnabled && IsPlayStream { - if pstream != nil && pstream.State() == gumbleffmpeg.StatePlaying { - pstream.Stop() - return + WaitForFFPlay := make(chan struct{}) + go func() { + cmd.Run() + if blocking { + WaitForFFPlay <- struct{}{} // signal that the routine has completed } - - LEDOnFunc(TransmitLED) - - IsPlayStream = true - pstream = gumbleffmpeg.New(b.Client, gumbleffmpeg.SourceFile(filepath), vol) - if err := pstream.Play(); err != nil { - log.Println(fmt.Sprintf("error: Can't play %s error %s", filepath, err)) - } else { - log.Println(fmt.Sprintf("info: File %s Playing!", filepath)) - pstream.Wait() - pstream.Stop() - LEDOffFunc(TransmitLED) - } - } else { - log.Println("warn: Sound Disabled by Config") + }() + if blocking { + <-WaitForFFPlay } } @@ -125,22 +103,68 @@ func (b *Talkkonnect) PlayTone(toneFreq int, toneDuration int, destination strin cmd.Stdout = &out if withRXLED { - LEDOnFunc(VoiceActivityLED) + GPIOOutPin("voiceactivity", "on") } err := cmd.Run() if err != nil { log.Println("error: ffplay error ", err) if withRXLED { - LEDOffFunc(VoiceActivityLED) + GPIOOutPin("voiceactivity", "off") } return } if withRXLED { - LEDOffFunc(VoiceActivityLED) + GPIOOutPin("voiceactivity", "off") } - log.Println("info: Played Tone at Frequency " + strconv.Itoa(RepeaterToneFrequencyHz) + " Hz With Duration of " + strconv.Itoa(RepeaterToneDurationSec) + " Seconds For Opening Repeater") + log.Printf("info: Played Tone at Frequency %v Hz With Duration of %v Seconds For Opening Repeater", toneFreq, toneDuration) + } +} +func playAnnouncementMedia(id int) { + + for _, multimedia := range Config.Global.Multimedia.ID { + apiid, err := strconv.Atoi(multimedia.Value) + if apiid == id && err == nil { + if multimedia.Params.Localplay { + if multimedia.Params.GPIO.Enabled { + GPIOOutPin(multimedia.Params.GPIO.Name, "on") + } + if multimedia.Params.Predelay.Enabled && multimedia.Params.Predelay.Value > 0 { + time.Sleep(multimedia.Params.Predelay.Value * time.Second) + } + if multimedia.Params.Announcementtone.Enabled && FileExists(multimedia.Params.Announcementtone.File) { + localMediaPlayer(multimedia.Params.Announcementtone.File, multimedia.Params.Announcementtone.Volume, multimedia.Params.Announcementtone.Blocking, 0, 1) //todo replace 1 with volume from xmlconfig + } + for _, source := range multimedia.Media.Source { + if source.Enabled { + log.Printf("debug: Playing %v filename %v\n", source.Name, source.File) + localMediaPlayer(source.File, source.Volume, multimedia.Params.Announcementtone.Blocking, source.Duration, source.Loop) + } + } + if multimedia.Params.Postdelay.Enabled && multimedia.Params.Postdelay.Value > 0 { + time.Sleep(multimedia.Params.Postdelay.Value * time.Second) + } + if multimedia.Params.GPIO.Enabled { + GPIOOutPin(multimedia.Params.GPIO.Name, "off") + } + } + if multimedia.Params.Playintostream { + log.Println("todo play into stream") + } + } } + // Config.Global.Multimedia.Params.Playintostream + // Config.Global.Multimedia.Params.Voicetarget + +} + +func findEventSound(findEventSound string) EventSoundStruct { + for _, sound := range Config.Global.Software.Sounds.Sound { + if sound.Enabled && sound.Event == findEventSound { + return EventSoundStruct{sound.Enabled, sound.File, sound.Volume, sound.Blocking} + } + } + return EventSoundStruct{false, "", "0", false} } diff --git a/mqtt.go b/mqtt.go index 9a16ed2..3916a46 100644 --- a/mqtt.go +++ b/mqtt.go @@ -47,7 +47,6 @@ package talkkonnect import ( "crypto/tls" - "fmt" "log" "os" "os/signal" @@ -62,26 +61,26 @@ import ( func (b *Talkkonnect) mqttsubscribe() { log.Printf("info: MQTT Subscription Information") - log.Printf("info: MQTT Broker : %s\n", MQTTBroker) - log.Printf("debug: MQTT clientid : %s\n", MQTTId) - log.Printf("debug: MQTT user : %s\n", MQTTUser) - log.Printf("debug: MQTT password : %s\n", MQTTPassword) - log.Printf("info: Subscribed topic : %s\n", MQTTTopic) + log.Printf("info: MQTT Broker : %s\n", Config.Global.Software.RemoteControl.MQTT.Settings.MQTTBroker) + log.Printf("debug: MQTT clientid : %s\n", Config.Global.Software.RemoteControl.MQTT.Settings.MQTTId) + log.Printf("debug: MQTT user : %s\n", Config.Global.Software.RemoteControl.MQTT.Settings.MQTTUser) + log.Printf("debug: MQTT password : %s\n", Config.Global.Software.RemoteControl.MQTT.Settings.MQTTPassword) + log.Printf("info: Subscribed topic : %s\n", Config.Global.Software.RemoteControl.MQTT.Settings.MQTTTopic) c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM) - connOpts := MQTT.NewClientOptions().AddBroker(MQTTBroker).SetClientID(MQTTId).SetCleanSession(true) - if MQTTUser != "" { - connOpts.SetUsername(MQTTUser) - if MQTTPassword != "" { - connOpts.SetPassword(MQTTPassword) + connOpts := MQTT.NewClientOptions().AddBroker(Config.Global.Software.RemoteControl.MQTT.Settings.MQTTBroker).SetClientID(Config.Global.Software.RemoteControl.MQTT.Settings.MQTTId).SetCleanSession(true) + if Config.Global.Software.RemoteControl.MQTT.Settings.MQTTUser != "" { + connOpts.SetUsername(Config.Global.Software.RemoteControl.MQTT.Settings.MQTTUser) + if Config.Global.Software.RemoteControl.MQTT.Settings.MQTTPassword != "" { + connOpts.SetPassword(Config.Global.Software.RemoteControl.MQTT.Settings.MQTTPassword) } } tlsConfig := &tls.Config{InsecureSkipVerify: true, ClientAuth: tls.NoClientCert} connOpts.SetTLSConfig(tlsConfig) connOpts.OnConnect = func(c MQTT.Client) { - if token := c.Subscribe(MQTTTopic, byte(MQTTQos), b.onMessageReceived); token.Wait() && token.Error() != nil { + if token := c.Subscribe(Config.Global.Software.RemoteControl.MQTT.Settings.MQTTTopic, byte(Config.Global.Software.RemoteControl.MQTT.Settings.MQTTQos), b.onMessageReceived); token.Wait() && token.Error() != nil { panic(token.Error()) } } @@ -90,147 +89,170 @@ func (b *Talkkonnect) mqttsubscribe() { if token := client.Connect(); token.Wait() && token.Error() != nil { panic(token.Error()) } else { - log.Printf("info: Connected to : %s\n", MQTTBroker) + log.Printf("info: Connected to : %s\n", Config.Global.Software.RemoteControl.MQTT.Settings.MQTTBroker) } <-c } func (b *Talkkonnect) onMessageReceived(client MQTT.Client, message MQTT.Message) { - log.Printf("info: Received MQTT message on topic: %s Payload: %s\n", message.Topic(), message.Payload()) - PayLoad := strings.ToLower(string(message.Payload())) + var ( + CommandDefined bool + PayLoad string + ) - var ID int - var err error + funcs := map[string]interface{}{ + "displaymenu": b.cmdDisplayMenu, + "channelup": b.cmdChannelUp, + "channeldown": b.cmdChannelDown, + "muteunmute": b.cmdMuteUnmute, + "currentvolume": b.cmdCurrentVolume, + "volumeup": b.cmdVolumeUp, + "volumedown": b.cmdVolumeDown, + "listserverchannels": b.cmdListServerChannels, + "starttransmitting": b.cmdStartTransmitting, + "stoptransmitting": b.cmdStopTransmitting, + "listonlineusers": b.cmdListOnlineUsers, + "playback": b.cmdPlayback, + "gpsposition": b.cmdGPSPosition, + "sendemail": b.cmdSendEmail, + "previousserver": b.cmdConnPreviousServer, + "connnextserver": b.cmdConnNextServer, + "clearscreen": b.cmdClearScreen, + "pingservers": b.cmdPingServers, + "panicsimulation": b.cmdPanicSimulation, + "repeattxloop": b.cmdRepeatTxLoop, + "scanchannels": b.cmdScanChannels, + "thanks": cmdThanks, + "showuptime": b.cmdShowUptime, + "dumpxmlconfig": b.cmdDumpXMLConfig, + "voicetargetset": b.cmdSendVoiceTargets, + "attention": attention, + "relay": relay} - if strings.Contains(PayLoad, "voicetargetset") { - if strings.Contains(PayLoad, ":") { - IDString := fmt.Sprintf("%v", PayLoad[15:]) - ID, err = strconv.Atoi(IDString) - if err != nil { - log.Println("error: Target is ID not a number") - return - } - if ID >= 0 && ID <= 31 { - b.cmdSendVoiceTargets(uint32(ID)) - log.Printf("info: MQTT SetTargetID %v Request Processed Successfully\n", IDString) - return - } else { - log.Println("error: Target ID NOT in Valid Range") - return + PayLoad = strings.ToLower(string(message.Payload())) + log.Printf("info: Received MQTT message on topic: %s Payload: %s\n", message.Topic(), PayLoad) + + for _, mqttcommand := range Config.Global.Software.RemoteControl.MQTT.Commands.Command { + if strings.Contains(PayLoad, strings.ToLower(mqttcommand.Action)) { + CommandDefined = true + } + } + + if !CommandDefined { + log.Printf("error: MQTT Command %v Not Defined\n", PayLoad) + return + } + + Command := []string{} + Command = strings.Split(strings.ToLower(PayLoad), ":") + + for _, mqttcommand := range Config.Global.Software.RemoteControl.MQTT.Commands.Command { + if strings.Contains(Command[0], mqttcommand.Action) { + if mqttcommand.Enabled { + var Err error + switch Command[0] { + case "muteunmute": + if len(Command) == 2 { + if Command[1] == "toggle" { + _, Err = b.Call(funcs, mqttcommand.Action, "mute-toggle") + } + if Command[1] == "mute" { + _, Err = b.Call(funcs, mqttcommand.Action, "mute") + } + if Command[1] == "unmute" { + _, Err = b.Call(funcs, mqttcommand.Action, "unmute") + } + } else { + log.Println("error: Malformed MQTT Command") + } + case "attention": + if len(Command) == 2 { + if Command[1] == "blink" { + _, Err = b.Call(funcs, mqttcommand.Action, "blink") + } + if Command[1] == "on" { + _, Err = b.Call(funcs, mqttcommand.Action, "on") + } + if Command[1] == "off" { + _, Err = b.Call(funcs, mqttcommand.Action, "off") + } + } else { + log.Println("error: Malformed MQTT Command") + } + case "relay": + if len(Command) == 3 { + if Command[2] == "pulse" { + _, Err = b.Call(funcs, mqttcommand.Action, "pulse", Command[3]) + } + if Command[2] == "on" { + _, Err = b.Call(funcs, mqttcommand.Action, "on", Command[3]) + } + if Command[2] == "off" { + _, Err = b.Call(funcs, mqttcommand.Action, "off", Command[3]) + } + } else { + log.Println("error: Malformed MQTT Command") + } + case "voicetargetset": + if len(Command) == 2 { + id, err := strconv.Atoi(Command[1]) + if err != nil { + return + } + if id < 32 { + _, Err = b.Call(funcs, mqttcommand.Action, uint32(id)) + } else { + log.Println("error: Value of Target ID Not In Range (0-31) ", id) + } + } else { + log.Println("error: Malformed MQTT Command") + } + default: + if len(Command) == 1 { + _, Err = b.Call(funcs, mqttcommand.Action) + } + } + + if Err == nil { + log.Printf("MQTT Command %v Processed", Command) + } else { + log.Printf("error: MQTT Command %v Failed", Command) + } } } } +} - switch PayLoad { - case "displaymenu": - log.Println("info: MQTT Display Menu Request Processed Successfully") - b.cmdDisplayMenu() - case "channelup": - log.Println("info: MQTT Channel Up Request Processed Successfully") - b.cmdChannelUp() - case "channeldown": - log.Println("info: MQTT Channel Down Request Processed Successfully") - b.cmdChannelDown() - case "mute-toggle": - log.Println("info: MQTT Mute/UnMute Speaker Request Processed Successfully") - b.cmdMuteUnmute("toggle") - case "mute": - log.Println("info: MQTT Mute/UnMute Speaker Request Processed Successfully") - b.cmdMuteUnmute("mute") - case "unmute": - log.Println("info: MQTT Mute/UnMute Speaker Request Processed Successfully") - b.cmdMuteUnmute("unmute") - case "currentvolume": - log.Println("info: MQTT Current Volume Level Request Processed Successfully") - b.cmdCurrentVolume() - case "volumeup": - log.Println("info: MQTT Digital Volume Up Request Processed Successfully") - b.cmdVolumeUp() - case "volumedown": - log.Println("info: MQTT Digital Volume Down Request Processed Successfully") - b.cmdVolumeDown() - case "listchannels": - log.Println("info: MQTT List Server Channels Request Processed Successfully") - b.cmdListServerChannels() - case "starttransmitting": - log.Println("info: MQTT Start Transmitting Request Processed Successfully") - b.cmdStartTransmitting() - case "stoptransmitting": - log.Println("info: MQTT Stop Transmitting Request Processed Successfully") - b.cmdStopTransmitting() - case "listonlineusers": - log.Println("info: MQTT List Online Users Request Processed Successfully") - b.cmdListOnlineUsers() - case "stream-toggle": - log.Println("info: MQTT Play/Stop Stream Request Processed Successfully") - b.cmdPlayback() - case "gpsposition": - log.Println("info: MQTT Request GPS Position Processed Successfully") - b.cmdGPSPosition() - case "sendemail": - log.Println("info: MQTT Send Email Processed Successfully") - b.cmdSendEmail() - case "connpreviousserver": - log.Println("info: MQTT Previous Server Processed Successfully") - b.cmdConnPreviousServer() - case "connnextserver": - log.Println("info: MQTT Next Server Processed Successfully") - b.cmdConnNextServer() - case "clearscreen": - log.Println("info: MQTT Clear Screen Processed Successfully") - b.cmdClearScreen() - case "pingservers": - log.Println("info: MQTT Ping Servers Processed Successfully") - b.cmdPingServers() - case "panicsimulation": - log.Println("info: MQTT Request Panic Simulation Processed Successfully") - b.cmdPanicSimulation() - case "repeattxLoop": - log.Println("info: MQTT Request Repeat Tx Loop Test Processed Successfully") - b.cmdRepeatTxLoop() - case "scanchannels": - log.Println("info: MQTT Request Scan Processed Successfully") - b.cmdScanChannels() - case "thanks": - log.Println("info: MQTT Request Show Acknowledgements Processed Successfully") - b.cmdThanks() - case "showuptime": - log.Println("info: MQTT Request Current Version Successfully") - b.cmdShowUptime() - case "dumpxmlconfig": - log.Println("info: MQTT Print XML Config Processed Successfully") - b.cmdDumpXMLConfig() - case "attentionled:on": - log.Println("info: MQTT Turn On Attention LED Successfully") - LEDOnFunc(AttentionLED) - case "attentionled:off": - log.Println("info: MQTT Turn Off Attention LED Successfully") - LEDOffFunc(AttentionLED) - case "attentionled:blink": - log.Println("info: MQTT Blink Attention LED 20 times Successfully") - for i := 0; i < MQTTAttentionBlinkTimes; i++ { - LEDOnFunc(AttentionLED) - time.Sleep(time.Duration(MQTTAttentionBlinkmsecs) * time.Millisecond) - LEDOffFunc(AttentionLED) - time.Sleep(time.Duration(MQTTAttentionBlinkmsecs) * time.Millisecond) +func attention(command string) { + switch command { + case "blink": + for i := 0; i < Config.Global.Software.RemoteControl.MQTT.Settings.MQTTAttentionBlinkTimes; i++ { + GPIOOutPin("attention", "on") + time.Sleep(time.Duration(Config.Global.Software.RemoteControl.MQTT.Settings.MQTTAttentionBlinkmsecs) * time.Millisecond) + GPIOOutPin("attention", "off") + time.Sleep(time.Duration(Config.Global.Software.RemoteControl.MQTT.Settings.MQTTAttentionBlinkmsecs) * time.Millisecond) } - case "relay1:on": - log.Println("info: MQTT Turn On Relay 1 Successfully") - relayCommand(1, "on") - case "relay1:off": - log.Println("info: MQTT Turn Off Relay 1 Successfully") - relayCommand(1, "off") - case "relay1:pulse": - log.Println("info: MQTT Pulse Relay 1 Successfully") - relayCommand(1, "pulse") - case "playrepeatertone": - log.Println("info: MQTT Play Repeater Tone Processed Successfully") - b.cmdPlayRepeaterTone() - - // todo add other automation control for buttons, relays and leds here as needed in the future - default: - log.Printf("error: Undefined Command Received MQTT message on topic: %s Payload: %s\n", message.Topic(), message.Payload()) + case "on": + GPIOOutPin("attention", "on") + case "off": + GPIOOutPin("attention", "off") + } +} + +func relay(command string, no string) { + number := no + checkno, err := strconv.Atoi(no) + if err != nil || checkno == 0 || checkno > 2 { + return + } + switch command { + case "pulse": + GPIOOutPin("relay"+number, "pulse") + case "on": + GPIOOutPin("relay"+number, "on") + case "off": + GPIOOutPin("relay"+number, "off") } } diff --git a/onevent.go b/onevent.go index 152fb52..3f73020 100644 --- a/onevent.go +++ b/onevent.go @@ -34,6 +34,7 @@ import ( "log" "strconv" "strings" + "time" "github.com/talkkonnect/gumble/gumble" ) @@ -60,16 +61,16 @@ func (b *Talkkonnect) OnConnect(e *gumble.ConnectEvent) { log.Printf("debug: Connected to %s Address %s on attempt %d index [%d]\n ", b.Name, b.Client.Conn.RemoteAddr(), b.ConnectAttempts, AccountIndex) if e.WelcomeMessage != nil { - var message string = fmt.Sprintf("%v", esc(*e.WelcomeMessage)) + var tmessage string = fmt.Sprintf("%v", esc(*e.WelcomeMessage)) log.Println("info: Welcome message: ") - for _, line := range strings.Split(strings.TrimSuffix(message, "\n"), "\n") { + for _, line := range strings.Split(strings.TrimSuffix(tmessage, "\n"), "\n") { log.Println("info: ", line) } } - if TargetBoard == "rpi" { - if !LedStripEnabled { - LEDOnFunc(OnlineLED) + if Config.Global.Hardware.TargetBoard == "rpi" { + if !Config.Global.Hardware.LedStripEnabled { + GPIOOutPin("online", "on") } else { MyLedStripOnlineLEDOn() } @@ -104,33 +105,37 @@ func (b *Talkkonnect) OnDisconnect(e *gumble.DisconnectEvent) { IsConnected = false - if TargetBoard == "rpi" { - if !LedStripEnabled { - LEDOffAll() + if Config.Global.Hardware.TargetBoard == "rpi" { + if !Config.Global.Hardware.LedStripEnabled { + GPIOOutAll("led/relay", "off") } else { - MyLedStripLEDOffAll() + MyLedStripGPIOOutAll() } } - log.Println("alert: Attempting Reconnect in 10 seconds...") + log.Println("alert: Attempting Reconnect in 5 seconds...") log.Println("alert: Connection to ", b.Address, "disconnected") log.Println("alert: Disconnection Reason ", reason) - b.ReConnect() + time.Sleep(5 * time.Second) + b.ReConnect() } func (b *Talkkonnect) OnTextMessage(e *gumble.TextMessageEvent) { b.BackLightTimer() - if EventSoundEnabled { - localMediaPlayer(EventMessageSoundFilenameAndPath, EventVolume, 0, 1) - } + var eventSound EventSoundStruct = findEventSound("message") + if eventSound.Enabled { + if v, err := strconv.Atoi(eventSound.Volume); err == nil { + localMediaPlayer(eventSound.FileName, v, eventSound.Blocking, 0, 1) + } + } if len(cleanstring(e.Message)) > 105 { log.Println("warn: Message Too Long to Be Displayed on Screen") - message = strings.TrimSpace(cleanstring(e.Message)[:105]) + tmessage = strings.TrimSpace(cleanstring(e.Message)[:105]) } else { - message = strings.TrimSpace(cleanstring(e.Message)) + tmessage = strings.TrimSpace(cleanstring(e.Message)) } var sender string @@ -142,55 +147,59 @@ func (b *Talkkonnect) OnTextMessage(e *gumble.TextMessageEvent) { sender = "" } - log.Println(fmt.Sprintf("info: Message ("+strconv.Itoa(len(message))+") from %v %v\n", sender, message)) + log.Println(fmt.Sprintf("info: Message ("+strconv.Itoa(len(tmessage))+") from %v %v\n", sender, tmessage)) - if TTSMessageEnabled { - voiceMessage := fmt.Sprintf("Message from %v %v\n", sender, cleanstring(e.Message)) - if TTSMessageFromTag { - b.TTSPlayer(voiceMessage, TTSLocalPlay, TTSLocalPlayWithRXLED, TTSPlayIntoStream) - } else { - b.TTSPlayer(cleanstring(e.Message), TTSLocalPlay, TTSLocalPlayWithRXLED, TTSPlayIntoStream) + for _, tts := range Config.Global.Software.TTS.Sound { + if tts.Action == "message" { + if tts.Enabled { + voiceMessage := fmt.Sprintf("Message from %v %v\n", sender, cleanstring(e.Message)) + if Config.Global.Software.TTSMessages.TTSMessageFromTag { + b.TTSPlayerMessage(voiceMessage, Config.Global.Software.TTSMessages.LocalPlay, Config.Global.Software.TTSMessages.PlayIntoStream) + } else { + b.TTSPlayerMessage(cleanstring(e.Message), Config.Global.Software.TTSMessages.LocalPlay, Config.Global.Software.TTSMessages.PlayIntoStream) + } + } } } - if TargetBoard == "rpi" { + if Config.Global.Hardware.TargetBoard == "rpi" { if LCDEnabled { LcdText[0] = "Msg From " + sender - LcdText[1] = message + LcdText[1] = tmessage LcdDisplay(LcdText, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress) } if OLEDEnabled { oledDisplay(false, 2, 1, "Msg From "+sender) - if len(message) <= 21 { - oledDisplay(false, 3, 1, message) + if len(tmessage) <= 21 { + oledDisplay(false, 3, 1, tmessage) oledDisplay(false, 4, 1, "") oledDisplay(false, 5, 1, "") oledDisplay(false, 6, 1, "") oledDisplay(false, 7, 1, "") - } else if len(message) <= 42 { - oledDisplay(false, 3, 1, message[0:21]) - oledDisplay(false, 4, 1, message[21:41]) + } else if len(tmessage) <= 42 { + oledDisplay(false, 3, 1, tmessage[0:21]) + oledDisplay(false, 4, 1, tmessage[21:41]) oledDisplay(false, 5, 1, "") oledDisplay(false, 6, 1, "") oledDisplay(false, 7, 1, "") - } else if len(message) <= 63 { - oledDisplay(false, 3, 1, message[0:21]) - oledDisplay(false, 4, 1, message[21:42]) - oledDisplay(false, 5, 1, message[42:]) + } else if len(tmessage) <= 63 { + oledDisplay(false, 3, 1, tmessage[0:21]) + oledDisplay(false, 4, 1, tmessage[21:42]) + oledDisplay(false, 5, 1, tmessage[42:]) oledDisplay(false, 6, 1, "") oledDisplay(false, 7, 1, "") - } else if len(message) <= 84 { - oledDisplay(false, 3, 1, message[0:21]) - oledDisplay(false, 4, 1, message[21:42]) - oledDisplay(false, 5, 1, message[42:63]) - oledDisplay(false, 6, 1, message[63:]) + } else if len(tmessage) <= 84 { + oledDisplay(false, 3, 1, tmessage[0:21]) + oledDisplay(false, 4, 1, tmessage[21:42]) + oledDisplay(false, 5, 1, tmessage[42:63]) + oledDisplay(false, 6, 1, tmessage[63:]) oledDisplay(false, 7, 1, "") - } else if len(message) <= 105 { - oledDisplay(false, 3, 1, message[0:20]) - oledDisplay(false, 4, 1, message[21:44]) - oledDisplay(false, 5, 1, message[42:63]) - oledDisplay(false, 6, 1, message[63:84]) - oledDisplay(false, 7, 1, message[84:105]) + } else if len(tmessage) <= 105 { + oledDisplay(false, 3, 1, tmessage[0:20]) + oledDisplay(false, 4, 1, tmessage[21:44]) + oledDisplay(false, 5, 1, tmessage[42:63]) + oledDisplay(false, 6, 1, tmessage[63:84]) + oledDisplay(false, 7, 1, tmessage[84:105]) } } } @@ -222,12 +231,11 @@ func (b *Talkkonnect) OnUserChange(e *gumble.UserChangeEvent) { log.Println("info:", cleanstring(e.User.Name), " Changed Channel to ", e.User.Channel.Name) LcdText[2] = cleanstring(e.User.Name) + "->" + e.User.Channel.Name LcdText[3] = "" + if Config.Global.Hardware.IO.Max7219.Enabled { + Max7219(Config.Global.Hardware.IO.Max7219.Max7219Cascaded, Config.Global.Hardware.IO.Max7219.SPIBus, Config.Global.Hardware.IO.Max7219.SPIDevice, Config.Global.Hardware.IO.Max7219.Brightness, strconv.Itoa(int(b.Client.Self.Channel.ID))) + } case gumble.UserChangeComment: info = "chg comment" - b.BackLightTimer() - if EventSoundEnabled { - localMediaPlayer(EventMessageSoundFilenameAndPath, EventVolume, 0, 1) - } case gumble.UserChangeAudio: info = "chg audio" case gumble.UserChangePrioritySpeaker: @@ -240,8 +248,13 @@ func (b *Talkkonnect) OnUserChange(e *gumble.UserChangeEvent) { if info != "chg channel" { if info != "" { log.Println("info: User ", cleanstring(e.User.Name), " ", info, "Event type=", e.Type, " channel=", e.User.Channel.Name) - if TTSEnabled && TTSParticipants { - b.Speak("User "+cleanstring(e.User.Name)+info+"Has Changed to "+e.User.Channel.Name, "local", 1, 0, 1, TTSLanguage) + + for _, tts := range Config.Global.Software.TTS.Sound { + if tts.Action == "participants" { + if tts.Enabled { + b.Speak("User "+cleanstring(e.User.Name)+info+"Has Changed to "+e.User.Channel.Name, "local", 1, 0, 1, Config.Global.Software.TTSMessages.TTSLanguage) + } + } } } @@ -290,7 +303,7 @@ func (b *Talkkonnect) OnPermissionDenied(e *gumble.PermissionDeniedEvent) { LcdText[1] = b.Client.Self.Channel.Name + " (" + strconv.Itoa(len(b.Client.Self.Channel.Users)) + " Users)" } - if TargetBoard == "rpi" { + if Config.Global.Hardware.TargetBoard == "rpi" { if LCDEnabled { LcdDisplay(LcdText, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress) } diff --git a/scripts/tkbuild.sh b/scripts/tkbuild.sh index c43df96..a48b46c 100644 --- a/scripts/tkbuild.sh +++ b/scripts/tkbuild.sh @@ -28,6 +28,7 @@ ## Please RUN this Script as root user ## If this script is run after a fresh install of raspbian you man want to update the 2 lines below + apt-get update apt-get -y dist upgrade @@ -47,8 +48,8 @@ mkdir -p /home/talkkonnect/bin touch /var/log/talkkonnect.log cd /usr/local -wget https://golang.org/dl/go1.15.linux-armv6l.tar.gz -tar -zxvf go1.15.linux-armv6l.tar.gz +wget https://golang.org/dl/go1.17.2.linux-armv6l.tar.gz +tar -zxvf go1.17.2.linux-armv6l.tar.gz echo export PATH=$PATH:/usr/local/go/bin >> ~/.bashrc echo export GOPATH=/home/talkkonnect/gocode >> ~/.bashrc @@ -68,6 +69,7 @@ go get -v github.com/talkkonnect/talkkonnect ## Build talkkonnect as binary cd $GOPATH/src/github.com/talkkonnect/talkkonnect +mv $GOPATH/src/github.com/talkkonnect/talkkonnect $GOPATH/src/github.com/talkkonnect/talkkonnect /usr/local/go/bin/go build -o /home/talkkonnect/bin/talkkonnect cmd/talkkonnect/main.go ## Notify User diff --git a/soundfiles/announcements/announcement-01.wav b/soundfiles/announcements/announcement-01.wav index d7801d1..5669424 100644 Binary files a/soundfiles/announcements/announcement-01.wav and b/soundfiles/announcements/announcement-01.wav differ diff --git a/soundfiles/announcements/announcement-02.wav b/soundfiles/announcements/announcement-02.wav index ba1ed25..acd9338 100644 Binary files a/soundfiles/announcements/announcement-02.wav and b/soundfiles/announcements/announcement-02.wav differ diff --git a/soundfiles/announcements/announcement-03.wav b/soundfiles/announcements/announcement-03.wav index 69605b2..e7fe85e 100644 Binary files a/soundfiles/announcements/announcement-03.wav and b/soundfiles/announcements/announcement-03.wav differ diff --git a/soundfiles/announcements/announcement-04.wav b/soundfiles/announcements/announcement-04.wav index a4f8874..5bdb27b 100644 Binary files a/soundfiles/announcements/announcement-04.wav and b/soundfiles/announcements/announcement-04.wav differ diff --git a/soundfiles/announcements/announcement-05.wav b/soundfiles/announcements/announcement-05.wav index d7650a3..d533f2e 100644 Binary files a/soundfiles/announcements/announcement-05.wav and b/soundfiles/announcements/announcement-05.wav differ diff --git a/soundfiles/announcements/announcement-06.wav b/soundfiles/announcements/announcement-06.wav index c629767..88bb453 100644 Binary files a/soundfiles/announcements/announcement-06.wav and b/soundfiles/announcements/announcement-06.wav differ diff --git a/soundfiles/announcements/announcement-08.wav b/soundfiles/announcements/announcement-08.wav index bfbad08..517be76 100644 Binary files a/soundfiles/announcements/announcement-08.wav and b/soundfiles/announcements/announcement-08.wav differ diff --git a/soundfiles/announcements/announcement-09.wav b/soundfiles/announcements/announcement-09.wav index c62f98d..4f961eb 100644 Binary files a/soundfiles/announcements/announcement-09.wav and b/soundfiles/announcements/announcement-09.wav differ diff --git a/soundfiles/announcements/announcement-10.wav b/soundfiles/announcements/announcement-10.wav index 0c30abc..50e4792 100644 Binary files a/soundfiles/announcements/announcement-10.wav and b/soundfiles/announcements/announcement-10.wav differ diff --git a/soundfiles/events/appear.wav b/soundfiles/events/appear.wav new file mode 100644 index 0000000..16bf2b8 Binary files /dev/null and b/soundfiles/events/appear.wav differ diff --git a/soundfiles/events/joined.wav b/soundfiles/events/joined.wav index bf38f0c..8838d57 100644 Binary files a/soundfiles/events/joined.wav and b/soundfiles/events/joined.wav differ diff --git a/soundfiles/voiceprompts/MuteSpeaker.wav b/soundfiles/voiceprompts/MuteSpeaker.wav new file mode 100644 index 0000000..2f862d1 Binary files /dev/null and b/soundfiles/voiceprompts/MuteSpeaker.wav differ diff --git a/soundfiles/voiceprompts/ToggleMuteSpeaker.wav b/soundfiles/voiceprompts/ToggleMuteSpeaker.wav new file mode 100644 index 0000000..339a187 Binary files /dev/null and b/soundfiles/voiceprompts/ToggleMuteSpeaker.wav differ diff --git a/soundfiles/voiceprompts/UnmuteSpeaker.wav b/soundfiles/voiceprompts/UnmuteSpeaker.wav new file mode 100644 index 0000000..2e324ec Binary files /dev/null and b/soundfiles/voiceprompts/UnmuteSpeaker.wav differ diff --git a/stream.go b/stream.go index f5b0add..61310d6 100644 --- a/stream.go +++ b/stream.go @@ -34,6 +34,7 @@ import ( "errors" "fmt" "log" + "strconv" "time" "github.com/talkkonnect/go-openal/openal" @@ -42,13 +43,18 @@ import ( ) var ( - errState = errors.New("gumbleopenal: invalid state") - lcdtext = [4]string{"nil", "nil", "nil", ""} - now = time.Now() - debuglevel = 2 - emptyBufs = openal.NewBuffers(16) + errState = errors.New("gumbleopenal: invalid state") + lcdtext = [4]string{"nil", "nil", "nil", ""} + now = time.Now() + debuglevel = 2 + RXLEDStatus bool + TotalStreams int + NeedToKill int ) +// MumbleDuplex - listenera and outgoing +type MumbleDuplex struct{} + type Stream struct { client *gumble.Client link gumble.Detacher @@ -61,7 +67,7 @@ type Stream struct { contextSink *openal.Context } -func New(client *gumble.Client) (*Stream, error) { +func (b *Talkkonnect) New(client *gumble.Client) (*Stream, error) { s := &Stream{ client: client, sourceFrameSize: client.Config.AudioFrameSize(), @@ -79,131 +85,86 @@ func New(client *gumble.Client) (*Stream, error) { return s, nil } -func (s *Stream) Destroy() { +func (b *Talkkonnect) Destroy() { if debuglevel >= 3 { log.Println("debug: Destroy Stream Source") } - s.link.Detach() - if s.deviceSource != nil { - s.StopSource() - s.deviceSource.CaptureCloseDevice() - s.deviceSource = nil + b.Stream.link.Detach() + if b.Stream.deviceSource != nil { + b.Stream.deviceSource.CaptureStop() + b.Stream.deviceSource.CaptureCloseDevice() + b.Stream.deviceSource = nil } - if s.deviceSink != nil { - s.contextSink.Destroy() - s.deviceSink.CloseDevice() - s.contextSink = nil - s.deviceSink = nil + if b.Stream.deviceSink != nil { + b.Stream.contextSink.Destroy() + b.Stream.deviceSink.CloseDevice() + b.Stream.contextSink = nil + b.Stream.deviceSink = nil } } -func (s *Stream) StartSource() error { +func (b *Talkkonnect) StartSource() error { if debuglevel >= 3 { log.Println("debug: Start Stream Source") } - if s.sourceStop != nil { - return errState - } - if IncommingBeepSoundEnabled { - s.playIntoStream(IncommingBeepSoundFilenameAndPath, IncommingBeepSoundVolume) - } + // if b.Stream.sourceStop == nil { + // return errState + // } - s.deviceSource.CaptureStart() - s.sourceStop = make(chan bool) - go s.sourceRoutine() + var eventSound EventSoundStruct = findEventSound("incommingbeep") + if eventSound.Enabled { + if v, err := strconv.ParseFloat(eventSound.Volume, 32); err == nil { + time.Sleep(300 * time.Millisecond) + log.Println("alert: Playing Incomming into Stream") + b.splayIntoStream(eventSound.FileName, float32(v)) + } + } + b.Stream.deviceSource.CaptureStart() + b.Stream.sourceStop = make(chan bool) + go b.sourceRoutine() return nil } -func (s *Stream) StopSource() error { +func (b *Talkkonnect) StopSource() error { if debuglevel >= 3 { log.Println("debug: Stop Source File") } - if s.sourceStop == nil { + if b.Stream.sourceStop == nil { return errState } - close(s.sourceStop) - s.sourceStop = nil - s.deviceSource.CaptureStop() - s.deviceSource.CaptureCloseDevice() - - if RogerBeepSoundEnabled { + close(b.Stream.sourceStop) + b.Stream.sourceStop = nil + b.Stream.deviceSource.CaptureStop() + b.Stream.deviceSource.CaptureCloseDevice() + + var eventSound EventSoundStruct = findEventSound("rogerbeep") + if eventSound.Enabled { + GPIOOutPin("transmit", "on") log.Println("debug: Rogerbeep Playing") - s.playIntoStream(RogerBeepSoundFilenameAndPath, RogerBeepSoundVolume) + if v, err := strconv.ParseFloat(eventSound.Volume, 32); err == nil { + b.splayIntoStream(eventSound.FileName, float32(v)) + } + GPIOOutPin("transmit", "off") } - s.deviceSource = openal.CaptureOpenDevice("", gumble.AudioSampleRate, openal.FormatMono16, uint32(s.sourceFrameSize)) + b.Stream.deviceSource = openal.CaptureOpenDevice("", gumble.AudioSampleRate, openal.FormatMono16, uint32(b.Stream.sourceFrameSize)) return nil } func (s *Stream) OnAudioStream(e *gumble.AudioStreamEvent) { - - if TargetBoard == "rpi" && LCDEnabled { - LEDOffFunc(BackLightLED) - } - - StreamCounter++ - - TalkedTicker := time.NewTicker(200 * time.Millisecond) - Talking := make(chan bool) - - if StreamCounter == 1 { - go func() { - for { - select { - case <-Talking: - TalkedTicker.Reset(200 * time.Millisecond) - if !RXLEDStatus { - RXLEDStatus = true - LEDOnFunc(VoiceActivityLED) - - if IgnoreUserEnabled { - if len(IgnoreUserRegex) > 0 { - if checkRegex(IgnoreUserRegex, *e.LastSpeaker) { - log.Println("info: Ignoring Speaker->", *e.LastSpeaker) - } else { - log.Println("info: Speaking->", *e.LastSpeaker) - - } - } - } - - t := time.Now() - if TargetBoard == "rpi" { - if LCDEnabled { - LEDOnFunc(BackLightLED) - lcdtext = [4]string{"nil", "", "", *e.LastSpeaker + " " + t.Format("15:04:05")} - LcdDisplay(lcdtext, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress) - BackLightTime.Reset(time.Duration(LCDBackLightTimeout) * time.Second) - } - - if OLEDEnabled { - Oled.DisplayOn() - go oledDisplay(false, 3, 1, *e.LastSpeaker+" "+t.Format("15:04:05")) - BackLightTime.Reset(time.Duration(LCDBackLightTimeout) * time.Second) - } - } - } - case <-TalkedTicker.C: - RXLEDStatus = false - LEDOffFunc(VoiceActivityLED) - TalkedTicker.Stop() - - } - } - }() + TotalStreams++ + if _, userexists := StreamTracker[e.User.UserID]; userexists { + log.Printf("info: Stale GoRoutine Detected For UserID=%v UserName=%v Session=%v AudioStreamChannel=%v", e.User.UserID, e.User.Name, e.User.Session, e.C) + NeedToKill++ } + StreamTracker[e.User.UserID] = streamTrackerStruct{UserID: e.User.UserID, UserName: e.User.Name, UserSession: e.User.Session, C: e.C} + goStreamStats() go func() { - if StreamCounter > 1 { - StreamCounter-- - return - } - - source = openal.NewSource() - emptyBufs = openal.NewBuffers(16) - + source := openal.NewSource() + emptyBufs := openal.NewBuffers(24) reclaim := func() { if n := source.BuffersProcessed(); n > 0 { reclaimedBufs := make(openal.Buffers, n) @@ -211,30 +172,9 @@ func (s *Stream) OnAudioStream(e *gumble.AudioStreamEvent) { emptyBufs = append(emptyBufs, reclaimedBufs...) } } - var raw [gumble.AudioMaximumFrameSize * 2]byte - for packet := range e.C { - Talking <- true - - if IgnoreUserEnabled { - if len(IgnoreUserRegex) > 0 { - if checkRegex(IgnoreUserRegex, *e.LastSpeaker) { - continue - } - } - } - - if TargetBoard == "rpi" && LCDEnabled { - LEDOnFunc(BackLightLED) - } - - if CancellableStream && NowStreaming { - pstream.Stop() - } - samples := len(packet.AudioBuffer) - if samples > cap(raw) { continue } @@ -243,7 +183,6 @@ func (s *Stream) OnAudioStream(e *gumble.AudioStreamEvent) { } reclaim() if len(emptyBufs) == 0 { - emptyBufs = openal.NewBuffers(16) continue } last := len(emptyBufs) - 1 @@ -254,7 +193,6 @@ func (s *Stream) OnAudioStream(e *gumble.AudioStreamEvent) { if source.State() != openal.Playing { source.Play() } - Talking <- false } reclaim() emptyBufs.Delete() @@ -262,22 +200,22 @@ func (s *Stream) OnAudioStream(e *gumble.AudioStreamEvent) { }() } -func (s *Stream) sourceRoutine() { - interval := s.client.Config.AudioInterval - frameSize := s.client.Config.AudioFrameSize() +func (b *Talkkonnect) sourceRoutine() { + interval := b.Stream.client.Config.AudioInterval + frameSize := b.Stream.client.Config.AudioFrameSize() - if frameSize != s.sourceFrameSize { + if frameSize != b.Stream.sourceFrameSize { log.Println("error: FrameSize Error!") - s.deviceSource.CaptureCloseDevice() - s.sourceFrameSize = frameSize - s.deviceSource = openal.CaptureOpenDevice("", gumble.AudioSampleRate, openal.FormatMono16, uint32(s.sourceFrameSize)) + b.Stream.deviceSource.CaptureCloseDevice() + b.Stream.sourceFrameSize = frameSize + b.Stream.deviceSource = openal.CaptureOpenDevice("", gumble.AudioSampleRate, openal.FormatMono16, uint32(b.Stream.sourceFrameSize)) } ticker := time.NewTicker(interval) defer ticker.Stop() - stop := s.sourceStop + stop := b.Stream.sourceStop - outgoing := s.client.AudioOutgoing() + outgoing := b.Stream.client.AudioOutgoing() defer close(outgoing) for { @@ -289,7 +227,7 @@ func (s *Stream) sourceRoutine() { return case <-ticker.C: //this is for encoding (transmitting) - buff := s.deviceSource.CaptureSamples(uint32(frameSize)) + buff := b.Stream.deviceSource.CaptureSamples(uint32(frameSize)) if len(buff) != frameSize*2 { continue } @@ -302,8 +240,40 @@ func (s *Stream) sourceRoutine() { } } -func (s *Stream) playIntoStream(filepath string, vol float32) { - pstream = gumbleffmpeg.New(s.client, gumbleffmpeg.SourceFile(filepath), vol) +func (b *Talkkonnect) playIntoStream(filepath string, vol float32) { + if !IsPlayStream { + log.Println(fmt.Sprintf("info: File %s Stopped!", filepath)) + pstream.Stop() + GPIOOutPin("transmit", "off") + return + } + + var eventSound EventSoundStruct = findEventSound("stream") + if eventSound.Enabled { + if pstream != nil && pstream.State() == gumbleffmpeg.StatePlaying { + pstream.Stop() + return + } + + GPIOOutPin("transmit", "on") + + IsPlayStream = true + pstream = gumbleffmpeg.New(b.Client, gumbleffmpeg.SourceFile(filepath), vol/100) + if err := pstream.Play(); err != nil { + log.Println(fmt.Sprintf("error: Can't play %s error %s", filepath, err)) + } else { + log.Println(fmt.Sprintf("info: File %s Playing!", filepath)) + pstream.Wait() + pstream.Stop() + GPIOOutPin("transmit", "off") + } + } else { + log.Println("warn: Sound Disabled by Config") + } +} + +func (b *Talkkonnect) splayIntoStream(filepath string, vol float32) { + pstream = gumbleffmpeg.New(b.Stream.client, gumbleffmpeg.SourceFile(filepath), vol/100) if err := pstream.Play(); err != nil { log.Println(fmt.Sprintf("error: Can't play %s error %s", filepath, err)) } else { @@ -314,9 +284,9 @@ func (s *Stream) playIntoStream(filepath string, vol float32) { } func (b *Talkkonnect) OpenStream() { - if stream, err := New(b.Client); err != nil { + if stream, err := b.New(b.Client); err != nil { - if TargetBoard == "rpi" { + if Config.Global.Hardware.TargetBoard == "rpi" { if LCDEnabled { LcdText = [4]string{"Stream Error!", "nil", "nil", "nil"} LcdDisplay(LcdText, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress) @@ -333,7 +303,15 @@ func (b *Talkkonnect) OpenStream() { } func (b *Talkkonnect) ResetStream() { - b.Stream.Destroy() + b.Stream.contextSink.Destroy() time.Sleep(50 * time.Millisecond) b.OpenStream() } + +func goStreamStats() { + log.Println("info: Active Streams") + for item, value := range StreamTracker { + log.Printf("info: Item=%v UserID=%v UserName=%v Session=%v AudioStreamChannel=%v", item, value.UserID, value.UserName, value.UserSession, value.C) + } + log.Printf("Total GoRoutines Open=%v, Total GoRoutines Wasted=%v \n", TotalStreams, NeedToKill) +} diff --git a/talkkonnect.go b/talkkonnect.go index 7f8b8b5..375b255 100644 --- a/talkkonnect.go +++ b/talkkonnect.go @@ -30,10 +30,10 @@ package talkkonnect import ( - "github.com/talkkonnect/volume-go" "log" - "os" "strconv" + + "github.com/talkkonnect/volume-go" ) func talkkonnectBanner(backgroundcolor string) { @@ -95,7 +95,8 @@ func (b *Talkkonnect) talkkonnectMenu(backgroundcolor string) { log.Println("info: " + backgroundcolor + "│ Stop Transmitting │ List Online Users │" + backgroundreset) log.Println("info: " + backgroundcolor + "│ Playback/Stop Stream │ For GPS Position │" + backgroundreset) log.Println("info: " + backgroundcolor + "├─────────────────────────────┼────────────────────────────────┤" + backgroundreset) - log.Println("info: " + backgroundcolor + "│ Debug Stacktrace │ │" + backgroundreset) + log.Println("info: " + backgroundcolor + "│ Reload XML Config │ Debug Stacktrace │" + backgroundreset) + log.Println("info: " + backgroundcolor + "│ Check XML Config │ │" + backgroundreset) log.Println("info: " + backgroundcolor + "├─────────────────────────────┼────────────────────────────────┤" + backgroundreset) log.Println("info: " + backgroundcolor + "│ Send Email │ Conn Next Server │" + backgroundreset) log.Println("info: " + backgroundcolor + "│ Conn Previous Server│ Panic Simulation │" + backgroundreset) @@ -126,23 +127,16 @@ func (b *Talkkonnect) talkkonnectMenu(backgroundcolor string) { } } - origMuted, _ := volume.GetMuted(OutputDevice) + origMuted, _ := volume.GetMuted(Config.Global.Software.Settings.OutputDevice) if origMuted { log.Println("info: Speaker Currently Muted") } else { - origVolume, err := volume.GetVolume(OutputDevice) + origVolume, err := volume.GetVolume(Config.Global.Software.Settings.OutputDevice) if err == nil { log.Printf("info: Speaker Not Muted & Current Volume at Level %v%%\n", origVolume) } else { log.Println("error: Can't Get Volume Level From Sound Card!") } } - hostname, err1 := os.Hostname() - if err1 != nil { - log.Printf("warn: Cannot Get Hostname\n") - } else { - log.Printf("info: Hostname is %s\n", hostname) - } - log.Printf("info: Talkkonnect Version %v Released %v\n", talkkonnectVersion, talkkonnectReleased) } diff --git a/talkkonnect.xml b/talkkonnect.xml deleted file mode 100755 index 1c1f298..0000000 --- a/talkkonnect.xml +++ /dev/null @@ -1,477 +0,0 @@ - - - - - mumble.talkkonnect.com:64738 - - talkkonnect - true - false - - - Name Surname - - token1 - token2 - - - - - user1 - - - - - user2 - - - - - user1 - user2 - - - - - - channelname1 - true - true - "all" - - - - - - - - - - Speaker - Speaker - /var/log/talkkonnect.log - screenwithlineno - debug - false - true - false - false - false - 0 - - - - http://provisioning.mydomain.com - /home/talkkonnect/gocode/src/github.com/talkkonnect/talkkonnect - talkkonnect.xml - - - 10 - /home/talkkonnect/gocode/src/github.com/talkkonnect/talkkonnect/soundfiles/voiceprompts/Beacon.wav - 1 - - - 70 - false - true - /home/talkkonnect/gocode/src/github.com/talkkonnect/talkkonnect/soundfiles/voiceprompts/ChannelUp.wav - true - /home/talkkonnect/gocode/src/github.com/talkkonnect/talkkonnect/soundfiles/voiceprompts/ChannelDown.wav - true - /home/talkkonnect/gocode/src/github.com/talkkonnect/talkkonnect/soundfiles/voiceprompts/MuteUnMuteSpeaker.wav - true - /home/talkkonnect/gocode/src/github.com/talkkonnect/talkkonnect/soundfiles/voiceprompts/CurrentVolumeLevel.wav - true - /home/talkkonnect/gocode/src/github.com/talkkonnect/talkkonnect/soundfiles/voiceprompts/DigitalVolumeUp.wav - true - /home/talkkonnect/gocode/src/github.com/talkkonnect/talkkonnect/soundfiles/voiceprompts/DigitalVolumeDown.wav - true - /home/talkkonnect/gocode/src/github.com/talkkonnect/talkkonnect/soundfiles/voiceprompts/ListServerChannels.wav - true - /home/talkkonnect/gocode/src/github.com/talkkonnect/talkkonnect/soundfiles/voiceprompts/StartTransmitting.wav - true - /home/talkkonnect/gocode/src/github.com/talkkonnect/talkkonnect/soundfiles/voiceprompts/StopTransmitting.wav - true - /home/talkkonnect/gocode/src/github.com/talkkonnect/talkkonnect/soundfiles/voiceprompts/ListOnlineUsers.wav - true - /home/talkkonnect/gocode/src/github.com/talkkonnect/talkkonnect/soundfiles/voiceprompts/PlayChimes.wav - true - /home/talkkonnect/gocode/src/github.com/talkkonnect/talkkonnect/soundfiles/voiceprompts/RequestGpsPosition.wav - false - - false - - true - /home/talkkonnect/gocode/src/github.com/talkkonnect/talkkonnect/soundfiles/voiceprompts/PanicSimulation.wav - true - /home/talkkonnect/gocode/src/github.com/talkkonnect/talkkonnect/soundfiles/voiceprompts/PrintXmlConfig.wav - true - /home/talkkonnect/gocode/src/github.com/talkkonnect/talkkonnect/soundfiles/voiceprompts/SendEmail.wav - true - /home/talkkonnect/gocode/src/github.com/talkkonnect/talkkonnect/soundfiles/voiceprompts/DisplayMenu.wav - true - /home/talkkonnect/gocode/src/github.com/talkkonnect/talkkonnect/soundfiles/voiceprompts/QuitTalkkonnect.wav - true - /home/talkkonnect/gocode/src/github.com/talkkonnect/talkkonnect/soundfiles/voiceprompts/Loaded.wav - true - - - - robot@email.com - user - someone@somedomain.com - Talkkonnect Email Message with GPS - Hello From Talkkonnect - true - true - true - - - - /home/talkkonnect/gocode/src/github.com/talkkonnect/talkkonnect/soundfiles/events/event.wav - /home/talkkonnect/gocode/src/github.com/talkkonnect/talkkonnect/soundfiles/events/left.wav - /home/talkkonnect/gocode/src/github.com/talkkonnect/talkkonnect/soundfiles/events/message.wav - - - /home/talkkonnect/gocode/src/github.com/talkkonnect/talkkonnect/soundfiles/alerts/alert.wav - 1 - - - /home/talkkonnect/gocode/src/github.com/talkkonnect/talkkonnect/soundfiles/rogerbeeps/Incoming.wav - 1 - - - /home/talkkonnect/gocode/src/github.com/talkkonnect/talkkonnect/soundfiles/rogerbeeps/Image.wav - 0.1 - - - 1750 - 1 - - - http://prdonline.prd.go.th:8200 - 0.5 - - - - 60 - - - 8080 - true - true - true - true - true - true - true - true - true - true - true - true - true - false - true - true - true - true - true - true - true - true - true - - - false - false - false - false - false - false - false - false - false - false - false - false - false - false - false - false - false - false - false - false - false - false - - - country/city/division/talkkonnect - tcp://mqtt.yourdomain.com:1883 - username - password - talkkonnect002 - false - 0 - 1 - - sub - - 20 - 300 - - - true - true - true - - - - - false - 2 - 3 - 4 - 5 - - - - 2 - 3000 - 1000 - 1500 - - - 26 - 11 - 19 - 13 - 14 - - - - 9 - Standby - Unavailable - - - parallel - 63 - false - 30 - 6 - 7 - 8 - 25 - 24 - 23 - 18 - - - i2c - 6 - 21 - 1 - 60 - 128 - 64 - 33 - 176 - 9 - 0 - - - /dev/ttyACM0 - 115200 - - false - false - false - false - false - 1 - 8 - 100 - 0 - true - - - /home/talkkonnect/gocode/src/github.com/talkkonnect/talkkonnect/soundfiles/alerts/alert.wav - 0.5 - true - Need Help! Now! - false - true - true - 30 - - - false - - - 0 - - - 0 - - - - - - - - - /dev/input/event0 - 69 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - - - 0 - 69 - - - - - - - - 1 - - - 1 - - - - - - - - 2 - - - 2 - - - - - - - - 3 - - - 3 - - - - - - - - 4 - - - 4 - - - - - - - - 5 - - - 5 - - - - - - - - 6 - - - 6 - - - - - - - - 7 - - - 7 - - - - - - - - 8 - - - 8 - - - - - - - - 9 - - - 9 - - - - - - diff --git a/usbkeyboard.go b/usbkeyboard.go index 425a8be..88e06a5 100644 --- a/usbkeyboard.go +++ b/usbkeyboard.go @@ -40,9 +40,9 @@ import ( func (b *Talkkonnect) USBKeyboard() { - device, err := evdev.Open(USBKeyboardPath) + device, err := evdev.Open(Config.Global.Hardware.USBKeyboard.USBKeyboardPath) if err != nil { - log.Printf("error: Unable to open USB Keyboard input device: %s\nError: %v It will now Be Disabled\n", USBKeyboardPath, err) + log.Printf("error: Unable to open USB Keyboard input device: %s\nError: %v It will now Be Disabled\n", Config.Global.Hardware.USBKeyboard.USBKeyboardPath, err) return } @@ -96,7 +96,7 @@ func (b *Talkkonnect) USBKeyboard() { case "record": b.cmdAudioTrafficRecord() b.cmdAudioMicRecord() - case "setvoicetarget": + case "voicetargetset": voicetarget, err := strconv.Atoi(USBKeyMap[rune(ke.Scancode)].ParamValue) if err != nil { log.Println("error: Target is Non-Numeric Value") @@ -107,7 +107,7 @@ func (b *Talkkonnect) USBKeyboard() { log.Println("Command Not Defined ", strings.ToLower(USBKeyMap[rune(ke.Scancode)].Command)) } } else { - if ke.Scancode != uint16(NumlockScanID) { + if ke.Scancode != uint16(Config.Global.Hardware.USBKeyboard.NumlockScanID) { log.Println("error: Key Not Mapped ASC ", ke.Scancode) } } @@ -115,3 +115,4 @@ func (b *Talkkonnect) USBKeyboard() { } } } + diff --git a/utils.go b/utils.go index 4311df9..2c5e9b4 100644 --- a/utils.go +++ b/utils.go @@ -160,7 +160,15 @@ func sendviagmail(username string, password string, receiver string, subject str return fmt.Errorf("sending Email Via GMAIL Error") } - go LcdDisplay(LcdText, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress) + if Config.Global.Hardware.TargetBoard == "rpi" { + if LCDEnabled { + LcdText = [4]string{"nil", "nil", "nil", "Sending Email"} + go LcdDisplay(LcdText, LCDRSPin, LCDEPin, LCDD4Pin, LCDD5Pin, LCDD6Pin, LCDD7Pin, LCDInterfaceType, LCDI2CAddress) + } + if OLEDEnabled { + oledDisplay(false, 6, 1, "Sending Email") + } + } return nil } diff --git a/xmlparser.go b/xmlparser.go index 103725a..b23b3ef 100644 --- a/xmlparser.go +++ b/xmlparser.go @@ -13,14 +13,15 @@ * * talkkonnect is the based on talkiepi and barnard by Daniel Chote and Tim Cooper * - * The Initial Developer of the Original Code is - * Suvir Kumar + * The Initial Developer of the Original Code is Suvir Kumar + * * Portions created by the Initial Developer are Copyright (C) Suvir Kumar. All Rights Reserved. * * Contributor(s): * * Suvir Kumar * Zoran Dimitrijevic + * * My Blog is at www.talkkonnect.com * The source code is hosted at github.com/talkkonnect * @@ -41,504 +42,21 @@ import ( "strings" "time" + "github.com/comail/colog" goled "github.com/talkkonnect/go-oled-i2c" - "github.com/talkkonnect/go-openal/openal" - "github.com/talkkonnect/gpio" + + // "github.com/talkkonnect/go-openal/openal" "github.com/talkkonnect/gumble/gumble" "github.com/talkkonnect/gumble/gumbleffmpeg" "golang.org/x/sys/unix" ) -//version and release date const ( - talkkonnectVersion string = "1.68.03" - talkkonnectReleased string = "Sep 5 2021" -) - -// Generic Global Variables -var ( - AccountCount int - KillHeartBeat bool - IsPlayStream bool - ConnectAttempts int - IsConnected bool - BufferToOpenALCounter int - AccountIndex int - GenericCounter int - IsNumlock bool - RXLEDStatus bool - BackLightTime = time.NewTicker(5 * time.Second) - BackLightTimePtr = &BackLightTime - StartTime = time.Now() - LastTime = now.Unix() - StreamCounter = 0 - TimerTalked = time.NewTicker(time.Millisecond * 200) - LcdText = [4]string{"nil", "nil", "nil", "nil"} - ConfigXMLFile string - Streaming bool - HTTPServRunning bool - NowStreaming bool - MyLedStrip *LedStrip - TargetBoard string = "pc" - CancellableStream bool = true - StreamOnStart bool - StreamOnStartAfter time.Duration - TXOnStart bool - TXOnStartAfter time.Duration - RepeatTXTimes int -) - -// Generic Local Variables for xmlparser -var ( - txcounter int - isTx bool - pstream *gumbleffmpeg.Stream - source = openal.NewSource() -) - -//account settings -var ( - Default []bool - Name []string - Server []string - Username []string - Password []string - Insecure []bool - Register []bool - Certificate []string - Channel []string - Ident []string - Tokens []gumble.AccessTokens - VT []VTStruct - Accounts int - MaxTokensInAccounts int -) - -//software settings -var ( - OutputDevice string = "Speaker" - OutputDeviceShort string - LogFilenameAndPath string = "/var/log/talkkonnect.log" - Logging string = "screen" - Loglevel string = "info" - Daemonize bool - SimplexWithMute bool = true - TxCounter bool - NextServerIndex int = 0 -) - -//autoprovision settings -var ( - APEnabled bool - TkID string - URL string - SaveFilePath string - SaveFilename string -) - -//beacon settings -var ( - BeaconEnabled bool - BeaconTimerSecs int = 30 - BeaconFilenameAndPath string - BVolume float32 = 1.0 -) - -//tts -var ( - TTSEnabled bool - TTSVolumeLevel float32 - TTSParticipants bool - TTSChannelUp bool - TTSChannelUpFilenameAndPath string - TTSChannelDown bool - TTSChannelDownFilenameAndPath string - TTSMuteUnMuteSpeaker bool - TTSMuteUnMuteSpeakerFilenameAndPath string - TTSCurrentVolumeLevel bool - TTSCurrentVolumeLevelFilenameAndPath string - TTSDigitalVolumeUp bool - TTSDigitalVolumeUpFilenameAndPath string - TTSDigitalVolumeDown bool - TTSDigitalVolumeDownFilenameAndPath string - TTSListServerChannels bool - TTSListServerChannelsFilenameAndPath string - TTSStartTransmitting bool - TTSStartTransmittingFilenameAndPath string - TTSStopTransmitting bool - TTSStopTransmittingFilenameAndPath string - TTSListOnlineUsers bool - TTSListOnlineUsersFilenameAndPath string - TTSPlayStream bool - TTSPlayStreamFilenameAndPath string - TTSRequestGpsPosition bool - TTSRequestGpsPositionFilenameAndPath string - TTSNextServer bool - TTSNextServerFilenameAndPath string - TTSPreviousServer bool - TTSPreviousServerFilenameAndPath string - TTSPanicSimulation bool - TTSPanicSimulationFilenameAndPath string - TTSPrintXmlConfig bool - TTSPrintXmlConfigFilenameAndPath string - TTSSendEmail bool - TTSSendEmailFilenameAndPath string - TTSDisplayMenu bool - TTSDisplayMenuFilenameAndPath string - TTSQuitTalkkonnect bool - TTSQuitTalkkonnectFilenameAndPath string - TTSTalkkonnectLoaded bool - TTSTalkkonnectLoadedFilenameAndPath string - TTSPingServers bool - TTSPingServersFilenameAndPath string - TTSScan bool - TTSScanFilenameAndPath string -) - -//gmail smtp settings -var ( - EmailEnabled bool - EmailUsername string - EmailPassword string - EmailReceiver string - EmailSubject string - EmailMessage string - EmailGpsDateTime bool - EmailGpsLatLong bool - EmailGoogleMapsURL bool -) - -//sound settings -var ( - EventSoundEnabled bool - EventVolume float32 - EventJoinedSoundFilenameAndPath string - EventLeftSoundFilenameAndPath string - EventMessageSoundFilenameAndPath string - AlertSoundEnabled bool - AlertSoundFilenameAndPath string - AlertSoundVolume float32 = 1 - IncommingBeepSoundEnabled bool - IncommingBeepSoundFilenameAndPath string - IncommingBeepSoundVolume float32 - RogerBeepSoundEnabled bool - RogerBeepSoundFilenameAndPath string - RogerBeepSoundVolume float32 - RepeaterToneEnabled bool - RepeaterToneFrequencyHz int - RepeaterToneDurationSec int - StreamSoundEnabled bool - StreamSoundFilenameAndPath string - StreamSoundVolume float32 -) - -//api settings -var ( - APIEnabled bool - APIListenPort string - APIDisplayMenu bool - APIChannelUp bool - APIChannelDown bool - APIMute bool - APICurrentVolumeLevel bool - APIDigitalVolumeUp bool - APIDigitalVolumeDown bool - APIListServerChannels bool - APIStartTransmitting bool - APIStopTransmitting bool - APIListOnlineUsers bool - APIPlayStream bool - APIRequestGpsPosition bool - APIEmailEnabled bool - APINextServer bool - APIPreviousServer bool - APIPanicSimulation bool - APIScanChannels bool - APIDisplayVersion bool - APIClearScreen bool - APIPingServersEnabled bool - APIRepeatTxLoopTest bool - APIPrintXmlConfig bool - APIPlayRepeaterTone bool - APISetVoiceTarget bool -) - -//print xml config sections for easy debugging, set any section to false to prevent printing to screen -var ( - PrintAccount bool - PrintLogging bool - PrintProvisioning bool - PrintBeacon bool - PrintTTS bool - PrintIgnoreUser bool - PrintSMTP bool - PrintSounds bool - PrintTxTimeout bool - PrintHTTPAPI bool - PrintTargetboard bool - PrintLeds bool - PrintHeartbeat bool - PrintButtons bool - PrintRelays bool - PrintComment bool - PrintLcd bool - PrintOled bool - PrintGps bool - PrintTraccar bool - PrintPanic bool - PrintAudioRecord bool - PrintMQTT bool - PrintTTSMessages bool - PrintKeyboardMap bool - PrintUSBKeyboard bool -) - -// mqtt settings -var ( - MQTTEnabled bool = false - Iotuuid string - RelayAllState bool = false - RelayPulseMills time.Duration - TotalRelays uint - RelayPins = [9]uint{} - MQTTTopic string - MQTTBroker string - MQTTPassword string - MQTTUser string - MQTTId string - MQTTCleansess bool - MQTTQos int - MQTTNum int - MQTTPayload string - MQTTAction string - MQTTStore string - MQTTAttentionBlinkTimes int - MQTTAttentionBlinkmsecs int -) - -// ttsmessages settings -var ( - TTSMessageEnabled bool - TTSLocalPlay bool - TTSLocalPlayWithRXLED bool - TTSPlayIntoStream bool - TTSSoundDirectory string = "/sounds" - TTSLanguage string = "en" - TTSAnnouncementTone string = "" - TTSMessageFromTag bool = true -) - -var ( - IgnoreUserEnabled bool - IgnoreUserRegex string -) - -//indicator light settings -var ( - LedStripEnabled bool - VoiceActivityLEDPin uint - ParticipantsLEDPin uint - TransmitLEDPin uint - OnlineLEDPin uint - AttentionLEDPin uint - HeartBeatLEDPin uint - VoiceTargetLEDPin uint - - VoiceActivityLED gpio.Pin - ParticipantsLED gpio.Pin - TransmitLED gpio.Pin - OnlineLED gpio.Pin - AttentionLED gpio.Pin - HeartBeatLED gpio.Pin - BackLightLED gpio.Pin - VoiceTargetLED gpio.Pin -) - -//heartbeat light settings -var ( - HeartBeatEnabled bool - PeriodmSecs int - LEDOnmSecs int - LEDOffmSecs int -) - -//button settings -var ( - TxButton gpio.Pin - TxButtonPin uint - TxButtonState uint - - TxToggle gpio.Pin - TxTogglePin uint - TxToggleState uint - - UpButton gpio.Pin - UpButtonPin uint - UpButtonState uint - - DownButton gpio.Pin - DownButtonPin uint - DownButtonState uint - - PanicButton gpio.Pin - PanicButtonPin uint - PanicButtonState uint - - CommentButton gpio.Pin - CommentButtonPin uint - CommentButtonState uint - - StreamButton gpio.Pin - StreamButtonPin uint - StreamButtonState uint -) - -var ( - Relay0Pin int - Relay1Pin int - Relay2Pin int - Relay3Pin int - Relay0 gpio.Pin - Relay1 gpio.Pin - Relay2 gpio.Pin - Relay3 gpio.Pin -) - -//comment settings -var ( - CommentMessageOff string - CommentMessageOn string -) - -//HD44780 screen lcd settings -var ( - LCDEnabled bool - LCDInterfaceType string - LCDI2CAddress uint8 - LCDBackLightTimerEnabled bool - LCDBackLightTimeout time.Duration - LCDBackLightLEDPin int - LCDRSPin int - LCDEPin int - LCDD4Pin int - LCDD5Pin int - LCDD6Pin int - LCDD7Pin int - LCDIsDark bool -) - -//OLED screen settings -var ( - OLEDEnabled bool - OLEDInterfacetype string - OLEDDefaultI2cAddress uint8 - OLEDDefaultI2cBus int - OLEDScreenWidth int - OLEDScreenHeight int - OLEDDisplayRows int - OLEDDisplayColumns uint8 - OLEDStartColumn int - OLEDCharLength int - OLEDCommandColumnAddressing int - OLEDAddressBasePageStart int - Oled *goled.Oled -) - -//txtimeout settings -var ( - TxTimeOutEnabled bool - TxTimeOutSecs int -) - -//gps settings -var ( - GpsEnabled bool - Port string - Baud uint - TxData string - Even bool - Odd bool - Rs485 bool - Rs485HighDuringSend bool - Rs485HighAfterSend bool - StopBits uint - DataBits uint - CharTimeOut uint - MinRead uint - Rx bool - GpsInfoVerbose bool -) - -//traccar -var ( - TrackEnabled bool - TraccarSendTo bool - TraccarServerURL string - TraccarServerIP string - TraccarClientId string - TraccarReportFrequency int64 - TraccarProto string - TraccarServerFullURL string - TrackGPSShowLCD bool - TrackVerbose bool - TraccarPortT55 string = "5005" // Old Traccar Client port 5005 for working with T55 Protocol - TraccarPortOpenGTS string = "5159" // Traccar Client port 5159 for for working OpenGTS Protocol - TraccarPortOsmAnd string = "5055" // Traccar Client port 5055 for working with OsmAnd Protocol - GPSTime string - GPSDate string - GPSLatitude float64 - GPSLongitude float64 - GPSSpeed float64 - GPSCourse float64 - GPSVariation float64 -) - -//panic function settings -var ( - PEnabled bool - PFilenameAndPath string - PMessage string - PMailEnabled bool - PRecursive bool - PVolume float32 - PSendIdent bool - PSendGpsLocation bool - PTxLockEnabled bool - PTxlockTimeOutSecs uint - PLowProfile bool -) - -// audio recording -var ( - AudioRecordEnabled bool - AudioRecordOnStart bool - AudioRecordSystem string - AudioRecordMode string - AudioRecordTimeout int64 - AudioRecordFromOutput string - AudioRecordFromInput string - AudioRecordMicTimeout int64 - AudioRecordSoft string - AudioRecordSavePath string - AudioRecordArchivePath string - AudioRecordProfile string - AudioRecordFileFormat string - AudioRecordChunkSize string -) - -//keyboard settings -var ( - USBKeyboardPath string = "/dev/input/event0" - USBKeyboardEnabled bool - NumlockScanID rune - TTYKeyMap = make(map[rune]TTYKBStruct) - USBKeyMap = make(map[rune]USBKBStruct) + talkkonnectVersion string = "2.03.03" + talkkonnectReleased string = "Oct 29 2021" ) -//read xml config into struct -var Document DocumentStruct - -type DocumentStruct struct { +type ConfigStruct struct { XMLName xml.Name `xml:"document"` Accounts struct { Account []struct { @@ -577,18 +95,20 @@ type DocumentStruct struct { Global struct { Software struct { Settings struct { + SingleInstance bool `xml:"singleinstance"` OutputDevice string `xml:"outputdevice"` OutputDeviceShort string `xml:"outputdeviceshort"` LogFilenameAndPath string `xml:"logfilenameandpath"` Logging string `xml:"logging"` Loglevel string `xml:"loglevel"` - Daemonize bool `xml:"daemonize"` CancellableStream bool `xml:"cancellablestream"` StreamOnStart bool `xml:"streamonstart"` StreamOnStartAfter time.Duration `xml:"streamonstartafter"` + StreamSendMessage bool `xml:"streamsendmessage"` TXOnStart bool `xml:"txonstart"` TXOnStartAfter time.Duration `xml:"txonstartafter"` RepeatTXTimes int `xml:"repeattxtimes"` + RepeatTXDelay time.Duration `xml:"repeattxdelay"` SimplexWithMute bool `xml:"simplexwithmute"` TxCounter bool `xml:"txcounter"` NextServerIndex int `xml:"nextserverindex"` @@ -607,51 +127,15 @@ type DocumentStruct struct { Volume float32 `xml:"volume"` } `xml:"beacon"` TTS struct { - Enabled bool `xml:"enabled,attr"` - VolumeLevel float32 `xml:"volumelevel"` - Participants bool `xml:"participants"` - ChannelUp bool `xml:"channelup"` - ChannelUpFilenameAndPath string `xml:"channelupfilenameandpath"` - ChannelDown bool `xml:"channeldown"` - ChannelDownFilenameAndPath string `xml:"channeldownfilenameandpath"` - MuteUnmuteSpeaker bool `xml:"muteunmutespeaker"` - MuteUnmuteSpeakerFilenameAndPath string `xml:"muteunmutespeakerfilenameandpath"` - CurrentVolumeLevel bool `xml:"currentvolumelevel"` - CurrentVolumeLevelFilenameAndPath string `xml:"currentvolumelevelfilenameandpath"` - DigitalVolumeUp bool `xml:"digitalvolumeup"` - DigitalVolumeUpFilenameAndPath string `xml:"digitalvolumeupfilenameandpath"` - DigitalVolumeDown bool `xml:"digitalvolumedown"` - DigitalVolumeDownFilenameAndPath string `xml:"digitalvolumedownfilenameandpath"` - ListServerChannels bool `xml:"listserverchannels"` - ListServerChannelsFilenameAndPath string `xml:"listserverchannelsfilenameandpath"` - StartTransmitting bool `xml:"starttransmitting"` - StartTransmittingFilenameAndPath string `xml:"starttransmittingfilenameandpath"` - StopTransmitting bool `xml:"stoptransmitting"` - StopTransmittingFilenameAndPath string `xml:"stoptransmittingfilenameandpath"` - ListOnlineUsers bool `xml:"listonlineusers"` - ListOnlineUsersFilenameAndPath string `xml:"listonlineusersfilenameandpath"` - PlayStream bool `xml:"playstream"` - PlayStreamFilenameAndPath string `xml:"playstreamfilenameandpath"` - RequestGpsPosition bool `xml:"requestgpsposition"` - RequestGpsPositionFilenameAndPath string `xml:"requestgpspositionfilenameandpath"` - NextServer bool `xml:"nextserver"` - NextServerFilenameAndPath string `xml:"nextserverfilenameandpath"` - PreviousServer bool `xml:"previousserver"` - PreviousServerFilenameAndPath string `xml:"previousserverfilenameandpath"` - PanicSimulation bool `xml:"panicsimulation"` - PanicSimulationFilenameAndPath string `xml:"panicsimulationfilenameandpath"` - PrintXmlConfig bool `xml:"printxmlconfig"` - PrintXmlConfigFilenameAndPath string `xml:"printxmlconfigfilenameandpath"` - SendEmail bool `xml:"sendemail"` - SendEmailFilenameAndPath string `xml:"sendemailfilenameandpath"` - DisplayMenu bool `xml:"displaymenu"` - DisplayMenuFilenameAndPath string `xml:"displaymenufilenameandpath"` - QuitTalkkonnect bool `xml:"quittalkkonnect"` - QuitTalkkonnectFilenameAndPath string `xml:"quittalkkonnectfilenameandpath"` - TalkkonnectLoaded bool `xml:"talkkonnectloaded"` - TalkkonnectLoadedFilenameAndPath string `xml:"talkkonnectloadedfilenameandpath"` - PingServers bool `xml:"pingservers"` - PingServersFilenameAndPath string `xml:"pingserversfilenameandpath"` + Enabled bool `xml:"enabled,attr"` + Volumelevel int `xml:"volumelevel"` + Language string `xml:"language,attr"` + Sound []struct { + Action string `xml:"action,attr"` + File string `xml:"file,attr"` + Blocking bool `xml:"blocking,attr"` + Enabled bool `xml:"enabled,attr"` + } `xml:"sound"` } `xml:"tts"` SMTP struct { Enabled bool `xml:"enabled,attr"` @@ -665,125 +149,127 @@ type DocumentStruct struct { GoogleMapsURL bool `xml:"googlemapsurl"` } `xml:"smtp"` Sounds struct { - Event struct { - Enabled bool `xml:"enabled,attr"` - EventVolume float32 `xml:"eventvolume"` - JoinedFilenameAndPath string `xml:"joinedfilenameandpath"` - LeftFilenameAndPath string `xml:"leftfilenameandpath"` - MessageFilenameAndPath string `xml:"messagefilenameandpath"` - } `xml:"event"` - Alert struct { - Enabled bool `xml:"enabled,attr"` - FilenameAndPath string `xml:"filenameandpath"` - Volume float32 `xml:"volume"` - } `xml:"alert"` - IncommingBeep struct { - Enabled bool `xml:"enabled,attr"` - FilenameAndPath string `xml:"filenameandpath"` - Volume float32 `xml:"volume"` - } `xml:"incommingbeep"` - RogerBeep struct { - Enabled bool `xml:"enabled,attr"` - FilenameAndPath string `xml:"filenameandpath"` - Volume float32 `xml:"volume"` - } `xml:"rogerbeep"` + Sound []struct { + Event string `xml:"event,attr"` + File string `xml:"file,attr"` + Volume string `xml:"volume,attr"` + Blocking bool `xml:"blocking,attr"` + Enabled bool `xml:"enabled,attr"` + } `xml:"sound"` RepeaterTone struct { Enabled bool `xml:"enabled,attr"` ToneFrequencyHz int `xml:"tonefrequencyhz"` ToneDurationSec int `xml:"tonedurationsec"` + Sound struct { + Event string `xml:"event,attr"` + Tonefrequencyhz int `xml:"tonefrequencyhz,attr"` + Volume int `xml:"volume,attr"` + Tonedurationsec int `xml:"tonedurationsec,attr"` + Blocking bool `xml:"blocking,attr"` + Enabled bool `xml:"enabled,attr"` + } `xml:"sound"` } `xml:"repeatertone"` - Stream struct { - Enabled bool `xml:"enabled,attr"` - FilenameAndPath string `xml:"filenameandpath"` - Volume float32 `xml:"volume"` - } `xml:"stream"` } `xml:"sounds"` TxTimeOut struct { Enabled bool `xml:"enabled,attr"` TxTimeOutSecs int `xml:"txtimeoutsecs"` } `xml:"txtimeout"` - API struct { - Enabled bool `xml:"enabled,attr"` - ListenPort string `xml:"apilistenport"` - DisplayMenu bool `xml:"displaymenu"` - ChannelUp bool `xml:"channelup"` - ChannelDown bool `xml:"channeldown"` - Mute bool `xml:"mute"` - CurrentVolumeLevel bool `xml:"currentvolumelevel"` - DigitalVolumeUp bool `xml:"digitalvolumeup"` - DigitalVolumeDown bool `xml:"digitalvolumedown"` - ListServerChannels bool `xml:"listserverchannels"` - StartTransmitting bool `xml:"starttransmitting"` - StopTransmitting bool `xml:"stoptransmitting"` - ListOnlineUsers bool `xml:"listonlineusers"` - PlayStream bool `xml:"playstream"` - RequestGpsPosition bool `xml:"requestgpsposition"` - PreviousServer bool `xml:"previousserver"` - NextServer bool `xml:"nextserver"` - PanicSimulation bool `xml:"panicsimulation"` - ScanChannels bool `xml:"scanchannels"` - DisplayVersion bool `xml:"displayversion"` - ClearScreen bool `xml:"clearscreen"` - RepeatTxLoopTest bool `xml:"repeattxlooptest"` - PrintXmlConfig bool `xml:"printxmlconfig"` - SendEmail bool `xml:"sendemail"` - PingServers bool `xml:"pingservers"` - PlayRepeaterTone bool `xml:"playrepeatertone"` - SetVoiceTarget bool `xml:"setvoicetarget"` - } `xml:"api"` + RemoteControl struct { + XMLName xml.Name `xml:"remotecontrol"` + HTTP struct { + Enabled bool `xml:"enabled,attr"` + ListenPort string `xml:"listenport,attr"` + Command []struct { + Action string `xml:"action,attr"` + Funcname string `xml:"funcname,attr"` + Funcparamname string `xml:"funcparamname,attr"` + Message string `xml:"message,attr"` + Enabled bool `xml:"enabled,attr"` + } `xml:"command"` + } `xml:"http"` + MQTT struct { + Enabled bool `xml:"enabled,attr"` + Settings struct { + MQTTEnabled bool `xml:"enabled,attr"` + MQTTTopic string `xml:"mqtttopic"` + MQTTBroker string `xml:"mqttbroker"` + MQTTPassword string `xml:"mqttpassword"` + MQTTUser string `xml:"mqttuser"` + MQTTId string `xml:"mqttid"` + MQTTCleansess bool `xml:"cleansess"` + MQTTQos int `xml:"qos"` + MQTTNum int `xml:"num"` + MQTTPayload string `xml:"payload"` + MQTTAction string `xml:"action"` + MQTTStore string `xml:"store"` + MQTTAttentionBlinkTimes int `xml:"attentionblinktimes"` + MQTTAttentionBlinkmsecs int `xml:"attentionblinkmsecs"` + } `xml:"settings"` + Commands struct { + Command []struct { + Action string `xml:"action,attr"` + Message string `xml:"message,attr"` + Enabled bool `xml:"enabled,attr"` + } `xml:"command"` + } `xml:"commands"` + } `xml:"mqtt"` + } PrintVariables struct { - PrintAccount bool `xml:"printaccount"` - PrintLogging bool `xml:"printlogging"` - PrintProvisioning bool `xml:"printprovisioning"` - PrintBeacon bool `xml:"printbeacon"` - PrintTTS bool `xml:"printtts"` - PrintIgnoreUser bool `xml:"printignoreuser"` - PrintSMTP bool `xml:"printsmtp"` - PrintSounds bool `xml:"printsounds"` - PrintTxTimeout bool `xml:"printtxtimeout"` - PrintHTTPAPI bool `xml:"printhttpapi"` - PrintTargetBoard bool `xml:"printtargetboard"` - PrintLeds bool `xml:"printleds"` - PrintHeartbeat bool `xml:"printheartbeat"` - PrintButtons bool `xml:"printbuttons"` - PrintRelays bool `xml:"printrelays"` - PrintComment bool `xml:"printcomment"` - PrintLcd bool `xml:"printlcd"` - PrintOled bool `xml:"printoled"` - PrintGps bool `xml:"printgps"` - PrintTraccar bool `xml:"printtraccar"` - PrintPanic bool `xml:"printpanic"` - PrintAudioRecord bool `xml:"printaudiorecord"` - PrintMQTT bool `xml:"printmqtt"` - PrintTTSMessages bool `xml:"printttsmessages"` - PrintKeyboardMap bool `xml:"printkeyboardmap"` - PrintUSBKeyboard bool `xml:"printusbkeyboard"` + PrintAccount bool `xml:"printaccount"` + PrintSystemSettings bool `xml:"printsystemsettings"` + PrintProvisioning bool `xml:"printprovisioning"` + PrintBeacon bool `xml:"printbeacon"` + PrintTTS bool `xml:"printtts"` + PrintIgnoreUser bool `xml:"printignoreuser"` + PrintSMTP bool `xml:"printsmtp"` + PrintSounds bool `xml:"printsounds"` + PrintTxTimeout bool `xml:"printtxtimeout"` + PrintHTTPAPI bool `xml:"printhttpapi"` + PrintTargetBoard bool `xml:"printtargetboard"` + PrintLeds bool `xml:"printleds"` + PrintHeartbeat bool `xml:"printheartbeat"` + PrintGPIO bool `xml:"printgpio"` + PrintButtons bool `xml:"printbuttons"` + PrintComment bool `xml:"printcomment"` + PrintLcd bool `xml:"printlcd"` + PrintOled bool `xml:"printoled"` + PrintGps bool `xml:"printgps"` + PrintTraccar bool `xml:"printtraccar"` + PrintPanic bool `xml:"printpanic"` + PrintAudioRecord bool `xml:"printaudiorecord"` + PrintMQTT bool `xml:"printmqtt"` + PrintTTSMessages bool `xml:"printttsmessages"` + PrintKeyboardMap bool `xml:"printkeyboardmap"` + PrintUSBKeyboard bool `xml:"printusbkeyboard"` + PrintMultimedia bool `xml:"printmultimedia"` } `xml:"printvariables"` - MQTT struct { - MQTTEnabled bool `xml:"enabled,attr"` - MQTTTopic string `xml:"mqtttopic"` - MQTTBroker string `xml:"mqttbroker"` - MQTTPassword string `xml:"mqttpassword"` - MQTTUser string `xml:"mqttuser"` - MQTTId string `xml:"mqttid"` - MQTTCleansess bool `xml:"cleansess"` - MQTTQos int `xml:"qos"` - MQTTNum int `xml:"num"` - MQTTPayload string `xml:"payload"` - MQTTAction string `xml:"action"` - MQTTStore string `xml:"store"` - MQTTAttentionBlinkTimes int `xml:"attentionblinktimes"` - MQTTAttentionBlinkmsecs int `xml:"attentionblinkmsecs"` - } `xml:"mqtt"` TTSMessages struct { - TTSMessageEnabled bool `xml:"enabled,attr"` - TTSLocalPlay bool `xml:"localplay"` - TTSLocalPlayWithRXLED bool `xml:"localplaywithrxled"` - TTSPlayIntoStream bool `xml:"playintostream"` - TTSSoundDirectory string `xml:"ttssounddirectory"` - TTSLanguage string `xml:"ttslanguage"` - TTSAnnouncementTone string `xml:"ttsannouncementtone"` - TTSMessageFromTag bool `xml:"ttsmessagefromtag"` + Enabled bool `xml:"enabled,attr"` + TTSLanguage string `xml:"ttslanguage"` + TTSMessageFromTag bool `xml:"ttsmessagefromtag"` + TTSTone struct { + ToneEnabled bool `xml:"enabled,attr"` + ToneFile string `xml:"file,attr"` + ToneVolume int `xml:"volume,attr"` + } `xml:"ttstone"` + Blocking bool `xml:"localblocking"` + TTSSoundDirectory string `xml:"ttssounddirectory"` + LocalPlay bool `xml:"localplay"` + PlayIntoStream bool `xml:"playintostream"` + SpeakVolumeIntoStream int `xml:"speakvolumeintostream"` + PlayVolumeIntoStream float32 `xml:"playvolumeintostream"` + GPIO struct { + Name string `xml:"name,attr"` + Enabled bool `xml:"enabled,attr"` + } `xml:"gpio"` + PreDelay struct { + Value time.Duration `xml:"value,attr"` + Enabled bool `xml:"enabled,attr"` + } `xml:"predelay"` + PostDelay struct { + Value time.Duration `xml:"value,attr"` + Enabled bool `xml:"enabled,attr"` + } `xml:"postdelay"` } `xml:"ttsmessages"` IgnoreUser struct { IgnoreUserEnabled bool `xml:"enabled,attr"` @@ -791,16 +277,42 @@ type DocumentStruct struct { } `xml:"ignoreuser"` } `xml:"software"` Hardware struct { - TargetBoard string `xml:"targetboard,attr"` - Lights struct { - LedStripEnabled bool `xml:"ledstripenabled"` - VoiceActivityLedPin string `xml:"voiceactivityledpin"` - ParticipantsLedPin string `xml:"participantsledpin"` - TransmitLedPin string `xml:"transmitledpin"` - OnlineLedPin string `xml:"onlineledpin"` - AttentionLedPin string `xml:"attentionledpin"` - VoiceTargetLedPin string `xml:"voicetargetledpin"` - } `xml:"lights"` + TargetBoard string `xml:"targetboard,attr"` + LedStripEnabled bool `xml:"ledstripenabled"` + IO struct { + GPIOExpander struct { + Enabled bool `xml:"enabled,attr"` + Chip []struct { + ID int `xml:"id,attr"` + I2Cbus uint8 `xml:"i2cbus,attr"` + MCP23017Device uint8 `xml:"mcp23017device,attr"` + Enabled bool `xml:"enabled,attr"` + } `xml:"chip"` + } `xml:"gpioexpander"` + Max7219 struct { + Enabled bool `xml:"enabled,attr"` + Max7219Cascaded int `xml:"max7219cascaded,attr"` + SPIBus int `xml:"spibus,attr"` + SPIDevice int `xml:"spidevice,attr"` + Brightness byte `xml:"brightness,attr"` + } `xml:"max7219"` + Pins struct { + Pin []struct { + Direction string `xml:"direction,attr"` + Device string `xml:"device,attr"` + Name string `xml:"name,attr"` + PinNo uint `xml:"pinno,attr"` + Type string `xml:"type,attr"` + ID int `xml:"chipid,attr"` + Enabled bool `xml:"enabled,attr"` + } `xml:"pin"` + } `xml:"pins"` + Pulse struct { + Leading time.Duration `xml:"leadingmsecs,attr"` + Pulse time.Duration `xml:"pulsemsecs,attr"` + Trailing time.Duration `xml:"trailingmsecs,attr"` + } `xml:"pulse"` + } `xml:"io"` HeartBeat struct { Enabled bool `xml:"enabled,attr"` LEDPin string `xml:"heartbeatledpin"` @@ -808,20 +320,6 @@ type DocumentStruct struct { LEDOnmsecs int `xml:"ledonmsecs"` LEDOffmsecs int `xml:"ledoffmsecs"` } `xml:"heartbeat"` - Buttons struct { - TxButtonPin string `xml:"txbuttonpin"` - TxTogglePin string `xml:"txtogglepin"` - UpButtonPin string `xml:"upbuttonpin"` - DownButtonPin string `xml:"downbuttonpin"` - PanicButtonPin string `xml:"panicbuttonpin"` - StreamButtonPin string `xml:"streambuttonpin"` - } `xml:"buttons"` - Relays struct { - Relay0Pin string `xml:"relay0pin"` - Relay1Pin string `xml:"relay1pin"` - Relay2Pin string `xml:"relay2pin"` - Relay3Pin string `xml:"relay3pin"` - } `xml:"relays"` Comment struct { CommentButtonPin string `xml:"commentbuttonpin"` CommentMessageOff string `xml:"commentmessageoff"` @@ -888,11 +386,12 @@ type DocumentStruct struct { Enabled bool `xml:"enabled,attr"` FilenameAndPath string `xml:"filenameandpath"` Volume float32 `xml:"volume"` + Blocking bool `xml:"blocking,attr"` SendIdent bool `xml:"sendident"` Message string `xml:"panicmessage"` PMailEnabled bool `xml:"panicemail"` PEavesdropEnabled bool `xml:"eavesdrop"` - RecursiveSendMessage string `xml:"recursivesendmessage"` + RecursiveSendMessage bool `xml:"recursivesendmessage"` SendGpsLocation bool `xml:"sendgpslocation"` TxLockEnabled bool `xml:"txlockenabled"` TxLockTimeOutSecs uint `xml:"txlocktimeoutsecs"` @@ -919,29 +418,66 @@ type DocumentStruct struct { RecordFileFormat string `xml:"recordfileformat"` RecordChunkSize string `xml:"recordchunksize"` } `xml:"audiorecordfunction"` - KeyboardCommands struct { + Keyboard struct { Command []struct { - Name string `xml:"name,attr"` - Enabled bool `xml:"enabled,attr"` - Params struct { - Param []struct { - Name string `xml:"name,attr"` - Value string `xml:"value,attr"` - } `xml:"param"` - } `xml:"params"` + Action string `xml:"action,attr"` + ParamName string `xml:"paramname,attr"` + Paramvalue string `xml:"paramvalue,attr"` + Enabled bool `xml:"enabled,attr"` Ttykeyboard struct { Scanid rune `xml:"scanid,attr"` + Keylabel uint32 `xml:"keylabel,attr"` Enabled bool `xml:"enabled,attr"` - Keylabel uint32 `xml:"keylabel"` } `xml:"ttykeyboard"` Usbkeyboard struct { Scanid rune `xml:"scanid,attr"` + Keylabel uint32 `xml:"keylabel,attr"` Enabled bool `xml:"enabled,attr"` - Keylabel uint32 `xml:"keylabel"` } `xml:"usbkeyboard"` } `xml:"command"` - } `xml:"keyboardcommands"` + } `xml:"keyboard"` } `xml:"hardware"` + Multimedia struct { + ID []struct { + Value string `xml:"value,attr"` + Enabled bool `xml:"enabled,attr"` + Params struct { + Announcementtone struct { + File string `xml:"file,attr"` + Volume int `xml:"volume,attr"` + Blocking bool `xml:"blocking"` + Enabled bool `xml:"enabled,attr"` + } `xml:"announcementtone"` + Localplay bool `xml:"localplay"` + GPIO struct { + Name string `xml:"name,attr"` + Enabled bool `xml:"enabled,attr"` + } `xml:"gpio"` + Predelay struct { + Value time.Duration `xml:"value,attr"` + Enabled bool `xml:"enabled,attr"` + } `xml:"predelay"` + Postdelay struct { + Value time.Duration `xml:"value,attr"` + Enabled bool `xml:"enabled,attr"` + } `xml:"postdelay"` + Playintostream bool `xml:"playintostream"` + Voicetarget string `xml:"voicetarget"` + } `xml:"params"` + Media struct { + Source []struct { + Name string `xml:"name,attr"` + File string `xml:"file,attr"` + Volume int `xml:"volume,attr"` + Duration float32 `xml:"duration,attr"` + Offset float32 `xml:"offset,attr"` + Loop int `xml:"loop,attr"` + Blocking bool `xml:"blocking"` + Enabled bool `xml:"enabled,attr"` + } `xml:"source"` + } `xml:"media"` + } `xml:"id"` + } `xml:"multimedia"` } `xml:"global"` } @@ -978,7 +514,125 @@ type USBKBStruct struct { ParamValue string } -func readxmlconfig(file string) error { +type EventSoundStruct struct { + Enabled bool + FileName string + Volume string + Blocking bool +} + +type streamTrackerStruct struct { + UserID uint32 + UserName string + UserSession uint32 + C <-chan *gumble.AudioPacket +} + +// Generic Global Config Variables +var Config ConfigStruct +var ConfigXMLFile string + +// Generic Global State Variables +var ( + KillHeartBeat bool + IsPlayStream bool + IsConnected bool + Streaming bool + HTTPServRunning bool + NowStreaming bool + InStreamTalking bool + InStreamSource bool + LCDIsDark bool +) + +// Generic Global Counter Variables +var ( + AccountCount int + ConnectAttempts int + AccountIndex int + GenericCounter int + ChannelIndex int +) + +// Generic Global Timer Variables +var ( + BackLightTime = time.NewTicker(5 * time.Second) + BackLightTimePtr = &BackLightTime + StartTime = time.Now() + LastTime = now.Unix() + TimerTalked = time.NewTicker(time.Millisecond * 200) +) + +var ( + LcdText = [4]string{"nil", "nil", "nil", "nil"} + MyLedStrip *LedStrip + TTYKeyMap = make(map[rune]TTYKBStruct) + USBKeyMap = make(map[rune]USBKBStruct) +) + +//Mumble Account Settings Global Variables +var ( + Default []bool + Name []string + Server []string + Username []string + Password []string + Insecure []bool + Register []bool + Certificate []string + Channel []string + Ident []string + Tokens []gumble.AccessTokens + VT []VTStruct + Accounts int + MaxTokensInAccounts int +) + +//HD44780 LCD Screen Settings Golbal Variables +var ( + LCDEnabled bool + LCDInterfaceType string + LCDI2CAddress uint8 + LCDBackLightTimerEnabled bool + LCDBackLightTimeout time.Duration + LCDRSPin int + LCDEPin int + LCDD4Pin int + LCDD5Pin int + LCDD6Pin int + LCDD7Pin int +) + +//OLED Screen Settings Golbal Variables +var ( + OLEDEnabled bool + OLEDInterfacetype string + OLEDDefaultI2cAddress uint8 + OLEDDefaultI2cBus int + OLEDScreenWidth int + OLEDScreenHeight int + OLEDDisplayRows int + OLEDDisplayColumns uint8 + OLEDStartColumn int + OLEDCharLength int + OLEDCommandColumnAddressing int + OLEDAddressBasePageStart int + Oled *goled.Oled +) + +// Generic Local Variables +var ( + txcounter int + isTx bool + pstream *gumbleffmpeg.Stream + //source = openal.NewSource() +) + +var StreamTracker = map[uint32]streamTrackerStruct{} + +func readxmlconfig(file string, reloadxml bool) error { + var ReConfig ConfigStruct + xmlFile, err := os.Open(file) if err != nil { return fmt.Errorf(err.Error()) @@ -988,41 +642,46 @@ func readxmlconfig(file string) error { byteValue, _ := ioutil.ReadAll(xmlFile) - err = xml.Unmarshal(byteValue, &Document) - if err != nil { - return fmt.Errorf(filepath.Base(file) + " " + err.Error()) - } - for _, account := range Document.Accounts.Account { - if account.Default { - Name = append(Name, account.Name) - Server = append(Server, account.ServerAndPort) - Username = append(Username, account.UserName) - Password = append(Password, account.Password) - Insecure = append(Insecure, account.Insecure) - Register = append(Register, account.Register) - Certificate = append(Certificate, account.Certificate) - Channel = append(Channel, account.Channel) - Ident = append(Ident, account.Ident) - Tokens = append(Tokens, account.Tokens.Token) - VT = append(VT, VTStruct(account.Voicetargets)) - AccountCount++ + if !reloadxml { + err = xml.Unmarshal(byteValue, &Config) + if err != nil { + return fmt.Errorf(filepath.Base(file) + " " + err.Error()) + } + } else { + err = xml.Unmarshal(byteValue, &ReConfig) + if err != nil { + return fmt.Errorf(filepath.Base(file) + " " + err.Error()) } } - - if AccountCount == 0 { - FatalCleanUp("No Default Accounts Found in talkkonnect.xml File! Please Add At Least 1 Account in XML") + CheckConfigSanity(reloadxml) + + if !reloadxml { + for _, account := range Config.Accounts.Account { + if account.Default { + Name = append(Name, account.Name) + Server = append(Server, account.ServerAndPort) + Username = append(Username, account.UserName) + Password = append(Password, account.Password) + Insecure = append(Insecure, account.Insecure) + Register = append(Register, account.Register) + Certificate = append(Certificate, account.Certificate) + Channel = append(Channel, account.Channel) + Ident = append(Ident, account.Ident) + Tokens = append(Tokens, account.Tokens.Token) + VT = append(VT, VTStruct(account.Voicetargets)) + AccountCount++ + } + } } - - for _, KMainCommands := range Document.Global.Hardware.KeyboardCommands.Command { - if KMainCommands.Enabled { - for _, KSubCommands := range KMainCommands.Params.Param { - if KMainCommands.Ttykeyboard.Enabled { - TTYKeyMap[KMainCommands.Ttykeyboard.Scanid] = TTYKBStruct{KMainCommands.Ttykeyboard.Enabled, KMainCommands.Ttykeyboard.Keylabel, KMainCommands.Name, KSubCommands.Name, KSubCommands.Value} - } - if KMainCommands.Usbkeyboard.Enabled { - USBKeyMap[KMainCommands.Usbkeyboard.Scanid] = USBKBStruct{KMainCommands.Usbkeyboard.Enabled, KMainCommands.Usbkeyboard.Keylabel, KMainCommands.Name, KSubCommands.Name, KSubCommands.Value} - } + for _, kMainCommands := range Config.Global.Hardware.Keyboard.Command { + if kMainCommands.Enabled { + if kMainCommands.Ttykeyboard.Enabled { + TTYKeyMap[kMainCommands.Ttykeyboard.Scanid] = TTYKBStruct{kMainCommands.Ttykeyboard.Enabled, kMainCommands.Ttykeyboard.Keylabel, kMainCommands.Action, kMainCommands.ParamName, kMainCommands.Paramvalue} } + if kMainCommands.Usbkeyboard.Enabled { + USBKeyMap[kMainCommands.Usbkeyboard.Scanid] = USBKBStruct{kMainCommands.Usbkeyboard.Enabled, kMainCommands.Usbkeyboard.Keylabel, kMainCommands.Action, kMainCommands.ParamName, kMainCommands.Paramvalue} + } + } } @@ -1066,913 +725,272 @@ func readxmlconfig(file string) error { f.Close() } - // Set our default sharefile path - defaultSharePath := "/tmp" - dir := filepath.Dir(exec) - //Check for soundfiles directory in various locations - // First, check env for $GOPATH and check in the hardcoded talkkonnect/talkkonnect dir - if os.Getenv("GOPATH") != "" { - defaultRepo := os.Getenv("GOPATH") + "/src/github.com/talkkonnect/talkkonnect" - if stat, err := os.Stat(defaultRepo); err == nil && stat.IsDir() { - defaultSharePath = defaultRepo + if len(Config.Global.Software.Settings.OutputDeviceShort) == 0 { + Config.Global.Software.Settings.OutputDeviceShort = Config.Global.Software.Settings.OutputDevice + } + + if strings.ToLower(Config.Global.Software.Settings.Logging) != "screen" && Config.Global.Software.Settings.LogFilenameAndPath == "" { + Config.Global.Software.Settings.LogFilenameAndPath = defaultLogPath + } + + if !reloadxml { + LCDEnabled = Config.Global.Hardware.LCD.Enabled + LCDInterfaceType = Config.Global.Hardware.LCD.InterfaceType + LCDI2CAddress = Config.Global.Hardware.LCD.I2CAddress + LCDBackLightTimerEnabled = Config.Global.Hardware.LCD.Enabled + LCDBackLightTimeout = time.Duration(Config.Global.Hardware.LCD.BackLightTimeoutSecs) + LCDRSPin = Config.Global.Hardware.LCD.RsPin + LCDEPin = Config.Global.Hardware.LCD.EPin + LCDD4Pin = Config.Global.Hardware.LCD.D4Pin + LCDD5Pin = Config.Global.Hardware.LCD.D5Pin + LCDD6Pin = Config.Global.Hardware.LCD.D6Pin + LCDD7Pin = Config.Global.Hardware.LCD.D7Pin + + OLEDEnabled = Config.Global.Hardware.OLED.Enabled + OLEDInterfacetype = Config.Global.Hardware.OLED.InterfaceType + OLEDDisplayRows = Config.Global.Hardware.OLED.DisplayRows + OLEDDisplayColumns = Config.Global.Hardware.OLED.DisplayColumns + OLEDDefaultI2cBus = Config.Global.Hardware.OLED.DefaultI2CBus + OLEDDefaultI2cAddress = Config.Global.Hardware.OLED.DefaultI2CAddress + OLEDScreenWidth = Config.Global.Hardware.OLED.ScreenWidth + OLEDScreenHeight = Config.Global.Hardware.OLED.ScreenHeight + OLEDCommandColumnAddressing = Config.Global.Hardware.OLED.CommandColumnAddressing + OLEDAddressBasePageStart = Config.Global.Hardware.OLED.AddressBasePageStart + OLEDCharLength = Config.Global.Hardware.OLED.CharLength + OLEDStartColumn = Config.Global.Hardware.OLED.StartColumn + + if Config.Global.Hardware.TargetBoard != "rpi" { + LCDBackLightTimerEnabled = false } - } - // Next, check the same dir as executable for 'soundfiles' - if stat, err := os.Stat(dir + "/soundfiles"); err == nil && stat.IsDir() { - defaultSharePath = dir - } - // Last, if its in a bin directory, we check for ../share/talkkonnect/ and prioritize it if it exists - if strings.HasSuffix(dir, "bin") { - shareDir := filepath.Dir(dir) + "/share/" + filepath.Base(exec) - if stat, err := os.Stat(shareDir); err == nil && stat.IsDir() { - defaultSharePath = shareDir - } - } - - OutputDevice = Document.Global.Software.Settings.OutputDevice - OutputDeviceShort = Document.Global.Software.Settings.OutputDeviceShort - - if len(OutputDeviceShort) == 0 { - OutputDeviceShort = Document.Global.Software.Settings.OutputDevice - } - - LogFilenameAndPath = Document.Global.Software.Settings.LogFilenameAndPath - Logging = Document.Global.Software.Settings.Logging - - if Document.Global.Software.Settings.Loglevel == "trace" || Document.Global.Software.Settings.Loglevel == "debug" || Document.Global.Software.Settings.Loglevel == "info" || Document.Global.Software.Settings.Loglevel == "warning" || Document.Global.Software.Settings.Loglevel == "error" || Document.Global.Software.Settings.Loglevel == "alert" { - Loglevel = Document.Global.Software.Settings.Loglevel - } - - if strings.ToLower(Logging) != "screen" && LogFilenameAndPath == "" { - LogFilenameAndPath = defaultLogPath - } - - Daemonize = Document.Global.Software.Settings.Daemonize - - CancellableStream = Document.Global.Software.Settings.CancellableStream - StreamOnStart = Document.Global.Software.Settings.StreamOnStart - - StreamOnStartAfter = Document.Global.Software.Settings.StreamOnStartAfter - - TXOnStart = Document.Global.Software.Settings.TXOnStart - - TXOnStartAfter = Document.Global.Software.Settings.TXOnStartAfter - - RepeatTXTimes = Document.Global.Software.Settings.RepeatTXTimes - - SimplexWithMute = Document.Global.Software.Settings.SimplexWithMute - TxCounter = Document.Global.Software.Settings.TxCounter - NextServerIndex = Document.Global.Software.Settings.NextServerIndex - APEnabled = Document.Global.Software.AutoProvisioning.Enabled - TkID = Document.Global.Software.AutoProvisioning.TkID - URL = Document.Global.Software.AutoProvisioning.URL - SaveFilePath = Document.Global.Software.AutoProvisioning.SaveFilePath - SaveFilename = Document.Global.Software.AutoProvisioning.SaveFilename - - if APEnabled && SaveFilePath == "" { - SaveFilePath = defaultConfPath - } - - if APEnabled && SaveFilename == "" { - SaveFilename = filepath.Base(exec) + "talkkonnect.xml" - } - - BeaconEnabled = Document.Global.Software.Beacon.Enabled - BeaconTimerSecs = Document.Global.Software.Beacon.BeaconTimerSecs - BeaconFilenameAndPath = Document.Global.Software.Beacon.BeaconFileAndPath - if BeaconEnabled && BeaconFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/voiceprompts/Beacon.wav" - if _, err := os.Stat(path); err == nil { - BeaconFilenameAndPath = path - } - } - - BVolume = Document.Global.Software.Beacon.Volume - - TTSEnabled = Document.Global.Software.TTS.Enabled - TTSVolumeLevel = Document.Global.Software.TTS.VolumeLevel - TTSParticipants = Document.Global.Software.TTS.Participants - TTSChannelUp = Document.Global.Software.TTS.ChannelUp - TTSChannelUpFilenameAndPath = Document.Global.Software.TTS.ChannelUpFilenameAndPath - - if TTSChannelUp && TTSChannelUpFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/voiceprompts/ChannelUp.wav" - if _, err := os.Stat(path); err == nil { - TTSChannelUpFilenameAndPath = path - } - } - - TTSChannelUpFilenameAndPath = Document.Global.Software.TTS.ChannelUpFilenameAndPath - TTSChannelDown = Document.Global.Software.TTS.ChannelDown - TTSChannelDownFilenameAndPath = Document.Global.Software.TTS.ChannelDownFilenameAndPath - - if TTSChannelDown && TTSChannelDownFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/voiceprompts/ChannelDown.wav" - if _, err := os.Stat(path); err == nil { - TTSChannelDownFilenameAndPath = path - } - } - - TTSMuteUnMuteSpeaker = Document.Global.Software.TTS.MuteUnmuteSpeaker - TTSMuteUnMuteSpeakerFilenameAndPath = Document.Global.Software.TTS.MuteUnmuteSpeakerFilenameAndPath - - if TTSMuteUnMuteSpeaker && TTSMuteUnMuteSpeakerFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/voiceprompts/MuteUnMuteSpeaker.wav" - if _, err := os.Stat(path); err == nil { - TTSMuteUnMuteSpeakerFilenameAndPath = path - } - } - - TTSCurrentVolumeLevel = Document.Global.Software.TTS.CurrentVolumeLevel - TTSCurrentVolumeLevelFilenameAndPath = Document.Global.Software.TTS.CurrentVolumeLevelFilenameAndPath - - if TTSCurrentVolumeLevel && TTSCurrentVolumeLevelFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/voiceprompts/CurrentVolumeLevel.wav" - if _, err := os.Stat(path); err == nil { - TTSCurrentVolumeLevelFilenameAndPath = path - } - } - - TTSDigitalVolumeUp = Document.Global.Software.TTS.DigitalVolumeUp - TTSDigitalVolumeUpFilenameAndPath = Document.Global.Software.TTS.DigitalVolumeUpFilenameAndPath - - if TTSDigitalVolumeUp && TTSDigitalVolumeUpFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/voiceprompts/DigitalVolumeUp.wav" - if _, err := os.Stat(path); err == nil { - TTSDigitalVolumeUpFilenameAndPath = path - } - } - - TTSDigitalVolumeDown = Document.Global.Software.TTS.DigitalVolumeDown - TTSDigitalVolumeDownFilenameAndPath = Document.Global.Software.TTS.DigitalVolumeDownFilenameAndPath - - if TTSDigitalVolumeDown && TTSDigitalVolumeDownFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/voiceprompts/DigitalVolumeDown.wav" - if _, err := os.Stat(path); err == nil { - TTSDigitalVolumeDownFilenameAndPath = path - } - } - - TTSListServerChannels = Document.Global.Software.TTS.ListServerChannels - TTSListServerChannelsFilenameAndPath = Document.Global.Software.TTS.ListServerChannelsFilenameAndPath - - if TTSListServerChannels && TTSListServerChannelsFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/voiceprompts/ListServerChannels.wav" - if _, err := os.Stat(path); err == nil { - TTSListServerChannelsFilenameAndPath = path - } - } - - TTSStartTransmitting = Document.Global.Software.TTS.StartTransmitting - TTSStartTransmittingFilenameAndPath = Document.Global.Software.TTS.StartTransmittingFilenameAndPath - - if TTSStartTransmitting && TTSStartTransmittingFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/voiceprompts/StartTransmitting.wav" - if _, err := os.Stat(path); err == nil { - TTSStartTransmittingFilenameAndPath = path - } - } - - TTSStopTransmitting = Document.Global.Software.TTS.StopTransmitting - TTSStopTransmittingFilenameAndPath = Document.Global.Software.TTS.StopTransmittingFilenameAndPath - - if TTSStopTransmitting && TTSStopTransmittingFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/voiceprompts/StopTransmitting.wav" - if _, err := os.Stat(path); err == nil { - TTSStopTransmittingFilenameAndPath = path - } - } - - TTSListOnlineUsers = Document.Global.Software.TTS.ListOnlineUsers - TTSListOnlineUsersFilenameAndPath = Document.Global.Software.TTS.ListOnlineUsersFilenameAndPath - - if TTSListOnlineUsers && TTSListOnlineUsersFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/voiceprompts/ListOnlineUsers.wav" - if _, err := os.Stat(path); err == nil { - TTSListOnlineUsersFilenameAndPath = path - } - } - - TTSPlayStream = Document.Global.Software.TTS.PlayStream - TTSPlayStreamFilenameAndPath = Document.Global.Software.TTS.PlayStreamFilenameAndPath - - if TTSPlayStream && TTSPlayStreamFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/voiceprompts/PlayStream.wav" - if _, err := os.Stat(path); err == nil { - TTSPlayStreamFilenameAndPath = path - } - } - - TTSRequestGpsPosition = Document.Global.Software.TTS.RequestGpsPosition - TTSRequestGpsPositionFilenameAndPath = Document.Global.Software.TTS.RequestGpsPositionFilenameAndPath - - if TTSRequestGpsPosition && TTSRequestGpsPositionFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/voiceprompts/RequestGpsPosition.wav" - if _, err := os.Stat(path); err == nil { - TTSRequestGpsPositionFilenameAndPath = path - } - } - - TTSNextServer = Document.Global.Software.TTS.NextServer - TTSNextServerFilenameAndPath = Document.Global.Software.TTS.NextServerFilenameAndPath - /* - //TODO: No default sound available. Placeholder for now - if TTSNextServer && TTSNextServerFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/voiceprompts/TODO" - if _, err := os.Stat(path); err == nil { - TTSNextServerFilenameAndPath = path + if OLEDEnabled { + Oled, err = goled.BeginOled(OLEDDefaultI2cAddress, OLEDDefaultI2cBus, OLEDScreenWidth, OLEDScreenHeight, OLEDDisplayRows, OLEDDisplayColumns, OLEDStartColumn, OLEDCharLength, OLEDCommandColumnAddressing, OLEDAddressBasePageStart) + if err != nil { + log.Println("error: Cannot Communicate with OLED") } } - */ - - TTSPreviousServer = Document.Global.Software.TTS.PreviousServer - TTSPreviousServerFilenameAndPath = Document.Global.Software.TTS.PreviousServerFilenameAndPath - - /* - //TODO: No default sound available. Placeholder for now - if TTSPreviousServer && TTSPreviousServerFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/voiceprompts/TODO" - if _, err := os.Stat(path); err == nil { - TTSPreviousServerFilenameAndPath = path - } - } - */ - - TTSPanicSimulation = Document.Global.Software.TTS.PanicSimulation - TTSPanicSimulationFilenameAndPath = Document.Global.Software.TTS.PanicSimulationFilenameAndPath - if TTSPanicSimulation && TTSPanicSimulationFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/voiceprompts/PanicSimulation.wav" - if _, err := os.Stat(path); err == nil { - TTSPanicSimulationFilenameAndPath = path - } } + log.Println("Successfully loaded XML configuration file into memory") - TTSPrintXmlConfig = Document.Global.Software.TTS.PrintXmlConfig - TTSPrintXmlConfigFilenameAndPath = Document.Global.Software.TTS.PrintXmlConfigFilenameAndPath - - if TTSPrintXmlConfig && TTSPrintXmlConfigFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/voiceprompts/PrintXmlConfig.wav" - if _, err := os.Stat(path); err == nil { - TTSPrintXmlConfigFilenameAndPath = path - } - } - - TTSSendEmail = Document.Global.Software.TTS.SendEmail - TTSSendEmailFilenameAndPath = Document.Global.Software.TTS.SendEmailFilenameAndPath - - if TTSSendEmail && TTSSendEmailFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/voiceprompts/SendEmail.wav" - if _, err := os.Stat(path); err == nil { - TTSSendEmailFilenameAndPath = path - } - } - - TTSDisplayMenu = Document.Global.Software.TTS.DisplayMenu - TTSDisplayMenuFilenameAndPath = Document.Global.Software.TTS.DisplayMenuFilenameAndPath - - if TTSDisplayMenu && TTSDisplayMenuFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/voiceprompts/DisplayMenu.wav" - if _, err := os.Stat(path); err == nil { - TTSDisplayMenuFilenameAndPath = path - } - } - - TTSQuitTalkkonnect = Document.Global.Software.TTS.QuitTalkkonnect - TTSQuitTalkkonnectFilenameAndPath = Document.Global.Software.TTS.QuitTalkkonnectFilenameAndPath - - if TTSQuitTalkkonnect && TTSQuitTalkkonnectFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/voiceprompts/QuitTalkkonnect.wav" - if _, err := os.Stat(path); err == nil { - TTSQuitTalkkonnectFilenameAndPath = path - } - } - - TTSTalkkonnectLoaded = Document.Global.Software.TTS.TalkkonnectLoaded - TTSTalkkonnectLoadedFilenameAndPath = Document.Global.Software.TTS.TalkkonnectLoadedFilenameAndPath - - if TTSTalkkonnectLoaded && TTSTalkkonnectLoadedFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/voiceprompts/Loaded.wav" - if _, err := os.Stat(path); err == nil { - TTSTalkkonnectLoadedFilenameAndPath = path - } - } - - TTSPingServers = Document.Global.Software.TTS.PingServers - TTSPingServersFilenameAndPath = Document.Global.Software.TTS.PingServersFilenameAndPath - - /* - //TODO: No default sound available. Placeholder for now - if TTSPingServers && TTSPingServersFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/voiceprompts/TODO" - if _, err := os.Stat(path); err == nil { - TTSPingServersFilenameAndPath = path + // Add Allowed Mutable Settings For talkkonnect upon live reloadxml config to the list below omit all other variables + if reloadxml { + if Config.Global.Software.Settings.Loglevel != ReConfig.Global.Software.Settings.Loglevel { + Config.Global.Software.Settings.Loglevel = ReConfig.Global.Software.Settings.Loglevel + switch Config.Global.Software.Settings.Loglevel { + case "trace": + colog.SetMinLevel(colog.LTrace) + log.Println("info: Loglevel Set to Trace") + case "debug": + colog.SetMinLevel(colog.LDebug) + log.Println("info: Loglevel Set to Debug") + case "info": + colog.SetMinLevel(colog.LInfo) + log.Println("info: Loglevel Set to Info") + case "warning": + colog.SetMinLevel(colog.LWarning) + log.Println("info: Loglevel Set to Warning") + case "error": + colog.SetMinLevel(colog.LError) + log.Println("info: Loglevel Set to Error") + case "alert": + colog.SetMinLevel(colog.LAlert) + log.Println("info: Loglevel Set to Alert") + default: + colog.SetMinLevel(colog.LInfo) + log.Println("info: Default Loglevel unset in XML config automatically loglevel to Info") } } - */ - - EmailEnabled = Document.Global.Software.SMTP.Enabled - EmailUsername = Document.Global.Software.SMTP.Username - EmailPassword = Document.Global.Software.SMTP.Password - EmailReceiver = Document.Global.Software.SMTP.Receiver - EmailSubject = Document.Global.Software.SMTP.Subject - EmailMessage = Document.Global.Software.SMTP.Message - EmailGpsDateTime = Document.Global.Software.SMTP.GpsDateTime - EmailGpsLatLong = Document.Global.Software.SMTP.GpsLatLong - EmailGoogleMapsURL = Document.Global.Software.SMTP.GoogleMapsURL - - EventSoundEnabled = Document.Global.Software.Sounds.Event.Enabled - EventVolume = Document.Global.Software.Sounds.Event.EventVolume - EventJoinedSoundFilenameAndPath = Document.Global.Software.Sounds.Event.JoinedFilenameAndPath - EventLeftSoundFilenameAndPath = Document.Global.Software.Sounds.Event.LeftFilenameAndPath - EventMessageSoundFilenameAndPath = Document.Global.Software.Sounds.Event.MessageFilenameAndPath - - if EventSoundEnabled && EventJoinedSoundFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/events/event.wav" - if _, err := os.Stat(path); err == nil { - EventJoinedSoundFilenameAndPath = path - } - } - if EventSoundEnabled && EventLeftSoundFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/events/event.wav" - if _, err := os.Stat(path); err == nil { - EventLeftSoundFilenameAndPath = path - } - } - if EventSoundEnabled && EventMessageSoundFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/events/event.wav" - if _, err := os.Stat(path); err == nil { - EventMessageSoundFilenameAndPath = path - } - } - AlertSoundEnabled = Document.Global.Software.Sounds.Alert.Enabled - AlertSoundFilenameAndPath = Document.Global.Software.Sounds.Alert.FilenameAndPath - - if AlertSoundEnabled && AlertSoundFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/alerts/alert.wav" - if _, err := os.Stat(path); err == nil { - AlertSoundFilenameAndPath = path - } - } - - AlertSoundVolume = Document.Global.Software.Sounds.Alert.Volume - - IncommingBeepSoundEnabled = Document.Global.Software.Sounds.IncommingBeep.Enabled - IncommingBeepSoundFilenameAndPath = Document.Global.Software.Sounds.IncommingBeep.FilenameAndPath - - if IncommingBeepSoundEnabled && IncommingBeepSoundFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/rogerbeeps/Chirsp.wav" - if _, err := os.Stat(path); err == nil { - IncommingBeepSoundFilenameAndPath = path - } - } - - IncommingBeepSoundVolume = Document.Global.Software.Sounds.IncommingBeep.Volume - - RogerBeepSoundEnabled = Document.Global.Software.Sounds.RogerBeep.Enabled - RogerBeepSoundFilenameAndPath = Document.Global.Software.Sounds.RogerBeep.FilenameAndPath - - if RogerBeepSoundEnabled && RogerBeepSoundFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/rogerbeeps/Chirsp.wav" - if _, err := os.Stat(path); err == nil { - RogerBeepSoundFilenameAndPath = path - } - } - - RogerBeepSoundVolume = Document.Global.Software.Sounds.RogerBeep.Volume - - RepeaterToneEnabled = Document.Global.Software.Sounds.RepeaterTone.Enabled - RepeaterToneFrequencyHz = Document.Global.Software.Sounds.RepeaterTone.ToneFrequencyHz - RepeaterToneDurationSec = Document.Global.Software.Sounds.RepeaterTone.ToneDurationSec - StreamSoundEnabled = Document.Global.Software.Sounds.Stream.Enabled - StreamSoundFilenameAndPath = Document.Global.Software.Sounds.Stream.FilenameAndPath + Config.Global.Software.Settings.CancellableStream = ReConfig.Global.Software.Settings.CancellableStream + Config.Global.Software.Settings.StreamSendMessage = ReConfig.Global.Software.Settings.StreamSendMessage + Config.Global.Software.Settings.RepeatTXTimes = ReConfig.Global.Software.Settings.RepeatTXTimes + Config.Global.Software.Settings.RepeatTXDelay = ReConfig.Global.Software.Settings.RepeatTXDelay + Config.Global.Software.Settings.SimplexWithMute = ReConfig.Global.Software.Settings.SimplexWithMute + Config.Global.Software.Beacon = ReConfig.Global.Software.Beacon + Config.Global.Software.TTS = ReConfig.Global.Software.TTS + Config.Global.Software.Sounds = ReConfig.Global.Software.Sounds + Config.Global.Software.TxTimeOut = ReConfig.Global.Software.TxTimeOut + Config.Global.Software.RemoteControl.HTTP.Enabled = ReConfig.Global.Software.RemoteControl.HTTP.Enabled + Config.Global.Software.RemoteControl.HTTP.Command = ReConfig.Global.Software.RemoteControl.HTTP.Command + Config.Global.Software.RemoteControl.MQTT.Commands.Command = ReConfig.Global.Software.RemoteControl.MQTT.Commands.Command + Config.Global.Software.PrintVariables = ReConfig.Global.Software.PrintVariables + Config.Global.Software.TTSMessages = ReConfig.Global.Software.TTSMessages + Config.Global.Software.IgnoreUser = ReConfig.Global.Software.IgnoreUser + Config.Global.Hardware.PanicFunction = ReConfig.Global.Hardware.PanicFunction + Config.Global.Hardware.Keyboard.Command = ReConfig.Global.Hardware.Keyboard.Command + Config.Global.Multimedia = ReConfig.Global.Multimedia - if StreamSoundEnabled && StreamSoundFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/alerts/stream.wav" - if _, err := os.Stat(path); err == nil { - StreamSoundFilenameAndPath = path - } - } - - StreamSoundVolume = Document.Global.Software.Sounds.Stream.Volume - - TxTimeOutEnabled = Document.Global.Software.TxTimeOut.Enabled - TxTimeOutSecs = Document.Global.Software.TxTimeOut.TxTimeOutSecs - - APIEnabled = Document.Global.Software.API.Enabled - APIListenPort = Document.Global.Software.API.ListenPort - APIDisplayMenu = Document.Global.Software.API.DisplayMenu - APIChannelUp = Document.Global.Software.API.ChannelUp - APIChannelDown = Document.Global.Software.API.ChannelDown - APIMute = Document.Global.Software.API.Mute - APICurrentVolumeLevel = Document.Global.Software.API.CurrentVolumeLevel - APIDigitalVolumeUp = Document.Global.Software.API.DigitalVolumeUp - APIDigitalVolumeDown = Document.Global.Software.API.DigitalVolumeDown - APIListServerChannels = Document.Global.Software.API.ListServerChannels - APIStartTransmitting = Document.Global.Software.API.StartTransmitting - APIStopTransmitting = Document.Global.Software.API.StopTransmitting - APIListOnlineUsers = Document.Global.Software.API.ListOnlineUsers - APIPlayStream = Document.Global.Software.API.PlayStream - APIRequestGpsPosition = Document.Global.Software.API.RequestGpsPosition - APIEmailEnabled = Document.Global.Software.API.Enabled - APINextServer = Document.Global.Software.API.NextServer - APIPreviousServer = Document.Global.Software.API.PreviousServer - APIPanicSimulation = Document.Global.Software.API.PanicSimulation - APIDisplayVersion = Document.Global.Software.API.DisplayVersion - APIClearScreen = Document.Global.Software.API.ClearScreen - APIPingServersEnabled = Document.Global.Software.API.Enabled - APIRepeatTxLoopTest = Document.Global.Software.API.RepeatTxLoopTest - APIPrintXmlConfig = Document.Global.Software.API.PrintXmlConfig - APIPlayRepeaterTone = Document.Global.Software.API.PlayRepeaterTone - APISetVoiceTarget = Document.Global.Software.API.SetVoiceTarget - - PrintAccount = Document.Global.Software.PrintVariables.PrintAccount - PrintLogging = Document.Global.Software.PrintVariables.PrintLogging - PrintProvisioning = Document.Global.Software.PrintVariables.PrintProvisioning - PrintBeacon = Document.Global.Software.PrintVariables.PrintBeacon - PrintTTS = Document.Global.Software.PrintVariables.PrintTTS - PrintIgnoreUser = Document.Global.Software.PrintVariables.PrintIgnoreUser - PrintSMTP = Document.Global.Software.PrintVariables.PrintSMTP - PrintSounds = Document.Global.Software.PrintVariables.PrintSounds - PrintTxTimeout = Document.Global.Software.PrintVariables.PrintTxTimeout - - MQTTEnabled = Document.Global.Software.MQTT.MQTTEnabled - MQTTTopic = Document.Global.Software.MQTT.MQTTTopic - MQTTBroker = Document.Global.Software.MQTT.MQTTBroker - MQTTPassword = Document.Global.Software.MQTT.MQTTPassword - MQTTUser = Document.Global.Software.MQTT.MQTTUser - MQTTId = Document.Global.Software.MQTT.MQTTId - MQTTCleansess = Document.Global.Software.MQTT.MQTTCleansess - MQTTQos = Document.Global.Software.MQTT.MQTTQos - MQTTNum = Document.Global.Software.MQTT.MQTTNum - MQTTPayload = Document.Global.Software.MQTT.MQTTPayload - MQTTAction = Document.Global.Software.MQTT.MQTTAction - MQTTStore = Document.Global.Software.MQTT.MQTTStore - MQTTAttentionBlinkTimes = Document.Global.Software.MQTT.MQTTAttentionBlinkTimes - MQTTAttentionBlinkmsecs = Document.Global.Software.MQTT.MQTTAttentionBlinkmsecs - - TTSMessageEnabled = Document.Global.Software.TTSMessages.TTSMessageEnabled - TTSLocalPlay = Document.Global.Software.TTSMessages.TTSLocalPlay - TTSLocalPlayWithRXLED = Document.Global.Software.TTSMessages.TTSLocalPlayWithRXLED - TTSPlayIntoStream = Document.Global.Software.TTSMessages.TTSPlayIntoStream - TTSLanguage = Document.Global.Software.TTSMessages.TTSLanguage - TTSSoundDirectory = Document.Global.Software.TTSMessages.TTSSoundDirectory - TTSAnnouncementTone = Document.Global.Software.TTSMessages.TTSAnnouncementTone - TTSMessageFromTag = Document.Global.Software.TTSMessages.TTSMessageFromTag - - IgnoreUserEnabled = Document.Global.Software.IgnoreUser.IgnoreUserEnabled - IgnoreUserRegex = Document.Global.Software.IgnoreUser.IgnoreUserRegex - - PrintHTTPAPI = Document.Global.Software.PrintVariables.PrintHTTPAPI - PrintTargetboard = Document.Global.Software.PrintVariables.PrintTargetBoard - PrintLeds = Document.Global.Software.PrintVariables.PrintLeds - PrintHeartbeat = Document.Global.Software.PrintVariables.PrintHeartbeat - PrintButtons = Document.Global.Software.PrintVariables.PrintButtons - PrintRelays = Document.Global.Software.PrintVariables.PrintRelays - PrintComment = Document.Global.Software.PrintVariables.PrintComment - PrintLcd = Document.Global.Software.PrintVariables.PrintLcd - PrintOled = Document.Global.Software.PrintVariables.PrintOled - PrintGps = Document.Global.Software.PrintVariables.PrintGps - PrintTraccar = Document.Global.Software.PrintVariables.PrintTraccar - PrintPanic = Document.Global.Software.PrintVariables.PrintPanic - PrintAudioRecord = Document.Global.Software.PrintVariables.PrintAudioRecord - PrintMQTT = Document.Global.Software.PrintVariables.PrintMQTT - PrintTTSMessages = Document.Global.Software.PrintVariables.PrintTTSMessages - PrintKeyboardMap = Document.Global.Software.PrintVariables.PrintKeyboardMap - PrintUSBKeyboard = Document.Global.Software.PrintVariables.PrintUSBKeyboard - TargetBoard = Document.Global.Hardware.TargetBoard - LedStripEnabled = Document.Global.Hardware.Lights.LedStripEnabled - // my stupid work around for null uint xml unmarshelling problem with numbers so use strings and convert it 2 times - temp0, _ := strconv.ParseUint(Document.Global.Hardware.Lights.VoiceActivityLedPin, 10, 64) - VoiceActivityLEDPin = uint(temp0) - temp1, _ := strconv.ParseUint(Document.Global.Hardware.Lights.VoiceActivityLedPin, 10, 64) - VoiceActivityLEDPin = uint(temp1) - temp2, _ := strconv.ParseUint(Document.Global.Hardware.Lights.ParticipantsLedPin, 10, 64) - ParticipantsLEDPin = uint(temp2) - temp3, _ := strconv.ParseUint(Document.Global.Hardware.Lights.TransmitLedPin, 10, 64) - TransmitLEDPin = uint(temp3) - temp4, _ := strconv.ParseUint(Document.Global.Hardware.Lights.OnlineLedPin, 10, 64) - OnlineLEDPin = uint(temp4) - temp14, _ := strconv.ParseUint(Document.Global.Hardware.Lights.AttentionLedPin, 10, 64) - AttentionLEDPin = uint(temp14) - temp15, _ := strconv.ParseUint(Document.Global.Hardware.Lights.VoiceTargetLedPin, 10, 64) - VoiceTargetLEDPin = uint(temp15) - - temp5, _ := strconv.ParseUint(Document.Global.Hardware.HeartBeat.LEDPin, 10, 64) - HeartBeatLEDPin = uint(temp5) - HeartBeatEnabled = Document.Global.Hardware.HeartBeat.Enabled - PeriodmSecs = Document.Global.Hardware.HeartBeat.Periodmsecs - LEDOnmSecs = Document.Global.Hardware.HeartBeat.LEDOnmsecs - LEDOffmSecs = Document.Global.Hardware.HeartBeat.LEDOffmsecs - - // my stupid work around for null uint xml unmarshelling problem with numbers so use strings and convert it 2 times - temp6, _ := strconv.ParseUint(Document.Global.Hardware.Buttons.TxButtonPin, 10, 64) - TxButtonPin = uint(temp6) - temp7, _ := strconv.ParseUint(Document.Global.Hardware.Buttons.TxTogglePin, 10, 64) - TxTogglePin = uint(temp7) - temp8, _ := strconv.ParseUint(Document.Global.Hardware.Buttons.UpButtonPin, 10, 64) - UpButtonPin = uint(temp8) - temp9, _ := strconv.ParseUint(Document.Global.Hardware.Buttons.DownButtonPin, 10, 64) - DownButtonPin = uint(temp9) - temp10, _ := strconv.ParseUint(Document.Global.Hardware.Buttons.PanicButtonPin, 10, 64) - PanicButtonPin = uint(temp10) - temp11, _ := strconv.ParseUint(Document.Global.Hardware.Comment.CommentButtonPin, 10, 64) - CommentButtonPin = uint(temp11) - CommentMessageOff = Document.Global.Hardware.Comment.CommentMessageOff - CommentMessageOn = Document.Global.Hardware.Comment.CommentMessageOn - temp12, _ := strconv.ParseUint(Document.Global.Hardware.Buttons.StreamButtonPin, 10, 64) - StreamButtonPin = uint(temp12) - - LCDEnabled = Document.Global.Hardware.LCD.Enabled - LCDInterfaceType = Document.Global.Hardware.LCD.InterfaceType - LCDI2CAddress = Document.Global.Hardware.LCD.I2CAddress - LCDBackLightTimerEnabled = Document.Global.Hardware.LCD.Enabled - LCDBackLightTimeout = time.Duration(Document.Global.Hardware.LCD.BackLightTimeoutSecs) - - // my stupid work around for null uint xml unmarshelling problem with numbers so use strings and convert it 2 times - temp13, _ := strconv.ParseUint(Document.Global.Hardware.LCD.BackLightLEDPin, 10, 64) - LCDBackLightLEDPin = int(temp13) - temp16, _ := strconv.ParseUint(Document.Global.Hardware.Relays.Relay0Pin, 10, 64) - Relay0Pin = int(temp16) - temp17, _ := strconv.ParseUint(Document.Global.Hardware.Relays.Relay1Pin, 10, 64) - Relay1Pin = int(temp17) - temp18, _ := strconv.ParseUint(Document.Global.Hardware.Relays.Relay2Pin, 10, 64) - Relay2Pin = int(temp18) - temp19, _ := strconv.ParseUint(Document.Global.Hardware.Relays.Relay3Pin, 10, 64) - Relay3Pin = int(temp19) - - LCDRSPin = Document.Global.Hardware.LCD.RsPin - LCDEPin = Document.Global.Hardware.LCD.EPin - LCDD4Pin = Document.Global.Hardware.LCD.D4Pin - LCDD5Pin = Document.Global.Hardware.LCD.D5Pin - LCDD6Pin = Document.Global.Hardware.LCD.D6Pin - LCDD7Pin = Document.Global.Hardware.LCD.D7Pin - - OLEDEnabled = Document.Global.Hardware.OLED.Enabled - OLEDInterfacetype = Document.Global.Hardware.OLED.InterfaceType - OLEDDisplayRows = Document.Global.Hardware.OLED.DisplayRows - OLEDDisplayColumns = Document.Global.Hardware.OLED.DisplayColumns - OLEDDefaultI2cBus = Document.Global.Hardware.OLED.DefaultI2CBus - OLEDDefaultI2cAddress = Document.Global.Hardware.OLED.DefaultI2CAddress - OLEDScreenWidth = Document.Global.Hardware.OLED.ScreenWidth - OLEDScreenHeight = Document.Global.Hardware.OLED.ScreenHeight - OLEDCommandColumnAddressing = Document.Global.Hardware.OLED.CommandColumnAddressing - OLEDAddressBasePageStart = Document.Global.Hardware.OLED.AddressBasePageStart - OLEDCharLength = Document.Global.Hardware.OLED.CharLength - OLEDStartColumn = Document.Global.Hardware.OLED.StartColumn - - GpsEnabled = Document.Global.Hardware.GPS.Enabled - Port = Document.Global.Hardware.GPS.Port - Baud = Document.Global.Hardware.GPS.Baud - TxData = Document.Global.Hardware.GPS.TxData - Even = Document.Global.Hardware.GPS.Even - Odd = Document.Global.Hardware.GPS.Odd - Rs485 = Document.Global.Hardware.GPS.Rs485 - Rs485HighDuringSend = Document.Global.Hardware.GPS.Rs485HighDuringSend - Rs485HighAfterSend = Document.Global.Hardware.GPS.Rs485HighAfterSend - StopBits = Document.Global.Hardware.GPS.StopBits - DataBits = Document.Global.Hardware.GPS.DataBits - CharTimeOut = Document.Global.Hardware.GPS.CharTimeOut - MinRead = Document.Global.Hardware.GPS.MinRead - Rx = Document.Global.Hardware.GPS.Rx - GpsInfoVerbose = Document.Global.Hardware.GPS.GpsInfoVerbose - TrackEnabled = Document.Global.Hardware.GPSTrackingFunction.TrackEnabled - TraccarSendTo = Document.Global.Hardware.GPSTrackingFunction.TraccarSendTo - TraccarServerURL = Document.Global.Hardware.GPSTrackingFunction.TraccarServerURL - TraccarServerIP = Document.Global.Hardware.GPSTrackingFunction.TraccarServerIP - TraccarClientId = Document.Global.Hardware.GPSTrackingFunction.TraccarClientId - TraccarReportFrequency = Document.Global.Hardware.GPSTrackingFunction.TraccarReportFrequency - TraccarProto = Document.Global.Hardware.GPSTrackingFunction.TraccarProto - TraccarServerFullURL = Document.Global.Hardware.GPSTrackingFunction.TraccarServerFullURL - TrackGPSShowLCD = Document.Global.Hardware.GPSTrackingFunction.TrackGPSShowLCD - TrackVerbose = Document.Global.Hardware.GPSTrackingFunction.TrackVerbose - PEnabled = Document.Global.Hardware.PanicFunction.Enabled - PFilenameAndPath = Document.Global.Hardware.PanicFunction.FilenameAndPath - - if PEnabled && PFilenameAndPath == "" { - path := defaultSharePath + "/soundfiles/alerts/alert.wav" - if _, err := os.Stat(path); err == nil { - PFilenameAndPath = path - } } - - PMessage = Document.Global.Hardware.PanicFunction.Message - PMailEnabled = Document.Global.Hardware.PanicFunction.PMailEnabled - PVolume = Document.Global.Hardware.PanicFunction.Volume - PSendIdent = Document.Global.Hardware.PanicFunction.SendIdent - PSendGpsLocation = Document.Global.Hardware.PanicFunction.SendGpsLocation - PTxLockEnabled = Document.Global.Hardware.PanicFunction.TxLockEnabled - PTxlockTimeOutSecs = Document.Global.Hardware.PanicFunction.TxLockTimeOutSecs - PLowProfile = Document.Global.Hardware.PanicFunction.PLowProfile - USBKeyboardEnabled = Document.Global.Hardware.USBKeyboard.Enabled - USBKeyboardPath = Document.Global.Hardware.USBKeyboard.USBKeyboardPath - NumlockScanID = Document.Global.Hardware.USBKeyboard.NumlockScanID - AudioRecordEnabled = Document.Global.Hardware.AudioRecordFunction.Enabled - AudioRecordOnStart = Document.Global.Hardware.AudioRecordFunction.RecordOnStart - AudioRecordSystem = Document.Global.Hardware.AudioRecordFunction.RecordSystem - AudioRecordMode = Document.Global.Hardware.AudioRecordFunction.RecordMode - AudioRecordTimeout = Document.Global.Hardware.AudioRecordFunction.RecordTimeout - AudioRecordFromOutput = Document.Global.Hardware.AudioRecordFunction.RecordFromOutput - AudioRecordFromInput = Document.Global.Hardware.AudioRecordFunction.RecordFromInput - AudioRecordMicTimeout = Document.Global.Hardware.AudioRecordFunction.RecordMicTimeout - AudioRecordSavePath = Document.Global.Hardware.AudioRecordFunction.RecordSavePath - AudioRecordArchivePath = Document.Global.Hardware.AudioRecordFunction.RecordArchivePath - AudioRecordSoft = Document.Global.Hardware.AudioRecordFunction.RecordSoft - AudioRecordProfile = Document.Global.Hardware.AudioRecordFunction.RecordProfile - AudioRecordFileFormat = Document.Global.Hardware.AudioRecordFunction.RecordFileFormat - AudioRecordChunkSize = Document.Global.Hardware.AudioRecordFunction.RecordChunkSize - - if TargetBoard != "rpi" { - LCDBackLightTimerEnabled = false - } - - if LCDBackLightTimerEnabled && (!OLEDEnabled && !LCDEnabled) { - FatalCleanUp("Alert: Logical Error in LCDBacklight Timer Check XML config file. Backlight Timer Enabled but both LCD and OLED disabled!") - } - - if OLEDEnabled { - Oled, err = goled.BeginOled(OLEDDefaultI2cAddress, OLEDDefaultI2cBus, OLEDScreenWidth, OLEDScreenHeight, OLEDDisplayRows, OLEDDisplayColumns, OLEDStartColumn, OLEDCharLength, OLEDCommandColumnAddressing, OLEDAddressBasePageStart) - if err != nil { - log.Println("error: Cannot Communicate with OLED") - } - } - - log.Println("Successfully loaded XML configuration file into memory") - - for i := 0; i < len(Document.Accounts.Account); i++ { - if Document.Accounts.Account[i].Default { - log.Printf("info: Successfully Added Account %s to Index [%d]\n", Document.Accounts.Account[i].Name, i) - } - } - return nil } func printxmlconfig() { - if PrintAccount { - log.Println("info: ---------- Account Information -------- ") - log.Println("info: Default ", fmt.Sprintf("%t", Default)) - log.Println("info: Server ", Server[AccountIndex]) - log.Println("info: Username ", Username[AccountIndex]) - log.Println("info: Password ", Password[AccountIndex]) - log.Println("info: Insecure ", fmt.Sprintf("%t", Insecure[AccountIndex])) - log.Println("info: Register ", fmt.Sprintf("%t", Register[AccountIndex])) - log.Println("info: Certificate ", Certificate[AccountIndex]) - log.Println("info: Channel ", Channel[AccountIndex]) - log.Println("info: Ident ", Ident[AccountIndex]) - log.Println("info: Tokens ", Tokens[AccountIndex]) - log.Println("info: VoiceTargets ", VT[AccountIndex]) - + if Config.Global.Software.PrintVariables.PrintAccount { + log.Println("info: ---------- Account Info ---------- ") + for index, account := range Config.Accounts.Account { + if account.Default { + var AcctIsDefault string = "x" + if Server[AccountIndex] == account.ServerAndPort && Username[AccountIndex] == account.UserName { + AcctIsDefault = "✓" + } + log.Printf("info: %v Account %v Name %v Enabled %v \n", AcctIsDefault, index, account.Name, account.Default) + log.Printf("info: %v Server:Port %v \n", AcctIsDefault, account.ServerAndPort) + log.Printf("info: %v Username %v Password %v \n", AcctIsDefault, account.UserName, account.Password) + log.Printf("info: %v Insecure %v Register %v \n", AcctIsDefault, account.Insecure, account.Register) + log.Printf("info: %v Certificate %v \n", AcctIsDefault, account.Certificate) + log.Printf("info: %v Channel %v \n", AcctIsDefault, account.Channel) + log.Printf("info: %v Ident %v \n", AcctIsDefault, account.Ident) + log.Printf("info: %v Tokens %v \n", AcctIsDefault, account.Tokens) + log.Printf("info: %v VoiceTargets %v \n", AcctIsDefault, account.Voicetargets) + } + } } else { log.Println("info: ---------- Account Information -------- SKIPPED ") } - if PrintLogging { - log.Println("info: -------- Logging & Daemonizing -------- ") - log.Println("info: Output Device ", OutputDevice) - log.Println("info: Output Device(Short) ", OutputDeviceShort) - log.Println("info: Log File ", LogFilenameAndPath) - log.Println("info: Logging ", Logging) - log.Println("info: Loglevel ", Loglevel) - log.Println("info: Daemonize ", fmt.Sprintf("%t", Daemonize)) - log.Println("info: CancellableStream ", fmt.Sprintf("%t", CancellableStream)) - log.Println("info: StreamOnStart ", fmt.Sprintf("%t", StreamOnStart)) - log.Println("info: StreamOnStartAfter ", fmt.Sprintf("%v", StreamOnStartAfter)) - log.Println("info: TXOnStart ", fmt.Sprintf("%t", TXOnStart)) - log.Println("info: TXOnStartAfter ", fmt.Sprintf("%v", TXOnStartAfter)) - log.Println("info: RepeatTXTimes ", fmt.Sprintf("%v", RepeatTXTimes)) - log.Println("info: SimplexWithMute ", fmt.Sprintf("%t", SimplexWithMute)) - log.Println("info: TxCounter ", fmt.Sprintf("%t", TxCounter)) - log.Println("info: NextServerIndex ", fmt.Sprintf("%v", NextServerIndex)) + if Config.Global.Software.PrintVariables.PrintSystemSettings { + log.Println("info: -------- System Settings -------- ") + log.Println("info: Single Instance ", Config.Global.Software.Settings.SingleInstance) + log.Println("info: Output Device ", Config.Global.Software.Settings.OutputDevice) + log.Println("info: Output Device(Short) ", Config.Global.Software.Settings.OutputDeviceShort) + log.Println("info: Log File ", Config.Global.Software.Settings.LogFilenameAndPath) + log.Println("info: Logging ", Config.Global.Software.Settings.Logging) + log.Println("info: Loglevel ", Config.Global.Software.Settings.Loglevel) + log.Println("info: CancellableStream ", fmt.Sprintf("%t", Config.Global.Software.Settings.CancellableStream)) + log.Println("info: StreamOnStart ", fmt.Sprintf("%t", Config.Global.Software.Settings.StreamOnStart)) + log.Println("info: StreamOnStartAfter ", fmt.Sprintf("%v", Config.Global.Software.Settings.StreamOnStartAfter)) + log.Println("info: TXOnStart ", fmt.Sprintf("%t", Config.Global.Software.Settings.TXOnStart)) + log.Println("info: TXOnStartAfter ", fmt.Sprintf("%v", Config.Global.Software.Settings.TXOnStartAfter)) + log.Println("info: RepeatTXTimes ", fmt.Sprintf("%v", Config.Global.Software.Settings.RepeatTXTimes)) + log.Println("info: RepeatTXDelay ", fmt.Sprintf("%v", Config.Global.Software.Settings.RepeatTXDelay)) + log.Println("info: SimplexWithMute ", fmt.Sprintf("%t", Config.Global.Software.Settings.SimplexWithMute)) + log.Println("info: TxCounter ", fmt.Sprintf("%t", Config.Global.Software.Settings.TxCounter)) + log.Println("info: NextServerIndex ", fmt.Sprintf("%v", Config.Global.Software.Settings.NextServerIndex)) } else { - log.Println("info: -------- Logging & Daemonizing -------- SKIPPED ") + log.Println("info: -------- System Settings -------- SKIPPED ") } - if PrintProvisioning { + if Config.Global.Software.PrintVariables.PrintProvisioning { log.Println("info: -------- AutoProvisioning --------- ") - log.Println("info: AutoProvisioning Enabled " + fmt.Sprintf("%t", APEnabled)) - log.Println("info: Talkkonned ID (tkid) " + TkID) - log.Println("info: AutoProvisioning Server URL " + URL) - log.Println("info: Config Local Path " + SaveFilePath) - log.Println("info: Config Local Filename " + SaveFilename) + log.Println("info: AutoProvisioning Enabled " + fmt.Sprintf("%t", Config.Global.Software.AutoProvisioning.Enabled)) + log.Println("info: Talkkonned ID (tkid) " + Config.Global.Software.AutoProvisioning.TkID) + log.Println("info: AutoProvisioning Server URL " + Config.Global.Software.AutoProvisioning.URL) + log.Println("info: Config Local Path " + Config.Global.Software.AutoProvisioning.SaveFilePath) + log.Println("info: Config Local Filename " + Config.Global.Software.AutoProvisioning.SaveFilename) } else { log.Println("info: -------- AutoProvisioning --------- SKIPPED ") } - if PrintBeacon { + if Config.Global.Software.PrintVariables.PrintBeacon { log.Println("info: -------- Beacon --------- ") - log.Println("info: Beacon Enabled " + fmt.Sprintf("%t", BeaconEnabled)) - log.Println("info: Beacon Time (Secs) " + fmt.Sprintf("%v", BeaconTimerSecs)) - log.Println("info: Beacon Filename & Path " + BeaconFilenameAndPath) - log.Println("info: Beacon Playback Volume " + fmt.Sprintf("%v", BVolume)) + log.Println("info: Beacon Enabled " + fmt.Sprintf("%t", Config.Global.Software.Beacon.Enabled)) + log.Println("info: Beacon Time (Secs) " + fmt.Sprintf("%v", Config.Global.Software.Beacon.BeaconTimerSecs)) + log.Println("info: Beacon Filename & Path " + Config.Global.Software.Beacon.BeaconFileAndPath) + log.Println("info: Beacon Playback Volume " + fmt.Sprintf("%v", Config.Global.Software.Beacon.Volume)) } else { log.Println("info: -------- Beacon --------- SKIPPED ") } - if PrintTTS { + if Config.Global.Software.PrintVariables.PrintTTS { log.Println("info: -------- TTS -------- ") - log.Println("info: TTS Global Enabled ", fmt.Sprintf("%t", TTSEnabled)) - log.Println("info: TTS Volume Level (%) ", fmt.Sprintf("%.1f", TTSVolumeLevel)) - log.Println("info: TTS Participants ", fmt.Sprintf("%t", TTSParticipants)) - log.Println("info: TTS ChannelUp ", fmt.Sprintf("%t", TTSChannelUp)) - log.Println("info: TTS ChannelUpFilenameAndPath ", TTSChannelUpFilenameAndPath) - log.Println("info: TTS ChannelDown ", fmt.Sprintf("%t", TTSChannelDown)) - log.Println("info: TTS ChannelDownFilenameAndPath ", TTSChannelDownFilenameAndPath) - log.Println("info: TTS MuteUnMuteSpeaker ", fmt.Sprintf("%t", TTSMuteUnMuteSpeaker)) - log.Println("info: TTS MuteUnMuteSpeakerFilenameAndPath ", TTSMuteUnMuteSpeakerFilenameAndPath) - log.Println("info: TTS CurrentVolumeLevel ", fmt.Sprintf("%t", TTSCurrentVolumeLevel)) - log.Println("info: TTS CurrentVolumeLevelFilenameAndPath ", TTSCurrentVolumeLevelFilenameAndPath) - log.Println("info: TTS DigitalVolumeUp ", fmt.Sprintf("%t", TTSDigitalVolumeUp)) - log.Println("info: TTS DigitalVolumeUpFilenameAndPath ", TTSDigitalVolumeUpFilenameAndPath) - log.Println("info: TTS DigitalVolumeDown ", fmt.Sprintf("%t", TTSDigitalVolumeDown)) - log.Println("info: TTS DigitalVolumeDownFilenameAndPath ", TTSDigitalVolumeDownFilenameAndPath) - log.Println("info: TTS ListServerChannels ", fmt.Sprintf("%t", TTSListServerChannels)) - log.Println("info: TTS ListServerChannelsFilenameAndPath ", TTSListServerChannelsFilenameAndPath) - log.Println("info: TTS StartTransmitting ", fmt.Sprintf("%t", TTSStartTransmitting)) - log.Println("info: TTS StartTransmittingFilenameAndPath ", TTSStartTransmittingFilenameAndPath) - log.Println("info: TTS StopTransmitting ", fmt.Sprintf("%t", TTSStopTransmitting)) - log.Println("info: TTS StopTransmittingFilenameAndPath ", TTSStopTransmittingFilenameAndPath) - log.Println("info: TTS ListOnlineUsers ", fmt.Sprintf("%t", TTSListOnlineUsers)) - log.Println("info: TTS ListOnlineUsersFilenameAndPath ", TTSListOnlineUsersFilenameAndPath) - log.Println("info: TTS PlayStream ", fmt.Sprintf("%t", TTSPlayStream)) - log.Println("info: TTS PlayStreamFilenameAndPath ", TTSPlayStreamFilenameAndPath) - log.Println("info: TTS RequestGpsPosition ", fmt.Sprintf("%t", TTSRequestGpsPosition)) - log.Println("info: TTS RequestGpsPositionFilenameAndPath ", TTSRequestGpsPositionFilenameAndPath) - log.Println("info: TTS NextServer ", fmt.Sprintf("%t", TTSNextServer)) - log.Println("info: TTS NextServerFilenameAndPath ", TTSNextServerFilenameAndPath) - log.Println("info: TTS PreviousServer ", fmt.Sprintf("%t", TTSPreviousServer)) - log.Println("info: TTS PreviousServerFilenameAndPath ", TTSPreviousServerFilenameAndPath) - log.Println("info: TTS PanicSimulation ", fmt.Sprintf("%t", TTSPanicSimulation)) - log.Println("info: TTS PanicSimulationFilenameAndPath ", TTSPanicSimulationFilenameAndPath) - log.Println("info: TTS PrintXmlConfig ", fmt.Sprintf("%t", TTSPrintXmlConfig)) - log.Println("info: TTS PrintXmlConfigFilenameAndPath ", TTSPrintXmlConfigFilenameAndPath) - log.Println("info: TTS SendEmail ", fmt.Sprintf("%t", TTSSendEmail)) - log.Println("info: TTS SendEmailFilenameAndPath ", TTSSendEmailFilenameAndPath) - log.Println("info: TTS DisplayMenu ", fmt.Sprintf("%t", TTSDisplayMenu)) - log.Println("info: TTS DisplayMenuFilenameAndPath ", TTSDisplayMenuFilenameAndPath) - log.Println("info: TTS QuitTalkkonnect ", fmt.Sprintf("%t", TTSQuitTalkkonnect)) - log.Println("info: TTS QuitTalkkonnectFilenameAndPath ", TTSQuitTalkkonnectFilenameAndPath) - log.Println("info: TTS TalkkonnectLoaded ", fmt.Sprintf("%t", TTSTalkkonnectLoaded)) - log.Println("info: TTS TalkkonnectLoadedFilenameAndPath ", TTSTalkkonnectLoadedFilenameAndPath) - log.Println("info: TTS TalkkonnectLoaded " + fmt.Sprintf("%t", TTSTalkkonnectLoaded)) - log.Println("info: TTS PingServersFilenameAndPath ", TTSPingServersFilenameAndPath) - log.Println("info: TTS PingServers " + fmt.Sprintf("%t", TTSPingServers)) + for _, tts := range Config.Global.Software.TTS.Sound { + log.Printf("%+v\n", tts) + } } else { log.Println("info: -------- TTS -------- SKIPPED ") } - if PrintSMTP { + if Config.Global.Software.PrintVariables.PrintSMTP { log.Println("info: -------- Gmail SMTP Settings -------- ") - log.Println("info: Email Enabled " + fmt.Sprintf("%t", EmailEnabled)) - log.Println("info: Username " + EmailUsername) - log.Println("info: Password " + EmailPassword) - log.Println("info: Receiver " + EmailReceiver) - log.Println("info: Subject " + EmailSubject) - log.Println("info: Message " + EmailMessage) - log.Println("info: GPS Date/Time " + fmt.Sprintf("%t", EmailGpsDateTime)) - log.Println("info: GPS Lat/Long " + fmt.Sprintf("%t", EmailGpsLatLong)) - log.Println("info: Google Maps URL " + fmt.Sprintf("%t", EmailGoogleMapsURL)) + log.Println("info: Email Enabled " + fmt.Sprintf("%t", Config.Global.Software.SMTP.Enabled)) + log.Println("info: Username " + Config.Global.Software.SMTP.Username) + log.Println("info: Password " + Config.Global.Software.SMTP.Password) + log.Println("info: Receiver " + Config.Global.Software.SMTP.Receiver) + log.Println("info: Subject " + Config.Global.Software.SMTP.Subject) + log.Println("info: Message " + Config.Global.Software.SMTP.Message) + log.Println("info: GPS Date/Time " + fmt.Sprintf("%t", Config.Global.Software.SMTP.GpsDateTime)) + log.Println("info: GPS Lat/Long " + fmt.Sprintf("%t", Config.Global.Software.SMTP.GpsLatLong)) + log.Println("info: Google Maps URL " + fmt.Sprintf("%t", Config.Global.Software.SMTP.GoogleMapsURL)) } else { log.Println("info: -------- Gmail SMTP Settings -------- SKIPPED ") } - if PrintSounds { + if Config.Global.Software.PrintVariables.PrintSounds { log.Println("info: ------------- Sounds ------------------ ") - log.Println("info: Event Sound Enabled " + fmt.Sprintf("%t", EventSoundEnabled)) - log.Println("info: Event Volume " + fmt.Sprintf("%.1f", EventVolume)) - log.Println("info: Event Joined Sound Filename " + EventJoinedSoundFilenameAndPath) - log.Println("info: Event Left Sound Filename " + EventJoinedSoundFilenameAndPath) - log.Println("info: Event Msg Sound Filename " + EventMessageSoundFilenameAndPath) - log.Println("info: Alert Sound Enabled " + fmt.Sprintf("%t", AlertSoundEnabled)) - log.Println("info: Alert Sound Filename " + AlertSoundFilenameAndPath) - log.Println("info: Alert Sound Volume " + fmt.Sprintf("%v", AlertSoundVolume)) - log.Println("info: Incoming Beep Enabled " + fmt.Sprintf("%t", IncommingBeepSoundEnabled)) - log.Println("info: Incoming Beep File " + IncommingBeepSoundFilenameAndPath) - log.Println("info: Incoming Beep Volume " + fmt.Sprintf("%v", IncommingBeepSoundVolume)) - log.Println("info: Roger Beep Enabled " + fmt.Sprintf("%t", RogerBeepSoundEnabled)) - log.Println("info: Roger Beep File " + RogerBeepSoundFilenameAndPath) - log.Println("info: Roger Beep Volume " + fmt.Sprintf("%v", RogerBeepSoundVolume)) - log.Println("info: Repeater Tone Enabled " + fmt.Sprintf("%t", RepeaterToneEnabled)) - log.Println("info: Repeater Tone Freq (Hz) " + fmt.Sprintf("%v", RepeaterToneFrequencyHz)) - log.Println("info: Repeater Tone Length (Sec) " + fmt.Sprintf("%v", RepeaterToneDurationSec)) - log.Println("info: Stream Enabled " + fmt.Sprintf("%t", StreamSoundEnabled)) - log.Println("info: Stream File " + StreamSoundFilenameAndPath) - log.Println("info: Stream Volume " + fmt.Sprintf("%v", StreamSoundVolume)) + for _, sounds := range Config.Global.Software.Sounds.Sound { + log.Printf("info: |Event=%v |File=%v |Volume=%v |Blocking=%v |Enabled=%v\n", sounds.Event, sounds.File, sounds.Volume, sounds.Blocking, sounds.Enabled) + } } else { log.Println("info: ------------ Sounds ------------------ SKIPPED ") } - if PrintTxTimeout { + if Config.Global.Software.PrintVariables.PrintTxTimeout { log.Println("info: ------------ TX Timeout ------------------ ") - log.Println("info: Tx Timeout Enabled " + fmt.Sprintf("%t", TxTimeOutEnabled)) - log.Println("info: Tx Timeout Secs " + fmt.Sprintf("%v", TxTimeOutSecs)) + log.Println("info: Tx Timeout Enabled " + fmt.Sprintf("%t", Config.Global.Software.TxTimeOut.Enabled)) + log.Println("info: Tx Timeout Secs " + fmt.Sprintf("%v", Config.Global.Software.TxTimeOut.TxTimeOutSecs)) } else { log.Println("info: ------------ TX Timeout ------------------ SKIPPED ") } - if PrintHTTPAPI { + if Config.Global.Software.PrintVariables.PrintHTTPAPI { log.Println("info: ------------ HTTP API ----------------- ") - log.Println("info: API Enabled " + fmt.Sprintf("%t", APIEnabled)) - log.Println("info: API Listen Port " + APIListenPort) - log.Println("info: DisplayMenu " + fmt.Sprintf("%t", APIDisplayMenu)) - log.Println("info: ChannelUp " + fmt.Sprintf("%t", APIChannelUp)) - log.Println("info: ChannelDown " + fmt.Sprintf("%t", APIChannelDown)) - log.Println("info: Mute " + fmt.Sprintf("%t", APIMute)) - log.Println("info: CurentVolumeLevel " + fmt.Sprintf("%t", APICurrentVolumeLevel)) - log.Println("info: DigitalVolumeUp " + fmt.Sprintf("%t", APIDigitalVolumeUp)) - log.Println("info: DigitalVolumeDown " + fmt.Sprintf("%t", APIDigitalVolumeDown)) - log.Println("info: ListServerChannels " + fmt.Sprintf("%t", APIListServerChannels)) - log.Println("info: StartTransmitting " + fmt.Sprintf("%t", APIStartTransmitting)) - log.Println("info: StopTransmitting " + fmt.Sprintf("%t", APIStopTransmitting)) - log.Println("info: ListOnlineUsers " + fmt.Sprintf("%t", APIListOnlineUsers)) - log.Println("info: PlayStream " + fmt.Sprintf("%t", APIPlayStream)) - log.Println("info: RequestGpsPosition " + fmt.Sprintf("%t", APIRequestGpsPosition)) - log.Println("info: EmailEnabled " + fmt.Sprintf("%t", APIEmailEnabled)) - log.Println("info: NextServer " + fmt.Sprintf("%t", APINextServer)) - log.Println("info: PreviousServer " + fmt.Sprintf("%t", APIPreviousServer)) - log.Println("info: PanicSimulation " + fmt.Sprintf("%t", APIPanicSimulation)) - log.Println("info: ScanChannels " + fmt.Sprintf("%t", APIScanChannels)) - log.Println("info: DisplayVersion " + fmt.Sprintf("%t", APIDisplayVersion)) - log.Println("info: ClearScreen " + fmt.Sprintf("%t", APIClearScreen)) - log.Println("info: PingServersEnabled " + fmt.Sprintf("%t", APIPingServersEnabled)) - log.Println("info: TxLoopTest " + fmt.Sprintf("%t", APIRepeatTxLoopTest)) - log.Println("info: PrintXmlConfig " + fmt.Sprintf("%t", APIPrintXmlConfig)) - log.Println("info: PlayRepeaterTone " + fmt.Sprintf("%t", APIPlayRepeaterTone)) - log.Println("info: SetVoiceTarget " + fmt.Sprintf("%t", APISetVoiceTarget)) + log.Println("info: HTTP API Enabled ", Config.Global.Software.RemoteControl.HTTP.Enabled) + log.Println("info: HTTP API Listen Port ", Config.Global.Software.RemoteControl.HTTP.ListenPort) + for _, command := range Config.Global.Software.RemoteControl.HTTP.Command { + log.Printf("info: Enabled=%v Action=%v Name=%v Param=%v Message=%v\n", command.Enabled, command.Action, command.Funcname, command.Funcparamname, command.Message) + } } else { log.Println("info: ------------ HTTP API ----------------- SKIPPED ") } - if PrintTargetboard { + if Config.Global.Software.PrintVariables.PrintTargetBoard { log.Println("info: ------------ Target Board --------------- ") - log.Println("info: Target Board " + fmt.Sprintf("%v", TargetBoard)) + log.Println("info: Target Board " + fmt.Sprintf("%v", Config.Global.Hardware.TargetBoard)) } else { log.Println("info: ------------ Target Board --------------- SKIPPED ") } - if PrintLeds { + if Config.Global.Software.PrintVariables.PrintLeds { log.Println("info: ------------ LEDS ---------------------- ") - log.Println("info: Led Strip Enabled " + fmt.Sprintf("%v", LedStripEnabled)) - log.Println("info: Voice Activity Led Pin " + fmt.Sprintf("%v", VoiceActivityLEDPin)) - log.Println("info: Participants Led Pin " + fmt.Sprintf("%v", ParticipantsLEDPin)) - log.Println("info: Transmit Led Pin " + fmt.Sprintf("%v", TransmitLEDPin)) - log.Println("info: Online Led Pin " + fmt.Sprintf("%v", OnlineLEDPin)) - log.Println("info: Attention Led Pin " + fmt.Sprintf("%v", AttentionLEDPin)) - log.Println("info: VoiceTarget Led Pin " + fmt.Sprintf("%v", VoiceTargetLEDPin)) + log.Println("info: Led Strip Enabled " + fmt.Sprintf("%v", Config.Global.Hardware.LedStripEnabled)) } else { log.Println("info: ------------ LEDS ---------------------- SKIPPED ") } - if PrintHeartbeat { + if Config.Global.Software.PrintVariables.PrintHeartbeat { log.Println("info: ---------- HEARTBEAT -------------------- ") - log.Println("info: HeartBeat Enabled " + fmt.Sprintf("%v", HeartBeatEnabled)) - log.Println("info: HeartBeat LED Pin " + fmt.Sprintf("%v", HeartBeatLEDPin)) - log.Println("info: Period mSecs " + fmt.Sprintf("%v", PeriodmSecs)) - log.Println("info: Led On mSecs " + fmt.Sprintf("%v", LEDOnmSecs)) - log.Println("info: Led Off mSecs " + fmt.Sprintf("%v", LEDOffmSecs)) - } - - if PrintButtons { - log.Println("info: ------------ Buttons ------------------- ") - log.Println("info: Tx Button Pin " + fmt.Sprintf("%v", TxButtonPin)) - log.Println("info: Tx Toggle Pin " + fmt.Sprintf("%v", TxTogglePin)) - log.Println("info: Channel Up Button Pin " + fmt.Sprintf("%v", UpButtonPin)) - log.Println("info: Channel Down Button Pin " + fmt.Sprintf("%v", DownButtonPin)) - log.Println("info: Panic Button Pin " + fmt.Sprintf("%v", PanicButtonPin)) - log.Println("info: Stream Button Pin " + fmt.Sprintf("%v", StreamButtonPin)) - } else { - log.Println("info: ------------ Buttons ------------------- SKIPPED ") + log.Println("info: HeartBeat Enabled " + fmt.Sprintf("%v", Config.Global.Hardware.HeartBeat.Enabled)) + log.Println("info: Period mSecs " + fmt.Sprintf("%v", Config.Global.Hardware.HeartBeat.Periodmsecs)) + log.Println("info: Led On mSecs " + fmt.Sprintf("%v", Config.Global.Hardware.HeartBeat.LEDOnmsecs)) + log.Println("info: Led Off mSecs " + fmt.Sprintf("%v", Config.Global.Hardware.HeartBeat.LEDOffmsecs)) } - if PrintRelays { - log.Println("info: ------------ Relays ------------------- ") - log.Println("info: Relay 0 Pin " + fmt.Sprintf("%v", Relay0Pin)) - log.Println("info: Relay 1 Pin " + fmt.Sprintf("%v", Relay1Pin)) - log.Println("info: Relay 2 Pin " + fmt.Sprintf("%v", Relay2Pin)) - log.Println("info: Relay 3 Pin " + fmt.Sprintf("%v", Relay3Pin)) + if Config.Global.Software.PrintVariables.PrintGPIO { + log.Println("info: ------------ GPIO ------------------- ") + for _, value := range Config.Global.Hardware.IO.Pins.Pin { + log.Printf("%+v\n", value) + } } else { - log.Println("info: ------------ Relays ------------------- SKIPPED ") + log.Println("info: ------------ GPIO ------------------- SKIPPED ") } - if PrintComment { + if Config.Global.Software.PrintVariables.PrintComment { log.Println("info: ------------ Comment ------------------- ") - log.Println("info: Comment Button Pin " + fmt.Sprintf("%v", CommentButtonPin)) - log.Println("info: Comment Message State 1 " + fmt.Sprintf("%v", CommentMessageOff)) - log.Println("info: Comment Message State 2 " + fmt.Sprintf("%v", CommentMessageOn)) + log.Println("info: Comment Button Pin " + fmt.Sprintf("%v", CommentButtonPin)) + log.Println("info: Comment Message State 1 (off) " + fmt.Sprintf("%v", Config.Global.Hardware.Comment.CommentMessageOff)) + log.Println("info: Comment Message State 2 (on) " + fmt.Sprintf("%v", Config.Global.Hardware.Comment.CommentMessageOn)) } else { log.Println("info: ------------ Comment ------------------- SKIPPED ") } - if PrintLcd { + if Config.Global.Software.PrintVariables.PrintLcd { log.Println("info: ------------ LCD HD44780 ----------------------- ") log.Println("info: LCDEnabled " + fmt.Sprintf("%v", LCDEnabled)) log.Println("info: LCDInterfaceType " + fmt.Sprintf("%v", LCDInterfaceType)) log.Println("info: Lcd I2C Address " + fmt.Sprintf("%x", LCDI2CAddress)) log.Println("info: Back Light Timer Enabled " + fmt.Sprintf("%t", LCDBackLightTimerEnabled)) log.Println("info: Back Light Timer Timeout " + fmt.Sprintf("%v", LCDBackLightTimeout)) - log.Println("info: Back Light Pin " + fmt.Sprintf("%v", LCDBackLightLEDPin)) log.Println("info: RS Pin " + fmt.Sprintf("%v", LCDRSPin)) log.Println("info: E Pin " + fmt.Sprintf("%v", LCDEPin)) log.Println("info: D4 Pin " + fmt.Sprintf("%v", LCDD4Pin)) @@ -1983,7 +1001,7 @@ func printxmlconfig() { log.Println("info: ------------ LCD ----------------------- SKIPPED ") } - if PrintOled { + if Config.Global.Software.PrintVariables.PrintOled { log.Println("info: ------------ OLED ----------------------- ") log.Println("info: Enabled " + fmt.Sprintf("%v", OLEDEnabled)) log.Println("info: Interfacetype " + fmt.Sprintf("%v", OLEDInterfacetype)) @@ -2001,137 +1019,178 @@ func printxmlconfig() { log.Println("info: ------------ OLED ----------------------- SKIPPED ") } - if PrintGps { + if Config.Global.Software.PrintVariables.PrintGps { log.Println("info: ------------ GPS ------------------------ ") - log.Println("info: GPS Enabled " + fmt.Sprintf("%t", GpsEnabled)) - log.Println("info: Port ", Port) - log.Println("info: Baud " + fmt.Sprintf("%v", Baud)) - log.Println("info: TxData ", TxData) - log.Println("info: Even " + fmt.Sprintf("%v", Even)) - log.Println("info: Odd " + fmt.Sprintf("%v", Odd)) - log.Println("info: RS485 " + fmt.Sprintf("%v", Rs485)) - log.Println("info: RS485 High During Send " + fmt.Sprintf("%v", Rs485HighDuringSend)) - log.Println("info: RS485 High After Send " + fmt.Sprintf("%v", Rs485HighAfterSend)) - log.Println("info: Stop Bits " + fmt.Sprintf("%v", StopBits)) - log.Println("info: Data Bits " + fmt.Sprintf("%v", DataBits)) - log.Println("info: Char Time Out " + fmt.Sprintf("%v", CharTimeOut)) - log.Println("info: Min Read " + fmt.Sprintf("%v", MinRead)) - log.Println("info: Rx " + fmt.Sprintf("%t", Rx)) + log.Println("info: GPS Enabled " + fmt.Sprintf("%t", Config.Global.Hardware.GPS.Enabled)) + log.Println("info: Port ", Config.Global.Hardware.GPS.Port) + log.Println("info: Baud " + fmt.Sprintf("%v", Config.Global.Hardware.GPS.Baud)) + log.Println("info: TxData ", Config.Global.Hardware.GPS.TxData) + log.Println("info: Even " + fmt.Sprintf("%v", Config.Global.Hardware.GPS.Even)) + log.Println("info: Odd " + fmt.Sprintf("%v", Config.Global.Hardware.GPS.Odd)) + log.Println("info: RS485 " + fmt.Sprintf("%v", Config.Global.Hardware.GPS.Rs485)) + log.Println("info: RS485 High During Send " + fmt.Sprintf("%v", Config.Global.Hardware.GPS.Rs485HighDuringSend)) + log.Println("info: RS485 High After Send " + fmt.Sprintf("%v", Config.Global.Hardware.GPS.Rs485HighAfterSend)) + log.Println("info: Stop Bits " + fmt.Sprintf("%v", Config.Global.Hardware.GPS.StopBits)) + log.Println("info: Data Bits " + fmt.Sprintf("%v", Config.Global.Hardware.GPS.DataBits)) + log.Println("info: Char Time Out " + fmt.Sprintf("%v", Config.Global.Hardware.GPS.CharTimeOut)) + log.Println("info: Min Read " + fmt.Sprintf("%v", Config.Global.Hardware.GPS.MinRead)) + log.Println("info: Rx " + fmt.Sprintf("%t", Config.Global.Hardware.GPS.Rx)) } else { log.Println("info: ------------ GPS ------------------------ SKIPPED ") } - if PrintTraccar { + if Config.Global.Software.PrintVariables.PrintTraccar { log.Println("info: ------------ TRACCAR Info ----------------------- ") - log.Println("info: Track Enabled " + fmt.Sprintf("%t", TrackEnabled)) - log.Println("info: Traccar Send To " + fmt.Sprintf("%t", TraccarSendTo)) - log.Println("info: Traccar Server URL ", TraccarServerURL) - log.Println("info: Traccar Server IP ", TraccarServerIP) - log.Println("info: Traccar Client ID ", TraccarClientId) - log.Println("info: Traccar Report Frequency " + fmt.Sprintf("%v", TraccarReportFrequency)) - log.Println("info: Traccar Proto ", TraccarProto) - log.Println("info: Traccar Server Full URL ", TraccarServerFullURL) - log.Println("info: Track GPS Show Lcd " + fmt.Sprintf("%t", TrackGPSShowLCD)) - log.Println("info: Track Verbose " + fmt.Sprintf("%t", TrackVerbose)) + log.Println("info: Track Enabled " + fmt.Sprintf("%t", Config.Global.Hardware.GPSTrackingFunction.TrackEnabled)) + log.Println("info: Traccar Send To " + fmt.Sprintf("%t", Config.Global.Hardware.GPSTrackingFunction.TraccarSendTo)) + log.Println("info: Traccar Server URL ", Config.Global.Hardware.GPSTrackingFunction.TraccarServerURL) + log.Println("info: Traccar Server IP ", Config.Global.Hardware.GPSTrackingFunction.TraccarServerIP) + log.Println("info: Traccar Client ID ", Config.Global.Hardware.GPSTrackingFunction.TraccarClientId) + log.Println("info: Traccar Report Frequency " + fmt.Sprintf("%v", Config.Global.Hardware.GPSTrackingFunction.TraccarReportFrequency)) + log.Println("info: Traccar Proto ", Config.Global.Hardware.GPSTrackingFunction.TraccarProto) + log.Println("info: Traccar Server Full URL ", Config.Global.Hardware.GPSTrackingFunction.TraccarServerFullURL) + log.Println("info: Track GPS Show Lcd " + fmt.Sprintf("%t", Config.Global.Hardware.GPSTrackingFunction.TrackGPSShowLCD)) + log.Println("info: Track Verbose " + fmt.Sprintf("%t", Config.Global.Hardware.GPSTrackingFunction.TrackVerbose)) } else { log.Println("info: ------------ TRACCAR Info ------------------------ SKIPPED ") } - if PrintPanic { + if Config.Global.Software.PrintVariables.PrintPanic { log.Println("info: ------------ PANIC Function -------------- ") - log.Println("info: Panic Function Enable ", fmt.Sprintf("%t", PEnabled)) - log.Println("info: Panic Sound Filename and Path ", PFilenameAndPath) - log.Println("info: Panic Message ", PMessage) - log.Println("info: Panic Email Send ", fmt.Sprintf("%t", PMailEnabled)) - log.Println("info: Panic Message Send Recursively ", fmt.Sprintf("%t", PRecursive)) - log.Println("info: Panic Volume ", fmt.Sprintf("%v", PVolume)) - log.Println("info: Panic Send Ident ", fmt.Sprintf("%t", PSendIdent)) - log.Println("info: Panic Send GPS Location ", fmt.Sprintf("%t", PSendGpsLocation)) - log.Println("info: Panic TX Lock Enabled ", fmt.Sprintf("%t", PTxLockEnabled)) - log.Println("info: Panic TX Lock Timeout Secs ", fmt.Sprintf("%v", PTxlockTimeOutSecs)) - log.Println("info: Panic Low Profile Lights Enable", fmt.Sprintf("%v", PLowProfile)) + log.Println("info: Panic Function Enable ", fmt.Sprintf("%t", Config.Global.Hardware.PanicFunction.Enabled)) + log.Println("info: Panic Sound Filename and Path ", Config.Global.Hardware.PanicFunction.FilenameAndPath) + log.Println("info: Panic Message ", Config.Global.Hardware.PanicFunction.Message) + log.Println("info: Panic Email Send ", fmt.Sprintf("%t", Config.Global.Hardware.PanicFunction.PMailEnabled)) + log.Println("info: Panic Message Send Recursively ", fmt.Sprintf("%t", Config.Global.Hardware.PanicFunction.RecursiveSendMessage)) + log.Println("info: Panic Volume ", fmt.Sprintf("%v", Config.Global.Hardware.PanicFunction.Volume)) + log.Println("info: Panic Send Ident ", fmt.Sprintf("%t", Config.Global.Hardware.PanicFunction.SendIdent)) + log.Println("info: Panic Send GPS Location ", fmt.Sprintf("%t", Config.Global.Hardware.PanicFunction.SendGpsLocation)) + log.Println("info: Panic TX Lock Enabled ", fmt.Sprintf("%t", Config.Global.Hardware.PanicFunction.TxLockEnabled)) + log.Println("info: Panic TX Lock Timeout Secs ", fmt.Sprintf("%v", Config.Global.Hardware.PanicFunction.TxLockEnabled)) + log.Println("info: Panic Low Profile Lights Enable", fmt.Sprintf("%v", Config.Global.Hardware.PanicFunction.PLowProfile)) } else { log.Println("info: ------------ PANIC Function -------------- SKIPPED ") } - if PrintAudioRecord { + if Config.Global.Software.PrintVariables.PrintAudioRecord { log.Println("info: ------------ AUDIO RECORDING Function -------------- ") - log.Println("info: Audio Recording Enabled " + fmt.Sprintf("%v", AudioRecordEnabled)) - log.Println("info: Audio Recording On Start " + fmt.Sprintf("%v", AudioRecordOnStart)) - log.Println("info: Audio Recording System " + fmt.Sprintf("%v", AudioRecordSystem)) - log.Println("info: Audio Record Mode " + fmt.Sprintf("%v", AudioRecordMode)) - log.Println("info: Audio Record Timeout " + fmt.Sprintf("%v", AudioRecordTimeout)) - log.Println("info: Audio Record From Output " + fmt.Sprintf("%v", AudioRecordFromOutput)) - log.Println("info: Audio Record From Input " + fmt.Sprintf("%v", AudioRecordFromInput)) - log.Println("info: Audio Recording Mic Timeout " + fmt.Sprintf("%v", AudioRecordMicTimeout)) - log.Println("info: Audio Recording Save Path " + fmt.Sprintf("%v", AudioRecordSavePath)) - log.Println("info: Audio Recording Archive Path " + fmt.Sprintf("%v", AudioRecordArchivePath)) - log.Println("info: Audio Recording Soft " + fmt.Sprintf("%v", AudioRecordSoft)) - log.Println("info: Audio Recording Profile " + fmt.Sprintf("%v", AudioRecordProfile)) - log.Println("info: Audio Recording File Format " + fmt.Sprintf("%v", AudioRecordFileFormat)) - log.Println("info: Audio Recording Chunk Size " + fmt.Sprintf("%v", AudioRecordChunkSize)) + log.Println("info: Audio Recording Enabled " + fmt.Sprintf("%v", Config.Global.Hardware.AudioRecordFunction.Enabled)) + log.Println("info: Audio Recording On Start " + fmt.Sprintf("%v", Config.Global.Hardware.AudioRecordFunction.RecordOnStart)) + log.Println("info: Audio Recording System " + fmt.Sprintf("%v", Config.Global.Hardware.AudioRecordFunction.RecordSystem)) + log.Println("info: Audio Record Mode " + fmt.Sprintf("%v", Config.Global.Hardware.AudioRecordFunction.RecordMode)) + log.Println("info: Audio Record Timeout " + fmt.Sprintf("%v", Config.Global.Hardware.AudioRecordFunction.RecordTimeout)) + log.Println("info: Audio Record From Output " + fmt.Sprintf("%v", Config.Global.Hardware.AudioRecordFunction.RecordFromOutput)) + log.Println("info: Audio Record From Input " + fmt.Sprintf("%v", Config.Global.Hardware.AudioRecordFunction.RecordFromInput)) + log.Println("info: Audio Recording Mic Timeout " + fmt.Sprintf("%v", Config.Global.Hardware.AudioRecordFunction.RecordMicTimeout)) + log.Println("info: Audio Recording Save Path " + fmt.Sprintf("%v", Config.Global.Hardware.AudioRecordFunction.RecordSavePath)) + log.Println("info: Audio Recording Archive Path " + fmt.Sprintf("%v", Config.Global.Hardware.AudioRecordFunction.RecordArchivePath)) + log.Println("info: Audio Recording Soft " + fmt.Sprintf("%v", Config.Global.Hardware.AudioRecordFunction.RecordSoft)) + log.Println("info: Audio Recording Profile " + fmt.Sprintf("%v", Config.Global.Hardware.AudioRecordFunction.RecordProfile)) + log.Println("info: Audio Recording File Format " + fmt.Sprintf("%v", Config.Global.Hardware.AudioRecordFunction.RecordFileFormat)) + log.Println("info: Audio Recording Chunk Size " + fmt.Sprintf("%v", Config.Global.Hardware.AudioRecordFunction.RecordChunkSize)) } else { log.Println("info: ------------ AUDIO RECORDING Function ------- SKIPPED ") } - if PrintMQTT { + if Config.Global.Software.PrintVariables.PrintMQTT { log.Println("info: ------------ MQTT Function -------------- ") - log.Println("info: Enabled " + fmt.Sprintf("%v", MQTTEnabled)) - log.Println("info: Topic " + fmt.Sprintf("%v", MQTTTopic)) - log.Println("info: Broker " + fmt.Sprintf("%v", MQTTBroker)) - log.Println("info: Password " + fmt.Sprintf("%v", MQTTPassword)) - log.Println("info: Id " + fmt.Sprintf("%v", MQTTId)) - log.Println("info: Cleansess " + fmt.Sprintf("%v", MQTTCleansess)) - log.Println("info: Qos " + fmt.Sprintf("%v", MQTTQos)) - log.Println("info: Num " + fmt.Sprintf("%v", MQTTNum)) - log.Println("info: Payload " + fmt.Sprintf("%v", MQTTPayload)) - log.Println("info: Action " + fmt.Sprintf("%v", MQTTAction)) - log.Println("info: Store " + fmt.Sprintf("%v", MQTTStore)) - log.Println("info: AttentionBlinkTimes " + fmt.Sprintf("%v", MQTTAttentionBlinkTimes)) - log.Println("info: AttentionBlinkmsecs " + fmt.Sprintf("%v", MQTTAttentionBlinkmsecs)) + log.Println("info: Enabled " + fmt.Sprintf("%v", Config.Global.Software.RemoteControl.MQTT.Enabled)) + log.Println("info: Topic " + fmt.Sprintf("%v", Config.Global.Software.RemoteControl.MQTT.Settings.MQTTTopic)) + log.Println("info: Broker " + fmt.Sprintf("%v", Config.Global.Software.RemoteControl.MQTT.Settings.MQTTBroker)) + log.Println("info: Password " + fmt.Sprintf("%v", Config.Global.Software.RemoteControl.MQTT.Settings.MQTTPassword)) + log.Println("info: Id " + fmt.Sprintf("%v", Config.Global.Software.RemoteControl.MQTT.Settings.MQTTId)) + log.Println("info: Cleansess " + fmt.Sprintf("%v", Config.Global.Software.RemoteControl.MQTT.Settings.MQTTCleansess)) + log.Println("info: Qos " + fmt.Sprintf("%v", Config.Global.Software.RemoteControl.MQTT.Settings.MQTTQos)) + log.Println("info: Num " + fmt.Sprintf("%v", Config.Global.Software.RemoteControl.MQTT.Settings.MQTTNum)) + log.Println("info: Payload " + fmt.Sprintf("%v", Config.Global.Software.RemoteControl.MQTT.Settings.MQTTPayload)) + log.Println("info: Action " + fmt.Sprintf("%v", Config.Global.Software.RemoteControl.MQTT.Settings.MQTTAction)) + log.Println("info: Store " + fmt.Sprintf("%v", Config.Global.Software.RemoteControl.MQTT.Settings.MQTTStore)) + log.Println("info: AttentionBlinkTimes " + fmt.Sprintf("%v", Config.Global.Software.RemoteControl.MQTT.Settings.MQTTAttentionBlinkTimes)) + log.Println("info: AttentionBlinkmsecs " + fmt.Sprintf("%v", Config.Global.Software.RemoteControl.MQTT.Settings.MQTTAttentionBlinkmsecs)) + for _, command := range Config.Global.Software.RemoteControl.MQTT.Commands.Command { + log.Printf("info: Enabled=%v Action=%v Message=%v\n", command.Enabled, command.Action, command.Message) + } } else { log.Println("info: ------------ MQTT Function ------- SKIPPED ") } - if PrintTTSMessages { + if Config.Global.Software.PrintVariables.PrintTTSMessages { log.Println("info: ------------ TTSMessages Function -------------- ") - log.Println("info: Enabled " + fmt.Sprintf("%v", TTSMessageEnabled)) - log.Println("info: LocalPlay " + fmt.Sprintf("%v", TTSLocalPlay)) - log.Println("info: LocalPlayWithRXLED " + fmt.Sprintf("%v", TTSLocalPlayWithRXLED)) - log.Println("info: Play Into Stream " + fmt.Sprintf("%v", TTSPlayIntoStream)) - log.Println("info: TTSLanguage " + fmt.Sprintf("%v", TTSLanguage)) - log.Println("info: TTSSoundDirectory " + fmt.Sprintf("%v", TTSSoundDirectory)) - log.Println("info: TTSAnnouncementTone " + fmt.Sprintf("%v", TTSAnnouncementTone)) - log.Println("info: TTSMessageFromTag " + fmt.Sprintf("%v", TTSMessageFromTag)) + log.Println("info: Enabled " + fmt.Sprintf("%v", Config.Global.Software.TTSMessages.Enabled)) + log.Println("info: LocalPlay " + fmt.Sprintf("%v", Config.Global.Software.TTSMessages.LocalPlay)) + log.Println("info: Play Into Stream " + fmt.Sprintf("%v", Config.Global.Software.TTSMessages.PlayIntoStream)) + log.Println("info: TTS Speak Volume Into Stream " + fmt.Sprintf("%v", Config.Global.Software.TTSMessages.SpeakVolumeIntoStream)) + log.Println("info: TTS Play Volume Into Stream " + fmt.Sprintf("%v", Config.Global.Software.TTSMessages.PlayVolumeIntoStream)) + log.Println("info: TTSLanguage " + fmt.Sprintf("%v", Config.Global.Software.TTSMessages.TTSLanguage)) + log.Println("info: TTSSoundDirectory " + fmt.Sprintf("%v", Config.Global.Software.TTSMessages.TTSSoundDirectory)) + log.Println("info: TTSAnnouncementTone Enabled " + fmt.Sprintf("%v", Config.Global.Software.TTSMessages.TTSTone.ToneEnabled)) + log.Println("info: TTSAnnouncementTone File " + fmt.Sprintf("%v", Config.Global.Software.TTSMessages.TTSTone.ToneFile)) + log.Println("info: TTSMessageFromTag " + fmt.Sprintf("%v", Config.Global.Software.TTSMessages.TTSMessageFromTag)) + log.Println("info: TTSGPIOEnabled " + fmt.Sprintf("%v", Config.Global.Software.TTSMessages.GPIO.Enabled)) + log.Println("info: TTSGPIOName " + fmt.Sprintf("%v", Config.Global.Software.TTSMessages.GPIO.Name)) + log.Println("info: TTSPreDelay " + fmt.Sprintf("%v", Config.Global.Software.TTSMessages.PreDelay)) + log.Println("info: TTSPostDelay " + fmt.Sprintf("%v", Config.Global.Software.TTSMessages.PreDelay)) } else { log.Println("info: ------------ TTSMessages Function ------- SKIPPED ") } - if PrintIgnoreUser { + if Config.Global.Software.PrintVariables.PrintIgnoreUser { log.Println("info: ------------ IgnoreUserRegex Function -------------- ") - log.Println("info: Enabled " + fmt.Sprintf("%v", IgnoreUserEnabled)) - log.Println("info: IgnoreUserRegex " + fmt.Sprintf("%v", IgnoreUserRegex)) + log.Println("info: Enabled " + fmt.Sprintf("%v", Config.Global.Software.IgnoreUser.IgnoreUserEnabled)) + log.Println("info: IgnoreUserRegex " + fmt.Sprintf("%v", Config.Global.Software.IgnoreUser.IgnoreUserRegex)) } else { log.Println("info: ------------ IgnoreUserRegex Function ------- SKIPPED ") } - if PrintKeyboardMap { + if Config.Global.Software.PrintVariables.PrintKeyboardMap { log.Println("info: ------------ KeyboardMap Function -------------- ") - log.Printf("TTYKeymap %+v\n", TTYKeyMap) - log.Printf("USBKeymap %+v\n", USBKeyMap) + counter := 1 + for _, value := range Config.Global.Hardware.Keyboard.Command { + if value.Enabled { + log.Printf("info: %v Enabled %v Command %v ParamValue %v\n", counter, value.Enabled, value.Action, value.Paramvalue) + counter++ + } + if value.Ttykeyboard.Enabled { + log.Println("info: TTYKeyboard " + fmt.Sprintf("%+v", value.Ttykeyboard)) + } + if value.Usbkeyboard.Enabled { + log.Println("info: USBKeyboard " + fmt.Sprintf("%+v", value.Usbkeyboard)) + } + } } else { log.Println("info: ------------ KeyboardMap Function ------ SKIPPED ") } - if PrintUSBKeyboard { + if Config.Global.Software.PrintVariables.PrintUSBKeyboard { log.Println("info: ------------ USBKeyboard Function -------------- ") - log.Println("USBKeyboardEnabled", USBKeyboardEnabled) - log.Println("USBKeyboardPath", USBKeyboardPath) - log.Println("NumLockScanID", NumlockScanID) + log.Println("USBKeyboardEnabled", Config.Global.Hardware.USBKeyboard.Enabled) + log.Println("USBKeyboardPath", Config.Global.Hardware.USBKeyboard.USBKeyboardPath) + log.Println("NumLockScanID", Config.Global.Hardware.USBKeyboard.NumlockScanID) } else { log.Println("info: ------------ USBKeyboard Function ------ SKIPPED ") } + if Config.Global.Software.PrintVariables.PrintMultimedia { + log.Println("info: ------------ Multimedia Function -------------- ") + for _, value := range Config.Global.Multimedia.ID { + if value.Enabled { + log.Printf("info: Announcement Tone Enabled %v \n", value.Params.Announcementtone.Enabled) + log.Printf("info: Announcement Tone File %v \n", value.Params.Announcementtone.File) + log.Printf("info: GPIO Enabled %v \n", value.Params.GPIO.Enabled) + log.Printf("info: GPIO Name %v \n", value.Params.GPIO.Name) + log.Printf("info: Local Play %v \n", value.Params.Localplay) + log.Printf("info: Play Into Stream %v \n", value.Params.Playintostream) + log.Printf("info: Pre Delay %v \n", value.Params.Predelay) + log.Printf("info: Post Delay %v \n", value.Params.Postdelay) + log.Printf("info: Voice Target %v \n", value.Params.Voicetarget) + log.Printf("info: Enabled %v \n", value.Enabled) + log.Printf("info: Media Souce %+v \n", value.Media.Source) + } + } + } else { + log.Println("info: ------------ Multimedia Function ------ SKIPPED ") + } + } func modifyXMLTagServerHopping(inputXMLFile string, newserverindex int) { @@ -2141,12 +1200,12 @@ func modifyXMLTagServerHopping(inputXMLFile string, newserverindex int) { return } - if NextServerIndex == newserverindex { + if Config.Global.Software.Settings.NextServerIndex == newserverindex { log.Println("error: Server Index is Not Changed") return } - PreparedSEDCommand := fmt.Sprintf("s#%d#%d#", NextServerIndex, newserverindex) + PreparedSEDCommand := fmt.Sprintf("s#%d#%d#", Config.Global.Software.Settings.NextServerIndex, newserverindex) cmd := exec.Command("sed", "-i", PreparedSEDCommand, inputXMLFile) err := cmd.Run() @@ -2157,3 +1216,296 @@ func modifyXMLTagServerHopping(inputXMLFile string, newserverindex int) { killSession() } + +func CheckConfigSanity(reloadxml bool) { + + Warnings := 0 + Alerts := 0 + + log.Println("info: Starting XML Configuration Sanity and Logical Checks") + + Counter := 0 + for _, account := range Config.Accounts.Account { + if account.Default { + if len(account.Name) == 0 { + log.Print("warn: Config Error [Section Accounts] Account Name Not Defined for Enabled Account") + } + if len(account.ServerAndPort) == 0 { + log.Print("alert: Config Error [Section Accounts] Account Server And Port Not Defined for Enabled Account") + } + + if len(account.Certificate) > 0 && !FileExists(account.Certificate) { + log.Print("warn: Config Error [Section Accounts] Certificate Enabled but Not Found") + } + Counter++ + } + } + + if Counter == 0 { + log.Print("alert: Config Error [Section Accounts] No Default/Enabled Accounts Found in Config") + Alerts++ + } + + if Config.Global.Software.Settings.NextServerIndex > Counter { + log.Print("warn: Config Error [Section Settings] Next Server Index Invalid Defaulting back to 0") + Config.Global.Software.Settings.NextServerIndex = 0 + Warnings++ + } + + if Config.Global.Software.AutoProvisioning.Enabled { + + if len(Config.Global.Software.AutoProvisioning.TkID) == 0 || len(Config.Global.Software.AutoProvisioning.URL) == 0 || len(Config.Global.Software.AutoProvisioning.SaveFilePath) == 0 || len(Config.Global.Software.AutoProvisioning.SaveFilename) == 0 { + log.Print("warn: Config Error [Section Autoprovisioning] Some Parameters Not Defined Disabling AutoProvisioning") + Config.Global.Software.AutoProvisioning.Enabled = false + Warnings++ + } + + } + + if Config.Global.Software.Beacon.Enabled { + if Config.Global.Software.Beacon.BeaconTimerSecs == 0 || len(Config.Global.Software.Beacon.BeaconFileAndPath) == 0 || Config.Global.Software.Beacon.Volume == 0 { + log.Print("warn: Config Error [Section Beacon] Some Parameters Not Defined Disabling Beacon") + Config.Global.Software.Beacon.Enabled = false + Warnings++ + } + } + + for index, sounds := range Config.Global.Software.Sounds.Sound { + if sounds.Enabled { + if len(sounds.File) > 0 { + if !FileExists(sounds.File) { + if !checkRegex("(http|rtsp)", sounds.File) { + log.Printf("warn: Config Error [Section Sounds] Enabled Sound Event %v File/Link Missing in Config\n", sounds.Event) + Config.Global.Software.Sounds.Sound[index].Enabled = false + Warnings++ + } + } + } + + volume, _ := strconv.Atoi(sounds.Volume) + if volume == 0 { + log.Printf("warn: Config Error [Section Sounds] Enabled Sound Event %v Volume = 0 in Config\n", sounds.Event) + Config.Global.Software.Sounds.Sound[index].Enabled = false + Warnings++ + } + } + } + + if Config.Global.Software.SMTP.Enabled { + if len(Config.Global.Software.SMTP.Username) == 0 || len(Config.Global.Software.SMTP.Password) == 0 || len(Config.Global.Software.SMTP.Receiver) == 0 { + log.Print("warn: Config Error [Section SMTP] Some Parameters Not Defined Disabling SMTP") + Config.Global.Software.SMTP.Enabled = false + Warnings++ + } + } + + for index, gpio := range Config.Global.Hardware.IO.Pins.Pin { + if gpio.Enabled { + if !(gpio.Direction == "input" || gpio.Direction == "output") { + log.Printf("warn: Config Error [Section GPIO] Enabled GPIO Name %v Pin Number %v Direction %v Misconfiguired\n", gpio.Name, gpio.PinNo, gpio.Direction) + Config.Global.Hardware.IO.Pins.Pin[index].Enabled = false + Warnings++ + } + if (gpio.Direction == "input") && !(gpio.Device == "pushbutton" || gpio.Device == "toggleswitch" || gpio.Device == "rotaryencoder") { + log.Printf("warn: Config Error [Section GPIO] Enabled Input GPIO Name %v Pin Number %v Name Mis-Configured\n", gpio.Name, gpio.PinNo) + Config.Global.Hardware.IO.Pins.Pin[index].Enabled = false + Warnings++ + } + if (gpio.Direction == "output") && !(gpio.Device == "led/relay" || gpio.Device == "lcd") { + log.Printf("warn: Config Error [Section GPIO] Enabled Output GPIO Name %v Pin Number %v Name Mis-Configured\n", gpio.Name, gpio.PinNo) + Config.Global.Hardware.IO.Pins.Pin[index].Enabled = false + Warnings++ + } + + if !(gpio.Name == "voiceactivity" || gpio.Name == "participants" || gpio.Name == "transmit" || gpio.Name == "online" || gpio.Name == "attention" || gpio.Name == "voicetarget" || gpio.Name == "heartbeat" || gpio.Name == "backlight" || gpio.Name == "relay0" || gpio.Name == "txptt" || gpio.Name == "txtoggle" || gpio.Name == "channelup" || gpio.Name == "channeldown" || gpio.Name == "panic" || gpio.Name == "streamtoggle" || gpio.Name == "comment" || gpio.Name == "rotarya" || gpio.Name == "rotaryb") { + log.Printf("warn: Config Error [Section GPIO] Enabled GPIO Name %v Pin Number %v Invalid Name\n", gpio.Name, gpio.PinNo) + Config.Global.Hardware.IO.Pins.Pin[index].Enabled = false + Warnings++ + } + + if gpio.PinNo > 30 { + log.Printf("warn: Config Error [Section GPIO] Enabled GPIO Name %v Pin Number %v Invalid GPIO Number\n", gpio.Name, gpio.PinNo) + Config.Global.Hardware.IO.Pins.Pin[index].Enabled = false + Warnings++ + } + + if gpio.ID > 8 { + log.Print("warn: Config Error [Section GPIO] Invalid ChipID Address") + Config.Global.Hardware.IO.Pins.Pin[index].Enabled = false + Warnings++ + } + + if gpio.Name == "heartbeat" { + if Config.Global.Hardware.HeartBeat.Periodmsecs < 100 || Config.Global.Hardware.HeartBeat.LEDOnmsecs < 100 || Config.Global.Hardware.HeartBeat.LEDOffmsecs < 100 { + if gpio.PinNo == 0 { + log.Printf("warn: Config Error [Section GPIO] Name %v Invalid GPIO Pin %v Value\n", gpio.Name, gpio.PinNo) + Config.Global.Hardware.IO.Pins.Pin[index].Enabled = false + Warnings++ + } + } + } + + } + } + + if Config.Global.Hardware.LCD.BacklightTimerEnabled && (!Config.Global.Hardware.OLED.Enabled || !Config.Global.Hardware.LCD.Enabled) { + log.Println("warn: Disabling Backlight Timer Since Neither LCD or OLED Displays Enabled") + Config.Global.Hardware.LCD.BacklightTimerEnabled = false + Warnings++ + } + + if Config.Global.Hardware.LCD.Enabled { + if !(Config.Global.Hardware.LCD.InterfaceType == "i2c" || Config.Global.Hardware.LCD.InterfaceType == "parallel") { + log.Printf("warn: Config Error [Section LCD] Enabled LCD Interface Type %v Invalid\n", Config.Global.Hardware.LCD.InterfaceType) + Config.Global.Hardware.LCD.Enabled = false + Warnings++ + } + + if Config.Global.Hardware.LCD.InterfaceType == "i2c" { + if Config.Global.Hardware.LCD.I2CAddress == 0 { + log.Printf("warn: Config Error [Section LCD] Enabled LCD Interface %v Invalid\n", Config.Global.Hardware.LCD.InterfaceType) + Config.Global.Hardware.LCD.Enabled = false + Warnings++ + } + } + + if Config.Global.Hardware.LCD.InterfaceType == "parallel" { + if Config.Global.Hardware.LCD.RsPin == 0 { + log.Printf("warn: Config Error [Section LCD] Enabled LCD Interface %v RsPin %v Invalid\n", Config.Global.Hardware.LCD.InterfaceType, Config.Global.Hardware.LCD.RsPin) + Config.Global.Hardware.LCD.Enabled = false + Warnings++ + } + if Config.Global.Hardware.LCD.EPin == 0 { + log.Printf("warn: Config Error [Section LCD] Enabled LCD Interface %v EPin %v Invalid\n", Config.Global.Hardware.LCD.InterfaceType, Config.Global.Hardware.LCD.RsPin) + Config.Global.Hardware.LCD.Enabled = false + Warnings++ + } + if Config.Global.Hardware.LCD.D4Pin == 0 { + log.Printf("warn: Config Error [Section LCD] Enabled LCD Interface %v D4Pin %v Invalid\n", Config.Global.Hardware.LCD.InterfaceType, Config.Global.Hardware.LCD.RsPin) + Config.Global.Hardware.LCD.Enabled = false + Warnings++ + } + if Config.Global.Hardware.LCD.D5Pin == 0 { + log.Printf("warn: Config Error [Section LCD] Enabled LCD Interface %v D5Pin %v Invalid\n", Config.Global.Hardware.LCD.InterfaceType, Config.Global.Hardware.LCD.RsPin) + Config.Global.Hardware.LCD.Enabled = false + Warnings++ + } + if Config.Global.Hardware.LCD.D6Pin == 0 { + log.Printf("warn: Config Error [Section LCD] Enabled LCD Interface %v D6Pin %v Invalid\n", Config.Global.Hardware.LCD.InterfaceType, Config.Global.Hardware.LCD.RsPin) + Config.Global.Hardware.LCD.Enabled = false + Warnings++ + } + if Config.Global.Hardware.LCD.D7Pin == 0 { + log.Printf("warn: Config Error [Section LCD] Enabled LCD Interface %v D7Pin %v Invalid\n", Config.Global.Hardware.LCD.InterfaceType, Config.Global.Hardware.LCD.RsPin) + Config.Global.Hardware.LCD.Enabled = false + Warnings++ + } + } + } + if Config.Global.Hardware.LCD.BacklightTimerEnabled { + if Config.Global.Hardware.LCD.BackLightTimeoutSecs == 0 { + log.Print("warn: Config Error [Section LCD] Disabling Invalid Backlight Timer") + Config.Global.Hardware.LCD.BacklightTimerEnabled = false + Warnings++ + } + } + + if Config.Global.Hardware.GPS.Enabled { + if !FileExists(Config.Global.Hardware.GPS.Port) { + log.Printf("warn: Config Error [Section GPS] Enabled GPS Port %v Invalid\n", Config.Global.Hardware.GPS.Port) + Config.Global.Hardware.GPS.Enabled = false + Warnings++ + } + if !(Config.Global.Hardware.GPS.Baud == 2400 || Config.Global.Hardware.GPS.Baud == 4800 || Config.Global.Hardware.GPS.Baud == 9600 || Config.Global.Hardware.GPS.Baud == 14400 || Config.Global.Hardware.GPS.Baud == 19200 || Config.Global.Hardware.GPS.Baud == 38400 || Config.Global.Hardware.GPS.Baud == 57600 || Config.Global.Hardware.GPS.Baud == 115200) { + log.Printf("warn: Config Error [Section GPS] Enabled GPS Port %v Invalid Baud %v Setting\n", Config.Global.Hardware.GPS.Port, Config.Global.Hardware.GPS.Baud) + Config.Global.Hardware.GPS.Enabled = false + Warnings++ + } + + if Config.Global.Hardware.GPS.Even && Config.Global.Hardware.GPS.Odd { + log.Printf("warn: Config Error [Section GPS] Enabled GPS Port %v Invalid Parity Both Even & Odd Set\n", Config.Global.Hardware.GPS.Port) + Config.Global.Hardware.GPS.Enabled = false + Warnings++ + } + + if Config.Global.Hardware.GPS.StopBits == 0 { + log.Printf("warn: Config Error [Section GPS] Enabled GPS Port %v Invalid Stop Bits\n", Config.Global.Hardware.GPS.Port) + Config.Global.Hardware.GPS.Enabled = false + Warnings++ + } + + if Config.Global.Hardware.GPS.DataBits == 0 { + log.Printf("warn: Config Error [Section GPS] Enabled GPS Port %v Invalid Data Bits\n", Config.Global.Hardware.GPS.Port) + Config.Global.Hardware.GPS.Enabled = false + Warnings++ + } + } + + if Config.Global.Software.RemoteControl.MQTT.Enabled { + + if len(Config.Global.Software.RemoteControl.MQTT.Settings.MQTTTopic) == 0 { + log.Println("warn: Config Error [Section MQTT] Enabled MQTT With Empty Topic") + Config.Global.Software.RemoteControl.MQTT.Enabled = false + Warnings++ + } + if len(Config.Global.Software.RemoteControl.MQTT.Settings.MQTTBroker) == 0 { + log.Println("warn: Config Error [Section MQTT] Enabled MQTT With Empty Broker") + Config.Global.Software.RemoteControl.MQTT.Enabled = false + Warnings++ + } + if len(Config.Global.Software.RemoteControl.MQTT.Settings.MQTTPassword) == 0 { + log.Println("warn: Config Error [Section MQTT] Enabled MQTT With Empty MQTTPassword") + Config.Global.Software.RemoteControl.MQTT.Enabled = false + Warnings++ + } + if len(Config.Global.Software.RemoteControl.MQTT.Settings.MQTTId) == 0 { + log.Println("warn: Config Error [Section MQTT] Enabled MQTT With Empty MQTTID") + Config.Global.Software.RemoteControl.MQTT.Enabled = false + Warnings++ + } + + } + + if Config.Global.Software.IgnoreUser.IgnoreUserEnabled { + if len(Config.Global.Software.IgnoreUser.IgnoreUserRegex) < 4 { + log.Printf("warn: Config Error [Section ignoreuser] %v Invalid Regex\n", Config.Global.Software.IgnoreUser.IgnoreUserRegex) + Config.Global.Software.IgnoreUser.IgnoreUserEnabled = false + } + } + + for index, keyboard := range Config.Global.Hardware.Keyboard.Command { + if keyboard.Enabled { + if !(keyboard.Action == "channelup" || keyboard.Action == "channeldown" || keyboard.Action == "serverup" || keyboard.Action == "serverdown" || keyboard.Action == "mute" || keyboard.Action == "unmute" || keyboard.Action == "mute-toggle" || keyboard.Action == "stream-toggle" || keyboard.Action == "volumeup" || keyboard.Action == "volumedown" || keyboard.Action == "setcomment" || keyboard.Action == "transmitstart" || keyboard.Action == "transmitstop" || keyboard.Action == "record" || keyboard.Action == "voicetargetset") { + log.Printf("warn: Config Error [Section Keyboard] Enabled Keyboard Action %v Invalid\n", keyboard.Action) + Config.Global.Hardware.Keyboard.Command[index].Enabled = false + Warnings++ + + } + if keyboard.Ttykeyboard.Enabled { + if keyboard.Ttykeyboard.Scanid == 0 || keyboard.Ttykeyboard.Scanid > 255 { + log.Printf("warn: Config Error [Section Keyboard] Enabled TTYKeyboard ScanID %v Invalid\n", keyboard.Ttykeyboard.Scanid) + Config.Global.Hardware.Keyboard.Command[index].Ttykeyboard.Enabled = false + Warnings++ + } + } + if keyboard.Usbkeyboard.Enabled { + if keyboard.Usbkeyboard.Scanid == 0 || keyboard.Usbkeyboard.Scanid > 255 { + log.Printf("warn: Config Error [Section Keyboard] Enabled USBKeyboard ScanID %v Invalid\n", keyboard.Usbkeyboard.Scanid) + Config.Global.Hardware.Keyboard.Command[index].Usbkeyboard.Enabled = false + Warnings++ + } + } + } + } + if Warnings+Alerts > 0 { + if Alerts > 0 { + FatalCleanUp("alert: Fatal Errors Found In talkkonnect.xml config file please fix errors, talkkonnect stopping now!") + } + + if Warnings > 0 { + log.Println("warn: Non-Critical Errors Found In talkkonnect.xml config file please fix errors or talkkonnect may not behave as expected") + } + } else { + log.Println("info: Finished XML Configuration Sanity and Logical Checks Without Any Alerts/Errors/Warnings") + } +}