/// <summary> /// Decoder statistics thread method /// </summary> static void DecoderLoop() { string logsrc = "DECODER"; Program.Log(logsrc, "START"); Socket s = new Socket(SocketType.Stream, ProtocolType.Tcp); Program.Log(logsrc, "Socket created"); try { // Connect socket s.Connect(IP.ToString(), DecoderPort); Program.Log(logsrc, string.Format("Connected to {0}:{1}", IP, DecoderPort.ToString())); // Send nanomsg init message s.Send(nninit); // Check nanomsg response byte[] res = new byte[8]; int bytesRec = s.Receive(res); if (res.SequenceEqual(nnires)) { Program.Log(logsrc, "nanomsg OK"); } else { string resHex = BitConverter.ToString(res); Program.Log(logsrc, string.Format("nanomsg error: {0} (Expected: {1})", resHex, BitConverter.ToString(nnires))); } } catch (Exception e) { Program.Log(logsrc, "Failed to connect"); return; } byte[] dres = new byte[256]; int num; JObject json; // Signal quality float sigQ = 0f; float vitLow = 30f; float vitHigh = 1000f; // Averaging long timeAvg = DateTimeOffset.Now.ToUnixTimeMilliseconds(); List <int> vitAvg = new List <int>(); List <int> rsAvg = new List <int>(); // Continually receive data while (true) { // Receive nanomsg header num = s.Receive(dres, 8, SocketFlags.None); // Kill thread if no data received if (num == 0) { Program.Log(logsrc, "Connection lost/no data, killing thread"); return; } // Get message length int msglen = dres[7]; // Receive message content num = s.Receive(dres, msglen, SocketFlags.None); // Log message bytes //Program.Log(logsrc, BitConverter.ToString(dres).Replace("-", "")); // Kill thread if no data received if (num == 0) { Program.Log(logsrc, "Connection lost/no data, killing thread"); return; } // Convert message bytes to ASCII string data = Encoding.ASCII.GetString(dres); // Trim message length and remove trailing new line data = data.Substring(0, msglen); data = data.TrimEnd('\n'); // Parse JSON object try { json = JObject.Parse(data); Program.Log(logsrc, string.Format("OK: {0}", data)); } catch (Newtonsoft.Json.JsonReaderException e) { Program.Log(logsrc, string.Format("Error parsing JSON: {0}", data)); Program.Log(logsrc, e.ToString()); continue; } // Signal lock indicator bool locked = (json["ok"] != null) ? ((int)json["ok"] != 0) : false; // Viterbi errors int vit = (int)json["viterbi_errors"]; // Reed-Solomon errors int rs = (int)json["reed_solomon_errors"]; rs = (rs > 0) ? rs : 0; // Write parsed data to log Program.Log(logsrc, string.Format("LOCK: {0} VITERBI: {1} RS: {2}", locked, vit, rs)); // Add values to average lists vitAvg.Add(vit); rsAvg.Add(rs); // Calculate signal quality (capped at 100) sigQ = 100 - (((vit - vitLow) / (vitHigh - vitLow)) * 100); sigQ = (sigQ > 100) ? 100 : sigQ; sigQ = (sigQ < 0) ? 0 : sigQ; // Update stats plot UI if (Program.PlotWindow.Visible && Program.PlotWindow.ReadyForData) { Program.PlotWindow.Update(vit, (int)rsAvg.Average()); } // Calculate average every second if (DateTimeOffset.Now.ToUnixTimeMilliseconds() - timeAvg > 1000) { Program.Log(logsrc, string.Format("AVERAGE QUALITY: {0}% AVERAGE VITERBI: {1} AVERAGE RS: {2}", sigQ, (int)vitAvg.Average(), (int)rsAvg.Average())); // Update main UI Program.MainWindow.SignalLock = locked; Program.MainWindow.SignalQuality = (int)sigQ; Program.MainWindow.ViterbiErrors = (int)vitAvg.Average(); Program.MainWindow.RSErrors = (int)rsAvg.Average(); // Update large stats UI if (Program.BigWindow.Visible) { Program.BigWindow.SignalLock = locked; Program.BigWindow.SignalQuality = (int)sigQ; Program.BigWindow.ViterbiErrors = (int)vitAvg.Average(); Program.BigWindow.RSErrors = (int)rsAvg.Average(); } // Reset average time vitAvg.Clear(); rsAvg.Clear(); timeAvg = DateTimeOffset.Now.ToUnixTimeMilliseconds(); } } }
/// <summary> /// Decoder statistics thread method /// </summary> static void DecoderLoop() { Console.WriteLine("[DECODER] Started"); Socket s = new Socket(SocketType.Stream, ProtocolType.Tcp); try { // Connect socket s.Connect(IP.ToString(), DecoderPort); Console.WriteLine("[DECODER] Connected to {0}:{1}", IP, DecoderPort.ToString()); // Send nanomsg init message s.Send(nninit); // Check nanomsg response byte[] res = new byte[8]; int bytesRec = s.Receive(res); if (res.SequenceEqual(nnires)) { Console.WriteLine("[DECODER] Nanomsg OK"); } else { string resHex = BitConverter.ToString(res); Console.WriteLine("[DECODER] Nanomsg error: {0} (Expected: {1})", resHex, BitConverter.ToString(nnires)); } } catch (Exception e) { Console.WriteLine("[DECODER] Failed to connect"); return; } // Continually receive data while (true) { byte[] dres = new byte[1024]; int numbytes = s.Receive(dres); // Kill thread if no data received if (numbytes == 0) { Console.WriteLine("[DECODER] No data"); return; } // Convert to string and trim string data = Encoding.ASCII.GetString(dres).TrimEnd('\0').TrimEnd('\n'); int vitErr; int rsErr = 0; bool locked; try { // Get Virerbi error count string vitStr = data.Substring(data.IndexOf("viterbi_errors") + 17); vitStr = vitStr.Substring(0, vitStr.IndexOf(',')); vitErr = int.Parse(vitStr); // Get lock state string lockStr = data.Substring(data.IndexOf("ok") + 5, 1); if (lockStr == "1") { locked = true; } else { locked = false; } // Split data into lines rsErr = 0; string[] lines = data.Split('\n'); foreach (string l in lines) { // Parse Line string rsStr = l.Substring(l.IndexOf("reed_solomon_errors") + 22); rsStr = rsStr.Substring(0, rsStr.IndexOf(',')); if (rsStr != "-1") { int.TryParse(rsStr, out rsErr); } } } catch (ArgumentOutOfRangeException e) { Console.WriteLine("[DEMOD] Substring error"); continue; } // Cap viterbi in range for signal quality float vitErrQ = vitErr; float vitLower = 30f; float vitUpper = 1000f; if (vitErr < vitLower) { vitErrQ = vitLower; } else if (vitErr > vitUpper) { vitErrQ = vitUpper; } // Calculate signal quality float sigQ = 100 - (((vitErrQ - vitLower) / (vitUpper - vitLower)) * 100); // Update UI Program.MainWindow.SignalLock = locked; Program.MainWindow.SignalQuality = (int)sigQ; Program.MainWindow.ViterbiErrors = vitErr; Program.MainWindow.RSErrors = rsErr; Thread.Sleep(500); } }