using LibrarySDR; using LibrarySDR.Enums; using LibrarySDR.Responses; using NAudio.Wave; using Nini.Config; using SafeMobileLib; using SafeMobileLib.Helpers; using SafeMobileLib.Registration; using SafeMobileLib.Tetra; using SharedUI; using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Drawing; using System.IO; using System.IO.Ports; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using Telerik.WinControls; using Telerik.WinControls.UI; using Tetra_GW.Helpers; using smutils = SafeMobileLib.Utils; namespace Tetra_GW { //+MCTGDR – Command for reading DMO talkgroups +MCTGDR: 1,DMO TG1,600101,420000000,1,1,DMO Folder1 // 2,DMO TG2,457,421000000,1,1,DMO Folder1 //+CTOM - TMO/DMO Operating mode // LIP - Location Information Protocol // DMO - Direct Mode Operations // TMO - Trunked Mode Operations(also known as V+D for Voice + Data) // TG - Talkgroup //ISSI - Individual Short Subscriber Identity // SDS - Short Data Service //SDS-TL - SDS Transport Layer(provides end-to-end delivery acknowledgement) //SSI - Short Subscriber Identity //DM-MS - MS operating in DMO // TSI - Tetra Subscriber Identit public partial class MainForm : RadForm { private System.Threading.Timer _memoryCheckTimer; private InterthreadMessageQueue> MessageQueue; private bool stopMessageConsume = false; private enum CallState { Idle, InProgress, HangTime }; private LIPDecoder lipDecoder = new LIPDecoder(); private Int64 ISSI = 0; private Int32 BAUD_RATE = ConfigHelper.BaudRate; //9600 //38400 //115200 private static Int32 AREA = ConfigHelper.Area; #region variables private CallState callState = CallState.Idle; private BindingList eventsList = new BindingList(); private Gateway currentGateway = null; private RadioGateway currentRadioGw; System.Timers.Timer rebootCheck; private volatile String[] ports; private Hashtable htSU = new Hashtable(); private UdpMulticast udpMulticast; private String lastLat = "", lastLng = "", SUID = ""; private Hashtable portHT = new Hashtable(); private volatile bool _shouldStop = false; private volatile bool _isConnected = false; private volatile int counter = 0; private volatile bool keepAlive = false; private volatile bool needToRegister = false; private volatile int intRegister = 0; System.Threading.Timer _gatewayStatusTimer = null; private string radioMesageError = "Fail to communicate with radio"; private string GWID = "0"; private string RadioGwId = "0"; private string callerID = null; private string callStatus = "1"; //init call private string _callType = null; private string groupID = null; private string callInstance = "1"; bool isDMO = true; bool hasPresenceCheck = true; int msgReceived = 0; #endregion variables #region voice variables public volatile WaveIn waveInClass = null; public volatile WaveOut waveOutClass = null; private volatile BufferedWaveProvider buffWaveProvider = null; public int selectedOUTDevice; public string selectedOUTDeviceName = " "; public int selectedINDevice; public string selectedINDeviceName = " "; private string voiceMulticastIP4Send; private string voiceMulticastIP4Recv; private UdpMulticast udp4VoiceSend; private UdpMulticast udp4VoiceRecv; private bool PTTbusy = false; private bool isPortable = false; #endregion voice #region constructor public MainForm() { InitializeComponent(); stopMessageConsume = false; Version v = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; SafeMobileLib.Utils.WriteLine("Version: " + v.ToString()); this.Text += " - v." + v.ToString(); SafeMobileLib.Utils.WriteLine("Tetra Gateway. SafeMobile 2012-2019", ConsoleColor.Magenta); SafeMobileLib.Utils.WriteLine(""); rcpSettings.Collapse(); // set datasource for events rlvEvents.DataSource = null; rlvEvents.DataSource = eventsList; btConnect.Enabled = false; //lbUpdateVAL.Text = "Not available"; //lbUpdateVAL.ForeColor = Color.Blue; } #endregion constructor #region voice Methods private void SendALLcallACK2SD(string _seqID) { string test = "#121#" + GWID + "." + RadioGwId + "#1#"; SendOnMsgBus(_seqID, test); SafeMobileLib.Utils.WriteLine("\n\n########### **************** ALL CALL VOICE :" + voiceMulticastIP4Recv); SafeMobileLib.Utils.WriteLine("########### **************** " + GWID + " | " + RadioGwId + " | \n\n"); PTTbusy = true; //start voice buss for send udp4VoiceRecv = new UdpMulticast(voiceMulticastIP4Recv, ConfigHelper.voicePort); udp4VoiceRecv.OnNewDataRecv += new UdpMulticast.newData4Send(udp4VoiceRecv_OnNewDataRecv); udp4VoiceRecv.StartListen(); } private void SendPrivateCallACK2SD(string _seqID) { string test = "#122#" + GWID + "." + RadioGwId + "#1#"; SendOnMsgBus(_seqID, test); PTTbusy = true; //start voice buss for send udp4VoiceRecv = new UdpMulticast(voiceMulticastIP4Recv, ConfigHelper.voicePort); udp4VoiceRecv.OnNewDataRecv += new UdpMulticast.newData4Send(udp4VoiceRecv_OnNewDataRecv); udp4VoiceRecv.StartListen(); } private void SendGroupCallACK2SD(string _seqID) { string test = "#123#" + GWID + "." + RadioGwId + "#1#"; SendOnMsgBus(_seqID, test); PTTbusy = true; //start voice buss for send udp4VoiceRecv = new UdpMulticast(voiceMulticastIP4Recv, ConfigHelper.voicePort); udp4VoiceRecv.OnNewDataRecv += new UdpMulticast.newData4Send(udp4VoiceRecv_OnNewDataRecv); udp4VoiceRecv.StartListen(); } public void StartnVoice() { try { if (waveOutClass != null) { waveOutClass.Dispose(); waveOutClass = null; } if (waveInClass != null) { waveInClass.DataAvailable -= waveInClass_DataAvailable; waveInClass.Dispose(); waveInClass = null; } //selectedINDevice = selectedOUTDevice = 0; if ((selectedINDevice != -1) && (selectedOUTDevice != -1)) { try { NAudio.Wave.WaveFormat waveFormat = new NAudio.Wave.WaveFormat(8000, 16, 1); // Instantiate waveOut WaveOut waveOutClass = new WaveOut(); waveOutClass.DeviceNumber = selectedOUTDevice; buffWaveProvider = new BufferedWaveProvider(waveFormat); waveOutClass.Init(buffWaveProvider); waveOutClass.Play(); // Instatiate waveIn try { waveInClass = new WaveIn(); waveInClass.DeviceNumber = selectedINDevice; waveInClass.BufferMilliseconds = 32; waveInClass.DataAvailable += waveInClass_DataAvailable; waveInClass.WaveFormat = waveFormat; waveInClass?.StartRecording(); } catch (NAudio.MmException ex) { Console.WriteLine(ex.ToString()); } SafeMobileLib.Utils.WriteLine("Init new WAVE module", ConsoleColor.Magenta); } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("Error to start voice for ALL call" + ex.ToString(), ConsoleColor.Red); } } } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("StartnVoice Exception: " + ex.ToString(), ConsoleColor.Red); SM.Debug("StartnVoice: " + ex.ToString()); } } private void OnCallStartedHandler() { AddEvent($"Incomming {(_callType.Equals("102") ? "private" : "group")} call from radio id {callerID}" + $"{(_callType.Equals("103") ? " on group " + groupID : "")}"); string message = "#125#" + GWID + "." + RadioGwId + "." + callerID.ToString() + "#" + callStatus + "#" + _callType + "#" + groupID + "#"; SendOnMsgBus("0.0", message); PTTbusy = true; isPortable = true; } private void OnCallHangTimeHandler() { if (callerID == null || _callType == null || groupID == null) { SafeMobileLib.Utils.WriteLine("Empty info when receiving CallEnd", ConsoleColor.Yellow); return; } string message = "#125#" + GWID + "." + RadioGwId + "." + callerID.ToString() + "#" + "2" + "#" + _callType + "#" + groupID + "#"; SendOnMsgBus("0.0", message); // TETRA is not available to init a call while in hangtime PTTbusy = false; isPortable = false; AddEvent($"Call from radio id {callerID} {(_callType.Equals("103") ? " on group " + groupID : "")} is in hangtime"); } private void OnCallEndedHandler() { if (callerID == null || _callType == null || groupID == null) { SafeMobileLib.Utils.WriteLine("Empty info when receiving CallEnd", ConsoleColor.Yellow); return; } string message = "#125#" + GWID + "." + RadioGwId + "." + callerID.ToString() + "#" + "3" + "#" + _callType + "#" + groupID + "#"; SendOnMsgBus("0.0", message); AddEvent($"Call from radio id {callerID} {(_callType.Equals("103") ? " on group " + groupID : "")} has ended"); } #endregion #region form methods private void MainForm_Load(object sender, EventArgs e) { ContextMenu contextMenu = new ContextMenu(); contextMenu.MenuItems.Add("Check for updates...", (s, e2) => { UpdateForm uf = new UpdateForm(App.GW_TETRA, true) { IsDevelop = Utils.isDevelop }; uf.Show(); }); contextMenu.MenuItems.Add("Exit", (s, e2) => CloseApp()); notifyIcon1.ContextMenu = contextMenu; // check for a new version if available if (Utils.autoupdate) CheckForUpdate(); // update ui for not connected state OnRegistrationStatusChanged(RegistrationStatus.NotConnected); // register for registration changed event this.OnRegistrationCompleted += OnRegistrationResponseHandler; Register(); stopMessageConsume = false; } private async void Register() { RegistrationResponse regResponse = await RegistrationHelper.RegisterGateway(ConfigHelper.APPLICATION_SERVER_IP, ConfigHelper.regPort); // raise event for registration completed OnRegistrationCompleted?.Invoke(regResponse); } #region REGISTRATION HANDLER private void OnRegistrationResponseHandler(RegistrationResponse regResponse) { this.Invoke((MethodInvoker)delegate () { switch (regResponse.RegistrationStatus) { case RegistrationCode.ServerUnreachable: onRegistrationServerUnreachable(); break; case RegistrationCode.Unauthorized: onRegistraionUnauthorized(); break; case RegistrationCode.Registered: onRegistrationCompleted(regResponse); break; } }); } private void onRegistrationServerUnreachable() { DisplayMessageBox("Application Server is unreachable. Please check internet connection and the application server IP in the configuration file.", "App Server Unreachable", RadMessageIcon.Error); Application.Exit(); } private void onRegistraionUnauthorized() { DisplayMessageBox("Please register this gateway in the admin module.", "Unauthorized gateway", RadMessageIcon.Exclamation); Application.Exit(); } private void DisplayMessageBox(String message, String title, RadMessageIcon boxType) { RadMessageBox.Instance.Dispose(); RadMessageBox.SetThemeName("TelerikMetroBlue"); RadMessageBox.Instance.TopMost = true; RadMessageBox.Instance.TopLevel = true; RadMessageBox.Show(this, "Application Server is unreachable. Please check internet connection and the application server IP in the configuration file.", "App Server Unreachable", MessageBoxButtons.OK, RadMessageIcon.Error); RadMessageBox.Instance.TopMost = false; RadMessageBox.Instance.TopLevel = false; } private void onRegistrationCompleted(RegistrationResponse response) { String currentIP = "127.0.0.1"; // this gateway is on other computer than the application server is if (!ConfigHelper.APPLICATION_SERVER_IP.Equals("127.0.0.1")) currentIP = RegistrationHelper.GatewayIP; // update values for Message bus, database received from AppServer ConfigHelper.DB_IP = response.DataBaseServerIP; ConfigHelper.DB_passwd = response.DataBasePassword; ConfigHelper.DB_port = response.DataBasePort + ""; ConfigHelper.DB_schema = response.DataBaseName; ConfigHelper.DB_user = response.DataBaseUser; ConfigHelper.messageBusIP = response.MessageBusIP; ConfigHelper.messageBusPort = response.MessageBusPort; ConfigHelper.voicePort = response.VoicePort; DBvehiclesManager vehManager = new DBvehiclesManager(ConfigHelper.DB_IP, ConfigHelper.DB_schema, ConfigHelper.DB_user, ConfigHelper.DB_passwd, ConfigHelper.DB_port); DBgatewaysManager gatewayManager = new DBgatewaysManager(ConfigHelper.DB_IP, ConfigHelper.DB_schema, ConfigHelper.DB_user, ConfigHelper.DB_passwd, ConfigHelper.DB_port); // get current gateway currentGateway = getGateway(currentIP, gatewayManager); List radioGws = getRadioGWsFromDB(currentGateway.Id, gatewayManager); // check if any sdr gateway is defined if (radioGws.Count == 0) { onNoRadioGatewayDefined(); return; } else { currentRadioGw = radioGws[0]; GWID = currentRadioGw.Gw_id + ""; RadioGwId = currentRadioGw.Id + ""; // search for radioGws with same identifier as this gateway foreach (RadioGateway rg in radioGws) { if (rg.Name.ToLower().Equals(ConfigHelper.GatewayName.ToLower())) { currentRadioGw = rg; GWID = rg.Gw_id + ""; RadioGwId = rg.Id + ""; break; } } // remove all others gateways from the list // update values for current gateway radioGws.Clear(); radioGws.Add(currentRadioGw); MessageQueue = new InterthreadMessageQueue>(); Task.Factory.StartNew(ConsumeMessage); } FindPortsWorker.RunWorkerAsync(); if (!File.Exists(Utils.configFile)) { SafeMobileLib.Utils.WriteLine("Config file didn't exist. Creating it...", ConsoleColor.Yellow); try { using (FileStream fs = File.Create(Utils.configFile)) { } } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("Application ended!!!! " + Utils.configFile + " could not be created. Exception: " + ex.ToString(), ConsoleColor.Red); Console.WriteLine("Press any key to exit..."); Console.ReadKey(); Environment.Exit(0); } } int configOutDeviceIdx = 0; int nrOfWaveOutDevices = WaveOut.DeviceCount; if (nrOfWaveOutDevices > 0) { OutputSoundList.Enabled = true; rbApplyAudioConfiguration.Enabled = true; for (int i = 0; i < nrOfWaveOutDevices; i++) { WaveOutCapabilities deviceInfo = WaveOut.GetCapabilities(i); OutputSoundList.Items.Add(deviceInfo.ProductName); if (deviceInfo.ProductName.Trim().StartsWith(ConfigHelper.SpeakerDeviceName)) configOutDeviceIdx = i; } } else { OutputSoundList.Items.Add("Please add a device"); OutputSoundList.Enabled = false; rbApplyAudioConfiguration.Enabled = false; } int configInDeviceIdx = 0; int nrOfWaveInDevices = WaveIn.DeviceCount; if (nrOfWaveInDevices > 0) { InputSoundList.Enabled = true; rbApplyAudioConfiguration.Enabled = true; for (int i = 0; i < nrOfWaveInDevices; i++) { WaveInCapabilities deviceInfo = WaveIn.GetCapabilities(i); InputSoundList.Items.Add(deviceInfo.ProductName); if (deviceInfo.ProductName.Trim().StartsWith(ConfigHelper.MicDeviceName)) configInDeviceIdx = i; } } else { InputSoundList.Items.Add("Please add a device"); InputSoundList.Enabled = false; rbApplyAudioConfiguration.Enabled = false; } // restore previous values for sound selectedINDevice = configInDeviceIdx; selectedOUTDevice = configOutDeviceIdx; InputSoundList.SelectedIndex = configInDeviceIdx; OutputSoundList.SelectedIndex = configOutDeviceIdx; StartnVoice(); _gatewayStatusTimer = new System.Threading.Timer(_gatewayStatusTimer_Elapsed, null, 3000, 10000); //INIT UDP try { udpMulticast = new UdpMulticast(ConfigHelper.messageBusIP, ConfigHelper.messageBusPort); SafeMobileLib.Utils.WriteLine($"Starting UDP multicast listener on {ConfigHelper.messageBusIP}:{ConfigHelper.messageBusPort}"); SafeMobileLib.Utils.WriteLine("ADDING LISTENER", ConsoleColor.Cyan); udpMulticast.OnNewDataRecv += udpMulticast_OnNewDataRecv; udpMulticast.StartListen(ConfigHelper.localIP); // start voice bus for send voiceMulticastIP4Send = "224.10." + GWID.ToString() + "." + RadioGwId.ToString(); udp4VoiceSend = new UdpMulticast(voiceMulticastIP4Send, ConfigHelper.voicePort); // start voice bus for receive } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("Location Thread exception while joining the multicast group: " + ex.ToString(), ConsoleColor.Red); } if(ConfigHelper.RestartOnMemoryLeak) _memoryCheckTimer = new System.Threading.Timer(RestartSoft, null, 5000, 5000); } #endregion private void RestartSoft(object state) { try { Process curentProcess = Process.GetCurrentProcess(); Process[] ProcessDispatchList = Process.GetProcessesByName("Tetra_GW"); Process ProcessDispName = null; try { if (ProcessDispatchList.Length > 0) { if (ProcessDispatchList[0] != null) ProcessDispName = ProcessDispatchList[0]; } } catch (Exception ex) { smutils.WriteLine("Error on get proccess by name" + ex.ToString()); } Process ProcessDispatch = Process.GetCurrentProcess(); //ok i will put 650 Mega to include more stuff with hisotry and geofence if (ProcessDispName != null) { //Utils.WriteLine("CurentProcess:" + curentProcess.WorkingSet64 + " ProccessDispName:" + ProcessDispName.WorkingSet64, ConsoleColor.Green); //Utils.WriteLine("rResatr ameem value:" + MainForm2.RestartMEM, ConsoleColor.Green); long currentMemoryMb = curentProcess.WorkingSet64 / 1024 / 1024; if (currentMemoryMb > ConfigHelper.MaxMemoryAllowedMb) { try { smutils.WriteLine("Restart software due to memory: " + currentMemoryMb + " Mb"); Process oldProcess = Process.GetCurrentProcess(); oldProcess.WaitForExit(5000); System.Diagnostics.Process.Start(System.Windows.Forms.Application.ExecutablePath, "-l"); oldProcess.Kill(); System.Windows.Forms.Application.Exit(); } catch (Exception ex) { smutils.WriteLine("Error on restart timer:" + ex.ToString()); } } } } catch (Exception ex) { smutils.WriteLine("Error on restart thread:" + ex.ToString()); } } #region RADIO GATEWAY private Gateway getGateway(String gatewayIP, DBgatewaysManager gatewayManager) { List allGateways = gatewayManager.getAllGateways(); foreach (Gateway g in allGateways) { if (g.Ip == gatewayIP) { SafeMobileLib.Utils.WriteLine("Gateway IP found in registration tabel. ID:" + g.Id, ConsoleColor.Yellow); currentGateway = g; ConfigHelper.GW_ID = g.Id; ConfigHelper.GW_IP = g.Ip; // TODO update thegateway infos in the config file return g; } } return null; } private List getRadioGWsFromDB(Int64 gatewayID, DBgatewaysManager gatewayManager) { List list = gatewayManager.gelAllRadioGateways(gatewayID); List listtoreturn = new List(); foreach (RadioGateway g in list) listtoreturn.Add(g); return listtoreturn; } private void onNoRadioGatewayDefined() { DisplayMessageBox("No Gateway defined in the admin module for this computer. Please contact your administrator.", "No Gateway defined", RadMessageIcon.Exclamation); } #endregion private RegistrationStatus registrationStatus; private void OnRegistrationStatusChanged(RegistrationStatus status) { registrationStatus = status; this.Invoke((MethodInvoker)delegate () { rpConnectionStatus.BackColor = status.Color; rpConnectionStatus.Text = status.ToString(); if (status == RegistrationStatus.Connected) btConnect.Enabled = true; AddEvent("Connection status : " + status); }); } private void AddEvent(String msg) { this.Invoke((MethodInvoker)delegate () { rlvEvents.BeginEdit(); eventsList.Add($"{DateTime.Now:HH:mm:ss} | {msg}"); // remove first item if more thatn 200 if (eventsList.Count > 200) eventsList.RemoveAt(0); rlvEvents.EndEdit(); }); } private void MainForm_Shown(object sender, EventArgs e) { ThemeResolutionService.ApplicationThemeName = "TelerikMetroBlue"; } private void MainForm_Resize(object sender, EventArgs e) { if (this.WindowState == FormWindowState.Minimized) { this.Visible = false; notifyIcon1.Visible = true; } } private void MainForm_FormClosing(object sender, FormClosingEventArgs e) { // disconnect from the radio if (registrationStatus == RegistrationStatus.Connected) btConnect.PerformClick(); _memoryCheckTimer?.Dispose(); _memoryCheckTimer = null; try { keepAlive = false; _shouldStop = true; _isConnected = false; stopMessageConsume = true; if (serialPort.IsOpen) { e.Cancel = true; //cancel the form closing Thread CloseDown = new Thread(new ThreadStart(CloseSerialOnExit)); //close port in new thread to avoid hang CloseDown.Start(); //close port in new thread to avoid hang } } catch (Exception ex) { Console.WriteLine(ex.ToString()); } } private void CloseApp() { MainForm_FormClosing(null, null); Process oldProcess = Process.GetCurrentProcess(); oldProcess.Kill(); Application.Exit(); } private async void btConnect_Click(object sender, EventArgs e) { //btConnect.Enabled = false; //btConnect.Enabled = await RadioConnectAsync(); } private void timer1_Tick(object sender, EventArgs e) { // btConect.PerformClick(); serialPort.BaudRate = BAUD_RATE; serialPort.PortName = radCBPorts.Text; SafeMobileLib.Utils.WriteLine("PortName: " + serialPort.PortName); serialPort.Open(); serialPort.ReadTimeout = 200; serialPort.WriteTimeout = 1; serialPort.DataBits = 8; if (Utils.isTetra) serialPort.Handshake = System.IO.Ports.Handshake.RequestToSend; else serialPort.Handshake = System.IO.Ports.Handshake.XOnXOff; serialPort.Parity = System.IO.Ports.Parity.None; serialPort.StopBits = System.IO.Ports.StopBits.One; SafeMobileLib.Utils.WriteLine("Serial port connection open."); //radCBPorts.Enabled = false; RegisterForSMSandGPS(); timer1.Stop(); timer1.Enabled = false; } private void RestartTimer_Tick(object sender, EventArgs e) { Process oldProcess = Process.GetCurrentProcess(); oldProcess.WaitForExit(5000); Process.Start(Application.ExecutablePath); Application.Exit(); } private void ckAutoconnect_ToggleStateChanged(object sender, StateChangedEventArgs args) { ConfigHelper.GW_Autoconnect = ckAutoconnect.Checked; ConfigHelper.SaveAutoConnect(ckAutoconnect.Checked); } private void radCBPorts_SelectedIndexChanged(object sender, Telerik.WinControls.UI.Data.PositionChangedEventArgs e) { if (radCBPorts.SelectedItem != null) { lbStatusVAL.Text = ""; ConfigHelper.SerialPort = radCBPorts.SelectedItem.Text; ConfigHelper.SaveSerialPort(radCBPorts.SelectedItem.Text); } } private void _gatewayStatusTimer_Elapsed(object obj) { if (serialPort.IsOpen) { //send Gateway On command to MSG bus string seqID = "0.0"; string toSend = "#500#" + GWID + "#" + RadioGwId + "#ON#"; String cmdok = "#" + seqID + toSend; Int32 tmp = cmdok.Length + 1; tmp += tmp.ToString().Length; cmdok = "#" + tmp.ToString() + cmdok; Encoding enc = Encoding.ASCII; byte[] buf = enc.GetBytes(cmdok); //put on multicast bus SafeMobileLib.Utils.WriteLine("keep alive message sent on multicast bus: " + cmdok); udpMulticast.Send(buf, buf.Length); } } private void waveInClass_DataAvailable(object sender, WaveInEventArgs e) { try { //SafeMobileLib.Utils.WriteLine(e.Buffer.ToString() + " " + e.BytesRecorded.ToString()); if (PTTbusy && isPortable && e.BytesRecorded != 0) { SafeMobileLib.Utils.WriteLine($"Sending voice to dispatcher {voiceMulticastIP4Send}", ConsoleColor.Yellow); udp4VoiceSend.Send(e.Buffer, e.BytesRecorded); } } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("waveInClass_DataAvailable Error:" + ex.ToString(), ConsoleColor.Red); } } private void udp4VoiceRecv_OnNewDataRecv(byte[] data, int dataLen) { try { SafeMobileLib.Utils.WriteLine($"Voice form SD on ip {voiceMulticastIP4Recv} -> soundIn: {selectedINDevice}; soundOut: {selectedOUTDevice}) "); buffWaveProvider?.AddSamples(data, 0, dataLen); } catch (InvalidOperationException ex) { // Buffer is full SafeMobileLib.Utils.WriteLine("udp4VoiceRecv_OnNewDataRecv InvalidOperationException: " + ex.ToString(), ConsoleColor.Red); } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("udp4VoiceRecv_OnNewDataRecv Exception: " + ex.ToString(), ConsoleColor.Red); } } private void udpMulticast_OnNewDataRecv(byte[] data, int dataLen) { string[] dataArr = null; try { string str = Encoding.ASCII.GetString(data, 0, dataLen); String[] tempArray = str.Trim().Split("#".ToCharArray()); int gwid_recv = 0; int radio_gwid_recv = 0; //SafeMobileLib.Utils.WriteLine("udpMulticast_OnNewDataRecv: " + str, ConsoleColor.Yellow); if (tempArray.Length > 3) { switch (tempArray[3]) { //init all call request case "101": if (callState == CallState.Idle) { InitPrivateCall("16777215"); voiceMulticastIP4Recv = tempArray[5]; SendALLcallACK2SD(tempArray[2]); } else { //send ack to SD string test = "#115#" + GWID + "." + RadioGwId + "#1#"; SendOnMsgBus(tempArray[2], test); PTTbusy = false; //RadioStatusProp = RADIO_STATUS.FREE; //tCheckPTT = null; } break; //init private call request case "102": if (callState == CallState.Idle && tempArray[4].Split(".".ToCharArray())[2] != null) { InitPrivateCall(tempArray[4].Split(".".ToCharArray())[2]); voiceMulticastIP4Recv = tempArray[5]; SendPrivateCallACK2SD(tempArray[2]); } else { //send ack to SD string test = "#116#" + GWID + "." + RadioGwId + "#1#"; SendOnMsgBus(tempArray[2], test); PTTbusy = false; //RadioStatusProp = RADIO_STATUS.FREE; //tCheckPTT = null; } break; //init group call request case "103": if (callState == CallState.Idle && tempArray[4].Split(".".ToCharArray())[2] != null) { InitGroupCall(tempArray[4].Split(".".ToCharArray())[2]); voiceMulticastIP4Recv = tempArray[5]; SendGroupCallACK2SD(tempArray[2]); } else { //send ack to SD string test = "#117#" + GWID + "." + RadioGwId + "#1#"; SendOnMsgBus(tempArray[2], test); PTTbusy = false; //RadioStatusProp = RADIO_STATUS.FREE; //tCheckPTT = null; } break; //terminate all call request: case "111": if (PTTbusy) { //all call faked with 16777215 id EndPrivateCall(); SafeMobileLib.Utils.WriteLine("UDP4VoiceRecv - Stop Listen " + " PTT BUSY 111"); udp4VoiceRecv.StopListen(); string message = "#115#" + GWID + "." + RadioGwId + "#1#"; SendOnMsgBus(tempArray[2], message); PTTbusy = false; } else { SafeMobileLib.Utils.WriteLine("PTTbussy != true could not process all call stop"); //send 115 failed to SD string message = "#115#" + GWID + "." + RadioGwId + "#2#"; SendOnMsgBus(tempArray[2], message); } break; //terminate private call request case "112": if (PTTbusy) { EndPrivateCall(); SafeMobileLib.Utils.WriteLine("UDP4VoiceRecv - Stop Listen " + " PTT Busy 112"); udp4VoiceRecv.StopListen(); string message = "#115#" + GWID + "." + RadioGwId + "#1#"; SendOnMsgBus(tempArray[2], message); PTTbusy = false; } else { SafeMobileLib.Utils.WriteLine("PTTbussy != true could not process private call stop"); //send 115 failed to SD string message = "#116#" + GWID + "." + RadioGwId + "#2#"; SendOnMsgBus(tempArray[2], message); } break; //terminate group call request case "113": if (PTTbusy == true) { EndGroupCall(); SafeMobileLib.Utils.WriteLine("UDP4VoiceRecv - Stop Listen " + " PTT Busy 113"); udp4VoiceRecv.StopListen(); string message = "#115#" + GWID + "." + RadioGwId + "#1#"; SendOnMsgBus(tempArray[2], message); PTTbusy = false; } else { SafeMobileLib.Utils.WriteLine("PTTbussy != true could not process group call stop"); //send 115 failed to SD string message = "#117#" + GWID + "." + RadioGwId + "#2#"; SendOnMsgBus(tempArray[2], message); break; } break; case "142": case "143": int sched_timeGMT = 0; if (tempArray.Length > 6) sched_timeGMT = Convert.ToInt32(tempArray[6]); dataArr = tempArray[4].Split(".".ToCharArray()); gwid_recv = Convert.ToInt32(dataArr[0]); radio_gwid_recv = Convert.ToInt32(dataArr[1]); if (gwid_recv == currentGateway.Id && radio_gwid_recv == currentRadioGw.Id)//|| gwid_recv == 0) { if (sched_timeGMT <= DateTime.Now.ToUniversalTime().DateTo70Format() + 60) { AddMsgtoQueue(tempArray[2] , dataArr[2], tempArray[5]); } } break; case "154": dataArr = tempArray[4].Split(".".ToCharArray()); gwid_recv = Convert.ToInt32(dataArr[0]); radio_gwid_recv = Convert.ToInt32(dataArr[1]); if (gwid_recv == currentGateway.Id && radio_gwid_recv == currentRadioGw.Id) //|| gwid_recv == 0) { SUID = dataArr[2]; SendPollLIP(dataArr[2]); } break; } } } catch (Exception ex) { SafeMobileLib.Utils.WriteLine(ex.ToString(), ConsoleColor.Red); } } private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e) { this.Visible = true; this.WindowState = FormWindowState.Normal; notifyIcon1.Visible = false; } #endregion form methods #region methods public void SendOnMsgBus(string seqID, string test) { if (udpMulticast != null) { String cmdok = "#" + seqID + test; Int32 tmp = cmdok.Length + 1; tmp += tmp.ToString().Length; cmdok = "#" + tmp.ToString() + cmdok; Encoding enc = Encoding.ASCII; byte[] buf = enc.GetBytes(cmdok); udpMulticast.Send(buf, buf.Length); SafeMobileLib.Utils.WriteLine("TX:" + cmdok); } else { SafeMobileLib.Utils.WriteLine("SendOnMsgBuss Error!!! MessageBusHandler messagebus =null", ConsoleColor.Red); } } static byte sms_seq_id = 1; public void SendSMSToRadio(String SUID, String messageBody) { //SafeMobileLib.Utils.WriteLine("++++++++++Send SMS to SU " + SUID); // send sms try { SendATCommand(CreateSMSATCommand(SUID, messageBody)); SafeMobileLib.Utils.WriteLine("»»» SMS [" + messageBody + "] sent to " + SUID + " [msg id " + sms_seq_id + "]"); AddEvent("»»» SMS [" + messageBody + "] sent to " + SUID + " [msg id " + sms_seq_id + "]"); } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("SendSMSToRadio Exception:" + ex.ToString(), ConsoleColor.Red); } } private String CreateSMSATCommand(String SUID, String messageBody) { string smsTXT = ""; for (int i = 0; i < messageBody.Length; i++) { smsTXT += Byte2Str(messageBody[i]); } string line = "AT+CMGS=" + SUID + ",1,0," + (messageBody.Length + 4) * 8 + SerialKey.CR + "82020101" + smsTXT + SerialKey.CTRLZ; return line; } public void SendATCommand(String command) { serialPort.ReadExisting(); serialPort.Write(command); Thread.Sleep(1000); } private List seqIds = new List(); private void AddMsgtoQueue(String seqId, String suid, String message) { lock (seqIds) { if (seqIds.Contains(seqId)) { // already in queue return; } } // compose AT cmd String atCommand = CreateSMSATCommand(suid, message); lock (seqIds) { seqIds.Add(seqId); } // add command to queue MessageQueue.PostItem(new Tuple(seqId, atCommand)); SafeMobileLib.Utils.WriteLine("Posted msg: " + atCommand); } private void ConsumeMessage() { while (true) { Tuple atCommand = MessageQueue.Peek(100); if (atCommand != null) { atCommand = MessageQueue.GetItem(1); SendATCommand(atCommand.Item2); lock(seqIds) { seqIds.Remove(atCommand.Item1); } string test = "#242#1#"; String cmdok = "#" + atCommand.Item1 + test; Int32 tmp = cmdok.Length + 1; tmp += tmp.ToString().Length; cmdok = "#" + tmp.ToString() + cmdok; Encoding enc = Encoding.ASCII; byte[] buf = enc.GetBytes(cmdok); //send to sd new channel value udpMulticast.Send(buf, buf.Length); Thread.Sleep(2000); } if (stopMessageConsume) break; } } public void SendPollLIP(String SUID) { // send poll try { //serialPort.ReadExisting(); string line = $"AT+CMGS={SUID},1,0,45{SerialKey.CR}{SerialKey.LF}0A44CE3A340E14{SerialKey.CTRLZ}"; SafeMobileLib.Utils.WriteLine("»»» POLL location request for " + SUID); serialPort.Write(line); Thread.Sleep(500); } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("SendPOLLToRadio Exception:" + ex.ToString(), ConsoleColor.Red); } } private async Task RadioConnectAsync() { return await Task.Factory.StartNew(Conn); } private bool Conn() { bool ret = false; if (!serialPort.IsOpen) { try { _shouldStop = false; timer1.Stop(); timer1.Enabled = false; serialPort.BaudRate = BAUD_RATE; serialPort.PortName = radCBPorts.Text; SafeMobileLib.Utils.WriteLine("PortName: " + serialPort.PortName); serialPort.Open(); serialPort.ReadTimeout = 200; serialPort.WriteTimeout = 1; serialPort.DataBits = 8; if (Utils.isTetra) serialPort.Handshake = Handshake.RequestToSend; else serialPort.Handshake = Handshake.XOnXOff; serialPort.Parity = Parity.None; serialPort.StopBits = StopBits.One; SafeMobileLib.Utils.WriteLine("Serial port connection open."); this.Invoke((MethodInvoker)delegate { OnRegistrationStatusChanged(RegistrationStatus.Connecting); lbStatusVAL.Text = "Serial port opened"; lbStatusVAL.ForeColor = Color.Blue; btConnect.Text = "Disconnect"; btConnect.Enabled = true; radCBPorts.Enabled = false; }); RegisterForSMSandGPS(); ThreadPool.QueueUserWorkItem(state => KeepAlive()); ret = true; SetRebootTimer(); } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("Error on connect:" + ex.Message); } } else { _shouldStop = true; _isConnected = false; serialPort.Close(); SafeMobileLib.Utils.WriteLine("Serial port connection closed."); if (registrationStatus != RegistrationStatus.Disconnected) OnRegistrationStatusChanged(RegistrationStatus.Disconnected); this.Invoke((MethodInvoker)delegate { radCBPorts.Enabled = true; lbStatusVAL.Text = "Serial port closed"; lbStatusVAL.ForeColor = Color.Red; btConnect.Text = "Connect"; btConnect.Enabled = true; }); rebootCheck.Close(); } return true; } public static readonly object locker = new object(); public void KeepAlive() { while (true) { if (!_shouldStop) { try { string line = "AT\r\n"; if (serialPort.IsOpen) { serialPort.WriteTimeout = 500; serialPort.Write(line); counter++; } else { SafeMobileLib.Utils.WriteLine("Serial port not opened"); this.Invoke((MethodInvoker)delegate { lbStatusVAL.ForeColor = Color.Red; lbStatusVAL.Text = radioMesageError; btConnect.Text = "Connect"; btConnect.Enabled = true; }); needToRegister = true; keepAlive = false; _shouldStop = true; _isConnected = false; serialPort.Close(); SafeMobileLib.Utils.WriteLine("COM Port not available!", ConsoleColor.Red); } } catch (InvalidOperationException ex) { SafeMobileLib.Utils.WriteLine("serialWrite InvalidOperationException: " + ex.ToString(), ConsoleColor.Red); } catch (ArgumentNullException an) { SafeMobileLib.Utils.WriteLine("serialWrite ArgumentNullException: " + an.ToString(), ConsoleColor.Red); } catch (TimeoutException te) { SafeMobileLib.Utils.WriteLine("serialWrite TimeoutException: " + te.ToString(), ConsoleColor.Red); } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("KeepAlive Exception: " + ex.ToString(), ConsoleColor.Red); this.Invoke((MethodInvoker)delegate { lbStatusVAL.ForeColor = Color.Red; lbStatusVAL.Text = radioMesageError; btConnect.Enabled = true; }); needToRegister = true; keepAlive = false; if (!keepAlive && !_shouldStop) { int count = 0; while (count < 400 && !_shouldStop) { Thread.Sleep(25); count++; } } } if (!_isConnected) counter++; if (counter == 2) { counter = 0; this.Invoke((MethodInvoker)delegate { lbStatusVAL.ForeColor = Color.Red; lbStatusVAL.Text = radioMesageError; btConnect.Enabled = true; }); needToRegister = true; keepAlive = false; if (!keepAlive && !_shouldStop) { int count = 0; while (count < 400 && !_shouldStop) { Thread.Sleep(25); count++; } } } } if (!_shouldStop) { int count = 0; while (count < 400 && !_shouldStop) { Thread.Sleep(25); count++; } } if (_shouldStop) break; } } /// /// /// private void SetRebootTimer() { // Create a timer with a two second interval. rebootCheck = new System.Timers.Timer(2000); // Hook up the Elapsed event for the timer. rebootCheck.Elapsed += RebootCheck_Elapsed; rebootCheck.AutoReset = true; rebootCheck.Enabled = true; } /// /// Checks if no msg was received from the gateway and reboots it after 20 seconds of no information /// /// /// private void RebootCheck_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { msgReceived++; if (msgReceived >= 5) { string line = "AT\r\n"; serialPort.WriteTimeout = 500; serialWrite(line); Thread.Sleep(300); } if (msgReceived == 10) { RebootRadio(); } } private void RegisterForSMSandGPS() { lock (locker) { if (Utils.isTetra) { try { intRegister = 0; SafeMobileLib.Utils.WriteLine("Send AT with 3 seconds time sleep"); string line = "AT\r\n"; serialPort.WriteTimeout = 500; serialWrite(line); Thread.Sleep(300); serialWrite(line); Thread.Sleep(300); serialWrite(line); // get base station ISSI serialWrite($"AT+CNUMF?{SerialKey.CR}"); Thread.Sleep(300); //serialPort.Write("AT+CNUM?\r"); if (!isDMO) { registerTMO(); Thread.Sleep(1000); } else { testDMO(); Thread.Sleep(1000); } registerForLRRP(AREA); Thread.Sleep(1000); registerForLIP(AREA); Thread.Sleep(1000); registerForVoice(); Thread.Sleep(1000); registerForSMS(); Thread.Sleep(1000); //fortare Doru Gheorghiu //ConfirmSMS("101", 0, 0); //serialPort.DiscardOutBuffer(); btConnect.Enabled = true; } catch (Exception ex) { this.Invoke((MethodInvoker)delegate { lbStatusVAL.ForeColor = Color.Red; lbStatusVAL.Text = radioMesageError; btConnect.Enabled = true; }); needToRegister = true; SafeMobileLib.Utils.WriteLine("RegisterForSMSandGPS Exception:" + ex.Message, ConsoleColor.Red); } } else { try { //SM.Debug("Send Enable RS232"); serialPort.WriteTimeout = 2000; string line = ""; SafeMobileLib.Utils.WriteLine("Send Enable RS232"); line = "XOY\r\n"; serialPort.Write(line); Thread.Sleep(299); SafeMobileLib.Utils.WriteLine("Finish registering", ConsoleColor.Green); SafeMobileLib.Utils.WriteLine("The Gateway is in: " + (isDMO ? "DMO" : "TMO"), ConsoleColor.Blue); try { this.Invoke((MethodInvoker)delegate { lbUpdateVAL.Text = DateTime.Now.ToString(); }); } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("Failed to update timestamp in UI Exception: " + ex.Message, ConsoleColor.Red); } } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("RegisterForGPS Exception: " + ex.Message, ConsoleColor.Red); } } } } private void registerTMO() { String line = "AT+CREG=1\r\n"; SafeMobileLib.Utils.WriteLine("Register in TMO with command: " + line, ConsoleColor.Cyan); serialPort.Write(line); } private void testDMO() { String line = $"AT+CTDGR=?{SerialKey.CR}"; SafeMobileLib.Utils.WriteLine("Testing DMO Mode... ", ConsoleColor.Magenta); serialWrite(line); } private void registerForLRRP(int area) { String line = $"AT+CMGS=0,{(int)DestinationType.SSI},{area},8\r\n83{SerialKey.CTRLZ}"; SafeMobileLib.Utils.WriteLine("Register for LRRP GPS with command: " + line, ConsoleColor.Cyan); serialWrite(line); } private void registerForLIP(int area) { String line = $"AT+CMGS=0,{(int)DestinationType.SSI},{area},8\r\n0A{SerialKey.CTRLZ}"; SafeMobileLib.Utils.WriteLine("Register for LIP GPS with command: " + line, ConsoleColor.Cyan); serialWrite(line); } private void registerForVoice() { String line = "AT+CTSP=2,0,0\r\n"; SafeMobileLib.Utils.WriteLine("Register for voice with command: " + line, ConsoleColor.Cyan); serialPort.Write(line); } private void registerForSMS() { String line = $"AT+CMGS=0,1,0,8\r\n82{SerialKey.CTRLZ}"; SafeMobileLib.Utils.WriteLine("Register for SMS with command: " + line, ConsoleColor.Cyan); serialWrite(line); } private void serialWrite(String msg) { SafeMobileLib.Utils.WriteLine("»»» " + msg); try { serialPort.Write(msg); } catch (InvalidOperationException ex) { SafeMobileLib.Utils.WriteLine("serialWrite InvalidOperationException: " + ex.ToString(), ConsoleColor.Red); rebootCheck.Close(); } catch (ArgumentNullException an) { SafeMobileLib.Utils.WriteLine("serialWrite ArgumentNullException: " + an.ToString(), ConsoleColor.Red); rebootCheck.Close(); } catch (TimeoutException te) { SafeMobileLib.Utils.WriteLine("serialWrite TimeoutException: " + te.ToString(), ConsoleColor.Red); if (te.ToString().Contains("The write timed out.")) { SafeMobileLib.Utils.WriteLine("Gateway Is Turned OFF!!!", ConsoleColor.Red); rebootCheck.Close(); } } catch (Exception ex) { } } private void serialWrite(byte[] data, int offset, int count) { SafeMobileLib.Utils.WriteLine("»»» " + msg); try { serialPort.Write(data, offset, count); } catch(InvalidOperationException ex) { SafeMobileLib.Utils.WriteLine("serialWrite InvalidOperationException: " + ex.ToString(), ConsoleColor.Red); } catch(ArgumentNullException an) { SafeMobileLib.Utils.WriteLine("serialWrite ArgumentNullException: " + an.ToString(), ConsoleColor.Red); } catch (TimeoutException te) { SafeMobileLib.Utils.WriteLine("serialWrite TimeoutException: " + te.ToString(), ConsoleColor.Red); if (te.ToString().Contains("The write timed out.")) { SafeMobileLib.Utils.WriteLine("Gateway Is Turned OFF!!!", ConsoleColor.Red); rebootCheck.Close(); } } } //private void DisplayReceivedData(byte[] data, int length) //{ // StringBuilder saux = new StringBuilder(2048); // for (int i = 0; i < length; i++) // { // saux.Append((char)data[i]); // } // SafeMobileLib.Utils.WriteLine(saux.ToString()); //} String msg = ""; next_msg nm; Byte[] dataRead = new Byte[2048]; int startPosition = 0; int restartAfterZeroMessages = 5; int numberOfZeroLengthMessages = 0; private void CheckMessage(object s, EventArgs e) { lock (locker) { if (needToRegister) { needToRegister = false; RegisterForSMSandGPS(); } } counter = 0; this.Invoke((MethodInvoker)delegate { lbStatusVAL.ForeColor = Color.Green; lbStatusVAL.Text = "Communication with radio established"; if (!_isConnected) { OnRegistrationStatusChanged(RegistrationStatus.Connected); } }); _isConnected = true; _shouldStop = false; if (serialPort.IsOpen) { try { int length = serialPort.BytesToRead; serialPort.Read(dataRead, startPosition, length); startPosition += length; bool hasCRLF = length > 1 && dataRead[startPosition - 2] == 13 && dataRead[startPosition - 1] == 10; if (!hasCRLF) { return; } //============================= // display received message //============================= //DisplayReceivedData(dataRead, startPosition); for(int i = 0; i< startPosition; i++) //foreach (Byte b in dataRead) { byte b = dataRead[i]; if ((b != 10) && (b != 13)) { msg += (char)b; } else { if (msg.Length > 0) SafeMobileLib.Utils.WriteLine($"Received message from serial port [{msg.Length} bytes]: " + msg); numberOfZeroLengthMessages = msg.Length == 0 ? (numberOfZeroLengthMessages + 1) : 0; if(numberOfZeroLengthMessages == restartAfterZeroMessages) { numberOfZeroLengthMessages = 0; Conn(); Thread.Sleep(1200); Conn(); return; } try { #region TETRA if (Utils.isTetra) { if (msg.Trim().Equals("OK")) { this.Invoke((MethodInvoker)delegate { lbUpdateVAL.Text = DateTime.Now.ToString(); }); } // parse a location report if (nm.parse && msg.Length > 2) { nm.parse = false; ParseReport(msg, nm); } //notifies if the gateway should re-register to the Mobile Radio if (msg.Contains("+MCCFG")) { Conn(); Thread.Sleep(1000); Conn(); } if (msg.Contains("+CME ERROR")) { SafeMobileLib.Utils.WriteLine("Error : " + ParseCMEError(msg), ConsoleColor.Yellow); if (ParseCMEError(msg) == "40") { isDMO = true; SafeMobileLib.Utils.WriteLine("Radio changed to DMO Mode", ConsoleColor.Red); Conn(); Thread.Sleep(1000); Conn(); } else if (ParseCMEError(msg) == "43") { isDMO = false; SafeMobileLib.Utils.WriteLine("Radio changed to TMO Mode", ConsoleColor.Red); Conn(); Thread.Sleep(1000); Conn(); } else if (ParseCMEError(msg) == "41") { MessageBox.Show("Transmissions are inhibited!!!", "MT is in TXI!!! Disable the TXI and reconnect!", MessageBoxButtons.OK); } } if (msg.Contains("+CNUMF")) { ParseCNUMF(msg); } if (msg.Contains("+CTOM")) { ParseCTOM(msg); } // see if it is a cmt message if (msg.Contains("CMT:")) { nm.parse = true; ParseCMT(msg); } if (msg.Contains("CME") && (msg.Contains("667"))) { System.Threading.Timer tCheckSTATUS = new System.Threading.Timer(ExecuteDisc, null, 500, Timeout.Infinite); } if (msg.Contains("CMGS")) { intRegister++; if (intRegister == 2) { keepAlive = true; SafeMobileLib.Utils.WriteLine("Finish registering", ConsoleColor.Green); SafeMobileLib.Utils.WriteLine("The Gateway is in: " + (isDMO ? "DMO" : "TMO"), ConsoleColor.Blue); try { this.Invoke((MethodInvoker)delegate { lbUpdateVAL.Text = DateTime.Now.ToString(); }); } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("Incoming call notification (init call): " + ex.Message, ConsoleColor.DarkGreen); } } } #region voice stuff // Voice AT from radio // +CTICN -> Incoming call notification (init call) // +CTCC -> call connect notification // +CTXG -> call transmission granted // +CDTXC -> call transmit cease notification // +CTCR -> call release notification (end call) // +CTSDC -> Define Call Parameters if (msg.Contains("CTICN")) { SafeMobileLib.Utils.WriteLine("Incomming call notification (init call)", ConsoleColor.DarkGreen); callerID = msg.Split(",".ToCharArray())[4]; if (!string.IsNullOrEmpty(callerID) && isDMO) callerID = callerID.Remove(0, 8).TrimStart('0'); //remove MCC&MNC infront of CallerID callStatus = "1"; //init call _callType = msg.Split(",".ToCharArray())[8] == "1" ? "103" : "102"; groupID = msg.Split(",".ToCharArray())[11]; if (!string.IsNullOrEmpty(groupID) && isDMO) groupID = groupID.Remove(0, 8).TrimStart('0'); //remove MCC&MNC infront of GroupID //for private call groupID=1 //if (msg.Split(",".ToCharArray())[8] == "4") //{ // //_callType = "101"; // groupID = "1"; //} OnCallStartedHandler(); } if (msg.Contains("CTCC")) { SafeMobileLib.Utils.WriteLine("Call connect notification", ConsoleColor.DarkGreen); } if (msg.Contains("CTXG")) { SafeMobileLib.Utils.WriteLine("Call transmission grant", ConsoleColor.DarkGreen); // parse the call instance //TODO //msg = +CTXG: 1,0,0,0 int idxOfDots = msg.IndexOf(":"); int idxOnFirstComma = msg.IndexOf(","); callInstance = msg.Substring(idxOfDots + 1, idxOnFirstComma - idxOfDots - 1).Trim(); if (callState == CallState.HangTime) OnCallStartedHandler(); callState = CallState.InProgress; } if (msg.Contains("CDTXC")) { SafeMobileLib.Utils.WriteLine("Call transmit cease notification (hang)", ConsoleColor.DarkGreen); callState = CallState.HangTime; OnCallHangTimeHandler(); } if (msg.Contains("CTCR")) { PTTbusy = false; SafeMobileLib.Utils.WriteLine("Call release notification (end call)", ConsoleColor.DarkGreen); callState = CallState.Idle; OnCallEndedHandler(); } #endregion voice stuff } #endregion else { if (msg.Length > 2) { ParseBarret(msg, SUID); } } } catch(Exception ex) { smutils.WriteLine("Exception on parsing serial message: " + ex.ToString()); } msg = ""; } } Array.Clear(dataRead, 0, dataRead.Length); startPosition = 0; } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("error while reading from serial port: " + ex.StackTrace, ConsoleColor.Red); } } } private void ForceTimer(Object state) { System.Threading.Timer tCheckSTATUS = new System.Threading.Timer(ExecuteDisc, null, 300, Timeout.Infinite); SafeMobileLib.Utils.WriteLine("Force Timer"); } private void ExecuteDisc(Object state) { try { // get old process and wait UP TO 5 secs then give up! Process oldProcess = Process.GetCurrentProcess(); oldProcess.WaitForExit(5000); Process.Start(Application.ExecutablePath); Application.Exit(); } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("ExecuteDisc: " + ex.ToString(), ConsoleColor.Red); // the process did not exist - probably already closed! } } private void ExecuteConnect(Object state) { btConnect.PerformClick(); SafeMobileLib.Utils.WriteLine("Force Connect"); } private float ProcessGPSLat(String latitude, String lat_dir) { try { long LAT, LAT2; char LAT3; long llat, grade, zec; char[] param = new char[50]; String[] latList; float flat; param = lat_dir.ToCharArray(); if (param[0] != 'N' && param[0] != 'S') return 0; //Console.WriteLine("Latitude " + latitude + " dir " + lat_dir); latList = latitude.Split('.'); LAT = Convert.ToInt32(latList[0]); if (latList[1].Length > 4) latList[1] = latList[1].Remove(4); LAT2 = Convert.ToInt32(latList[1]); LAT3 = param[0]; // process the lat and lng for display grade = (LAT / 100L); zec = (LAT % 100L) * 1000L + LAT2; // get MMMMM*1000, from MM.mmmmm by MM*1000+mmm (0-59999) zec = (zec * 100L) / 60L; // translate MMMMM*1000 to DD * 100 * 1000 (0-99998) grade = grade * 100000 + zec; // translate all to DDddddd llat = grade; flat = (float)llat / 100000; if (param[0] == 'S') flat = -flat; if (flat < -90 || flat > 90) { SafeMobileLib.Utils.WriteLine($"[warning \"overflow lat\": flat={flat} llat={llat}]"); return 0; } return flat; } catch (Exception ee) { SafeMobileLib.Utils.WriteLine("Error in ProcessGPSLat: " + ee.ToString(), ConsoleColor.Red); return 0; } } private float ProcessGPSLong(String longitude, String lng_dir) { try { long LNG, LNG2; char LNG3; long llng, grade, zec; char[] param = new char[50]; String[] lngList; float flong; param = lng_dir.ToCharArray(); if (param[0] != 'E' && param[0] != 'W') return 0; lngList = longitude.Split('.'); LNG = Convert.ToInt32(lngList[0]); if (lngList[1].Length > 4) lngList[1] = lngList[1].Remove(4); LNG2 = Convert.ToInt32(lngList[1]); LNG3 = param[0]; grade = LNG / 100; // get DD (0-90) zec = (LNG % 100L) * 1000L + LNG2; // get MMMMM*1000, from MM.mmmmm by MM*1000+mmm (0-59999) zec = (zec * 100L) / 60L; // translate MMMMM*1000 to DD * 100 * 1000 (0-99998) grade = grade * 100000 + zec; // translate all to DDddddd llng = grade; flong = (float)llng / 100000; if (param[0] == 'W') flong = -flong; if (flong < -180 || flong > 180) { SafeMobileLib.Utils.WriteLine($"[warning \"overflow lng\": flng={flong} llng={llng}]"); return 0; } return flong; } catch (Exception ee) { SafeMobileLib.Utils.WriteLine("Error in ProcessGPSLong: " + ee.ToString(), ConsoleColor.Red); return 0; } } private void ParseBarret(String msg, String suid) { try { htCell_t ht = new htCell_t(); ht.suid = suid; String latstr = ""; String directLAT = "N"; String lngstr = ""; String directLNG = "E"; SafeMobileLib.Utils.WriteLine("Message is:X" + msg + "X"); if (msg.Length > 20) { latstr = msg.Substring(1, 9); directLAT = msg[10].ToString(); lngstr = msg.Substring(12, 9); directLNG = msg[21].ToString(); } ht.lat = ProcessGPSLat(latstr, directLAT).ToString();//lat.ToString(); ht.lng = ProcessGPSLong(lngstr, directLNG).ToString(); ht.spd = "0"; ht.location_time = DateTime.UtcNow; InsertXML(ht); } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("Error on parse location on barret: " + ex.ToString(), ConsoleColor.Red); } } /// /// Parse the CME Error message received on a serial connection /// /// Message containing the CME Error flag, it containg the error code /// private String ParseCMEError(String msg) { String[] split = msg.Split(new char[] { ':' }); if (split.Length > 0) { Int16 code = 0; Int16.TryParse(split[1].Trim(), out code); return ((CMEError)code).ToString(); } return msg; } /// /// Parse a CNUMF message received on serial connection /// /// Message containing the TETRA Identities (ITSI, PABX, PSTN, Store & Forward Service centre addresses) void ParseCNUMF(string msg) { String[] splited = msg.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); if (splited.Length >= 1) { try { String issi = splited[1].Substring(splited[1].Length - 16, 16); ISSI = Int64.Parse(issi); SafeMobileLib.Utils.WriteLine($"Radio ISSI is {ISSI}", ConsoleColor.Magenta); } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("Exception ParseCNUMF: " + msg.ToString()); } } } /// /// Detects Mobil Radio Operating Mode (0 - TMO/1 - DMO/5-DM-Gateway/6-DM-Repeater /// /// private void ParseCTOM(string msg) { if (msg.Contains("1") && !isDMO) { isDMO = true; SafeMobileLib.Utils.WriteLine("Radio changed to DMO Mode", ConsoleColor.Red); AddEvent("Radio changed to DMO Mode"); Conn(); Thread.Sleep(1000); Conn(); } else if (msg.Contains("0") && isDMO) { isDMO = false; SafeMobileLib.Utils.WriteLine("Radio changed to TMO Mode", ConsoleColor.Red); AddEvent("Radio changed to TMO Mode"); Conn(); Thread.Sleep(1000); Conn(); } else if (msg.Contains("5") || msg.Contains("6")) { isDMO = false; SafeMobileLib.Utils.WriteLine("Radio changed to an unkown Mode", ConsoleColor.Red); Conn(); } else SafeMobileLib.Utils.WriteLine("Operating mode is: " + (isDMO ? "DMO" : "TMO"), ConsoleColor.Blue); } /// /// Receiving Status, Alarm, SDS type 1, 2, 3 and 4 messages (also covers SDS-TL and UDH). /// /// private void ParseCMT(string msg) { char[] separators = { ' ', ',' }; string[] vals = msg.Split(separators); nm.src_SUID = int.Parse(vals[1]); nm.msg_len = int.Parse(vals[3]); nm.parse = true; nm.suid_type = int.Parse(vals[2]); nm.data_type = DataType.SDS_TYPE_4; try { if(vals.Length >= 5) nm.data_type = (DataType)Enum.Parse(typeof(DataType), vals[4]); } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("ParseCMT error: " + ex.ToString(), ConsoleColor.Red); } if (nm.suid_type == 1 && nm.data_type == DataType.STATUS_MESSAGE) { EmergencyAlarm(nm.src_SUID + ""); } } /// /// Parse the message that comes after the flag /// /// Current parsing message that can be seen as a payload /// Message that contains this payload. Has informations regarding the subscriber that sent this message private void ParseReport(string msg, next_msg nm) { // ellipse-3d (lat, long, angle, semi-major, semi-minor, altitude, altitude-acc?) if ((msg.Length / 2) == (nm.msg_len / 8)) { string suid = nm.src_SUID.ToString(); int i = 0; byte b = GetNextByte(msg, ref i); int pi = (int)b; if (pi == (int)ProtocolIdentifier.GPSUsingSDSTL)// (byte)0x83: ParseLocation(msg, suid); else if (pi == (int)ProtocolIdentifier.SimpleTextUsingSDSTL) ParseSMS(msg, suid, nm.msg_len / 8 - 4); else if (pi == (int)ProtocolIdentifier.GPS) parseLIPLocation(msg, suid); else { ParseLocation(msg, suid); SafeMobileLib.Utils.WriteLine("Warning: This is not a location protocol 0x83, ignore"); } } else { // LIP messages are having the lengths in bits so the first verification will always fail int i = 0; byte b = GetNextByte(msg, ref i); if ((int)b == (int)ProtocolIdentifier.GPS) parseLIPLocation(msg, nm.src_SUID.ToString()); else SafeMobileLib.Utils.WriteLine("ParseReport: length does not match " + msg.Length + "/2 vs " + nm.msg_len + "/8"); } } private void SU_ChangeState(string name, bool state) { UpdateSUStatus(name, state); } public void UpdateSUStatus(string suid, bool status) { Byte[] receivedBytes = { 0x00, 0x00, 0x31 }; if (status) receivedBytes[2] = 0x30; Byte[] toSendMulticast = Utils.CreateMulticastMessage(130, suid, receivedBytes); udpMulticast.Send(toSendMulticast, toSendMulticast.Length); SafeMobileLib.Utils.WriteLine("ARS thread successfully sent data to message bus"); string seqID = "0.0"; //build string string fullSource = ""; try { fullSource = currentGateway.Id.ToString() + "#" + currentRadioGw.Ip.ToString() + "#" + suid; } catch (Exception ex) { fullSource = currentGateway.Id.ToString() + "#192.168.10.60#" + suid; SafeMobileLib.Utils.WriteLine("Error on parse IP: " + ex.ToString(), ConsoleColor.Red); } string test = "#139#" + fullSource + "#"; String cmdok = "#" + seqID + test; Int32 tmp = cmdok.Length + 1; tmp += tmp.ToString().Length; cmdok = "#" + tmp.ToString() + cmdok; Encoding enc = Encoding.ASCII; byte[] buf = enc.GetBytes(cmdok); //send to messagebus SafeMobileLib.Utils.WriteLine("Sending to MessageBus: " + cmdok); udpMulticast.Send(buf, buf.Length); try { this.Invoke((MethodInvoker)delegate { lbUpdateVAL.Text = DateTime.Now.ToString(); }); } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("Failed to update timestamp in UI: " + ex.ToString(), ConsoleColor.Red); } Thread.Sleep(100); } private void ParseLocation(String message, String suid) { htCell_t ht = new htCell_t(); ht.suid = suid; //ht.spd = "0"; bool parsed_req_id = false, parsed_elipse = false, parsed_time = false, parse_spd = false, parse_periodic = false, parse_circle = false; int i = 12; if ((htSU[suid] != null) && (!((htCell_t)htSU[suid]).state)) { ((htCell_t)htSU[suid]).state = true; SU_ChangeState(suid, true); } else if (htSU[suid] == null) { ht.state = true; htSU.Add(suid, ht); SU_ChangeState(suid, true); } while (i < msg.Length) { byte b = GetNextByte(msg, ref i); if (b == (byte)Report_Messages_Tokens_ENUM.request_id && !parsed_req_id) { b = GetNextByte(msg, ref i); DisplayReqId(b, suid); parsed_req_id = true; if (b == (byte)Request_Identifier.Periodic_report) parse_periodic = true; // ARS ON OFF and emerg Boolean getoutfast = false; if (b == (byte)Request_Identifier.SU_is_powered_ON) { if (htSU[suid] != null) ((htCell_t)htSU[suid]).state = true; else { ht.state = true; htSU.Add(suid, ht); } SU_ChangeState(suid, true); getoutfast = true; AddEvent("ARS ON from radio " + suid); } else if (b == (byte)Request_Identifier.SU_is_powered_OFF) { if (htSU[suid] != null) ((htCell_t)htSU[suid]).state = false; SU_ChangeState(suid, false); getoutfast = true; AddEvent("ARS OFF from radio " + suid); } else if (b == (byte)Request_Identifier.Emergency_condition_detected) { EmergencyAlarm(ht.suid); getoutfast = true; AddEvent("Emergency from radio " + suid); } if (getoutfast) { //Write_htSU(suid, ht); return; } continue; } //BACK TO GPS STATE if ((b == (byte)Report_Messages_Tokens_ENUM.info_time || b == (byte)Report_Messages_Tokens_ENUM.info_time1 ) && !parsed_time ) { SafeMobileLib.Utils.WriteLine(Report_Messages_Tokens_ENUM.info_time + " (" + b.ToString("X") + ")"); Byte[] time = new byte[5]; time[0] = GetNextByte(msg, ref i); time[1] = GetNextByte(msg, ref i); time[2] = GetNextByte(msg, ref i); time[3] = GetNextByte(msg, ref i); time[4] = GetNextByte(msg, ref i); try { ht.location_time = ProcessTime(time, 0, 5); } catch(Exception ex) { smutils.WriteLine("Exception on processing time for location: " + ex.ToString(), ConsoleColor.Yellow); ht.location_time = DateTime.UtcNow; } parsed_time = true; continue; } if((b== (byte)Report_Messages_Tokens_ENUM.circle_2d || b == (byte)Report_Messages_Tokens_ENUM.circle_2d1 || b== (byte)Report_Messages_Tokens_ENUM.circle_3d || b == (byte)Report_Messages_Tokens_ENUM.circle_3d1 || b == (byte)Report_Messages_Tokens_ENUM.circle_3d2 || b == (byte) Report_Messages_Tokens_ENUM.circle_3d3 || b == (byte) Report_Messages_Tokens_ENUM.circle_3d4) && !parse_circle) { SafeMobileLib.Utils.WriteLine("Circle (" + b.ToString("X") + "):"); Byte[] data = new byte[4]; data[0] = GetNextByte(msg, ref i); data[1] = GetNextByte(msg, ref i); data[2] = GetNextByte(msg, ref i); data[3] = GetNextByte(msg, ref i); double lat = ProcessLat(data, 0, 4); ht.lat = lat.ToString(); lastLat = lat.ToString(); data[0] = GetNextByte(msg, ref i); data[1] = GetNextByte(msg, ref i); data[2] = GetNextByte(msg, ref i); data[3] = GetNextByte(msg, ref i); double lng = ProcessLng(data, 0, 4); ht.lng = lng.ToString(); lastLng = lng.ToString(); SafeMobileLib.Utils.WriteLine("\tLat = " + lat); SafeMobileLib.Utils.WriteLine("\tLng = " + lng); parse_circle = true; continue; } if ((b == (byte)Report_Messages_Tokens_ENUM.ellipse_2d || b == (byte)Report_Messages_Tokens_ENUM.ellipse_2d1 || b == (byte)Report_Messages_Tokens_ENUM.ellipse_3d || b == (byte)Report_Messages_Tokens_ENUM.ellipse_3d1 || b == (byte)Report_Messages_Tokens_ENUM.ellipse_3d2 || b == (byte)Report_Messages_Tokens_ENUM.ellipse_3d3 || b == (byte)Report_Messages_Tokens_ENUM.point_2d ) && !parsed_elipse ) { SafeMobileLib.Utils.WriteLine("Ellipse (" + b.ToString("X") + "):"); Byte[] data = new byte[4]; data[0] = GetNextByte(msg, ref i); data[1] = GetNextByte(msg, ref i); data[2] = GetNextByte(msg, ref i); data[3] = GetNextByte(msg, ref i); double lat = ProcessLat(data, 0, 4); ht.lat = lat.ToString(); lastLat = lat.ToString(); data[0] = GetNextByte(msg, ref i); data[1] = GetNextByte(msg, ref i); data[2] = GetNextByte(msg, ref i); data[3] = GetNextByte(msg, ref i); double lng = ProcessLng(data, 0, 4); ht.lng = lng.ToString(); lastLng = lng.ToString(); SafeMobileLib.Utils.WriteLine("\tLat = " + lat); SafeMobileLib.Utils.WriteLine("\tLng = " + lng); parsed_elipse = true; continue; } if (b == (byte)Report_Messages_Tokens_ENUM.speed_hor_int && !parse_spd) { Console.Write(Report_Messages_Tokens_ENUM.speed_hor_int + "(" + b.ToString("X") + "): "); int aux = (int)GetNextByte(msg, ref i); aux &= 0xff; int spd = 0; while ((aux & 0x80) != 0) { spd |= (aux ^ 0x80); spd <<= 7; aux = GetNextByte(msg, ref i); aux &= 0xff; } spd |= aux; spd = (int)(spd * 3.6); SafeMobileLib.Utils.WriteLine("speed :" + spd); ht.spd = spd.ToString(); parse_spd = true; continue; } } if (parsed_time && parsed_elipse) InsertXML(ht); else if (parse_periodic) { ht.lat = "0"; ht.lng = "0"; ht.spd = "0"; ht.location_time = DateTime.UtcNow; InsertXML(ht); } else if (parse_circle) InsertXML(ht); } private static byte reqID_lastByte = 0; private static UdpClient udpClient; private static string sendTriggeredLocationReq(int report_time) { reqID_lastByte++; if (reqID_lastByte > 0xfe) reqID_lastByte = 0x00; reqID_lastByte = 0x05; Byte[] sendBytes = { (byte)Document_Identifiers_ENUM.Triggered_Location_Request_NoCDT, 0x0B, // length in Bytes (byte)Common_Element_Tokens_ENUM.request_id, //0x04, 0x24, 0x68, 0xAC, 0xE0, 0x04, 0x24, 0x68, 0xAC, reqID_lastByte, 0x51, (byte)Query_Request_Messages_Tokens_ENUM.request_speed_hor, (byte)Query_Request_Messages_Tokens_ENUM.periodic_trigger, (byte)Query_Request_Messages_Tokens_ENUM.interval, 0x00, 0x00 //(byte)report_time// in seconds }; try { if (report_time < 0x80) { //sendBytes[10] = (byte)report_time; sendBytes[12] = (byte)report_time; } else { sendBytes[1] += 1; // adjust length int process = report_time; // MSB process >>= 7; process &= 0x007F; process |= 0x0080; sendBytes[12] = (byte)process; sendBytes[13] = (byte)(report_time & 0x007F); //LSB } return sendBytes.ToString(); } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("Location Thread SendTriggeredLocationRequest exception: " + ex.ToString(), ConsoleType.GPS); return null; } } public void TriggerLocationRequest() { // send poll try { //serialPort.ReadExisting(); string line = $"AT+CMGS=102,1,0,{sendTriggeredLocationReq(60).Length + 8}{SerialKey.CR}{SerialKey.LF}82{sendTriggeredLocationReq(60)}{SerialKey.CTRLZ}"; SafeMobileLib.Utils.WriteLine("»»» POLL location request for " + SUID); serialPort.Write(line); Thread.Sleep(500); } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("SendPOLLToRadio Exception:" + ex.ToString(), ConsoleColor.Red); } } /// /// Parse a LIP location received over the serial connection /// /// Location message that was received /// Subscriber id from which the location was received private void parseLIPLocation(String message, String suid) { htCell_t ht = new htCell_t(); ht.suid = suid; //if ((htSU[suid] != null) && (!((htCell_t)htSU[suid]).state)) //{ // ((htCell_t)htSU[suid]).state = true; // SU_ChangeState(suid, true); //} //else if (htSU[suid] == null) //{ // ht.state = true; // htSU.Add(suid, ht); // SU_ChangeState(suid, true); //} SafeMobileLib.Utils.WriteLine("LIP Location"); var result = lipDecoder.DecodeLipDataMessage(message); #region LONG LOCATION if (lipDecoder.pduType == PDUType.LONG_LOCATION) { //SafeMobileLib.Utils.WriteLine("LIP LONG_LOCATION", ConsoleColor.Magenta); #region LONG_LOCATION_REPORT if (lipDecoder.pduTypeExtension == PDUTypeExtension.LONG_LOCATION_REPORT) { SafeMobileLib.Utils.WriteLine("LIP LONG_LOCATION_REPORT", ConsoleColor.Green); //LAT latitude if (lipDecoder.latitude != "") ht.lat = lipDecoder.latitude; //LNG if (lipDecoder.longitude != "") ht.lng = lipDecoder.longitude; if (lipDecoder.timePositionHour == null || lipDecoder.timePositionHour == "") { lipDecoder.timePositionHour = DateTime.UtcNow.Hour.ToString(); } if (lipDecoder.timePositionMinute == null || lipDecoder.timePositionMinute == "") { lipDecoder.timePositionMinute = DateTime.UtcNow.Minute.ToString(); } if (lipDecoder.timePositionSecond == null || lipDecoder.timePositionSecond == "") { lipDecoder.timePositionSecond = DateTime.UtcNow.Second.ToString(); } //time DateTime time = new DateTime((int)DateTime.UtcNow.Year, (int)DateTime.UtcNow.Month, (int)DateTime.UtcNow.Day, (int)Convert.ToInt32(lipDecoder.timePositionHour), (int)Convert.ToInt32(lipDecoder.timePositionMinute), (int)Convert.ToInt32(lipDecoder.timePositionSecond)); if (time != null) ht.location_time = time; ; //speed speed double spd = 0; //SafeMobileLib.Utils.WriteLine("Horizontal speed : " + lipDecoder.horizontalVelocity, ConsoleColor.DarkCyan); if (lipDecoder.horizontalVelocity.Contains("Horizontal speed is unknown")) { // Console.WriteLine("Horizontal speed is unknown"); lipDecoder.horizontalVelocity = "0"; } if (lipDecoder.horizontalVelocity.Contains("km/h")) { lipDecoder.horizontalVelocity = lipDecoder.horizontalVelocity.Replace("km/h", ""); //Console.WriteLine("After replace km/h: " + lip.horizontalVelocity); } if (!double.TryParse(lipDecoder.horizontalVelocity, out spd)) { //Console.WriteLine("!ulong.TryParse(lip.horizontalVelocity, out spd) " + lip.horizontalVelocity); lipDecoder.horizontalVelocity = "0"; } spd = double.Parse(lipDecoder.horizontalVelocity); try { spd = (ulong)Math.Round((double)spd); } catch (Exception ex) { Console.WriteLine("ERROR rounding speed:" + ex.Message); } try { ht.spd = spd + ""; } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("Exceptie pe aici : " + ex.ToString()); }; Boolean isGPSErrorValid = true; ht.poll = lipDecoder.reasonForSendingBinaryValue.Length > 1 && Convert.ToInt32(lipDecoder.reasonForSendingBinaryValue, 2) == 32; if (lipDecoder.reasonForSendingBinaryValue== "00000000") //ARS ON { if (htSU[suid] != null) ((htCell_t)htSU[suid]).state = true; else { ht.state = true; htSU.Add(suid, ht); } SU_ChangeState(suid, true); AddEvent("ARS ON from radio " + suid); if (ConfigHelper.ReportType.ToUpper() == "SHORT") { string line = $"AT+CMGS={suid},1,0,45{SerialKey.CR}{SerialKey.LF}0A59E6840C08{SerialKey.CTRLZ}"; SafeMobileLib.Utils.WriteLine($"Change Report Type to SHORT for Radio {suid}... ", ConsoleColor.Magenta); serialWrite(line); Thread.Sleep(1000); } else if (ConfigHelper.ReportType.ToUpper() == "LONG") { string line = $"AT+CMGS={suid},1,0,45{SerialKey.CR}{SerialKey.LF}0A59A6840C08{SerialKey.CTRLZ}"; SafeMobileLib.Utils.WriteLine($"Change Report Type to LONG for Radio { suid}... ", ConsoleColor.Magenta); serialWrite(line); Thread.Sleep(1000); } } else if (lipDecoder.reasonForSendingBinaryValue == "00000001") //ARS OFF { if (htSU[suid] != null) ((htCell_t)htSU[suid]).state = false; SU_ChangeState(suid, false); AddEvent("ARS OFF from radio " + suid); } else SendPositionOnMessageBus(ht); } #endregion #region BASIC_LOCATION_PARAM_REQ_REP else if (lipDecoder.pduTypeExtension == PDUTypeExtension.BASIC_LOCATION_PARAM_REQ_REP) { SafeMobileLib.Utils.WriteLine("LIP BASIC_LOCATION_PARAM_REQ_REP", ConsoleColor.Green); } #endregion #region LONG_LOCATION_ACK else if (lipDecoder.pduTypeExtension == PDUTypeExtension.LONG_LOCATION_ACK) { SafeMobileLib.Utils.WriteLine("LIP LONG_LOCATION_ACK", ConsoleColor.Green); } #endregion #region ENABLE/DISABLE RESPONSE else if (lipDecoder.pduTypeExtension == PDUTypeExtension.LOCATION_REPORTING_ENABLE_DISABLE) { SafeMobileLib.Utils.WriteLine("LIP LOCATION_REPORTING_ENABLE_DISABLE", ConsoleColor.Green); } #endregion #region Add MODIFY TRIGGER RESPONSE else if (lipDecoder.pduTypeExtension == PDUTypeExtension.ADD_MODIFY_TRIGGER_REQ_REP) { if(lipDecoder.resultCodeBinaryValue == "00011000") SafeMobileLib.Utils.WriteLine($"The request to change LIP GPS TYPE to: {lipDecoder.reportingType} was {lipDecoder.resultCode}", ConsoleColor.Green); else SafeMobileLib.Utils.WriteLine($"The request to change LIP GPS TYPE to: {lipDecoder.reportingType} was {lipDecoder.resultCode}", ConsoleColor.Red); } #endregion #region REMOVE TRIGGER RESPONSE else if (lipDecoder.pduTypeExtension == PDUTypeExtension.REMOVE_TRIGGER_REQ_REP) { RemoveTriggerResponse rtr = result as RemoveTriggerResponse; SafeMobileLib.Utils.WriteLine("LIP REMOVE_TRIGGER_REQ_REP with result: " + rtr.ResultCode, ConsoleColor.Green); } #endregion SafeMobileLib.Utils.WriteLine("Reason for sending GPS: " + lipDecoder.reasonForSending, ConsoleColor.DarkCyan); } #endregion #region SHORT LOCATION else if (lipDecoder.pduType == PDUType.SHORT_LOCATION) { SafeMobileLib.Utils.WriteLine("LIP SHORT_LOCATION"); ht.lat = lipDecoder.latitude ?? "0"; ht.lng = lipDecoder.longitude ?? "0"; ht.spd = "0"; ht.location_time = DateTime.UtcNow; if (lipDecoder.reasonForSendingBinaryValue == "00000000") //ARS ON { if (htSU[suid] != null) ((htCell_t)htSU[suid]).state = true; else { ht.state = true; htSU.Add(suid, ht); } SU_ChangeState(suid, true); AddEvent("ARS ON from radio " + suid); if (ConfigHelper.ReportType.ToUpper() == "SHORT") { string line = $"AT+CMGS={suid},1,0,45{SerialKey.CR}{SerialKey.LF}0A59E6840C08{SerialKey.CTRLZ}"; SafeMobileLib.Utils.WriteLine($"Change Report Type to SHORT for Radio {suid}... ", ConsoleColor.Magenta); serialWrite(line); Thread.Sleep(1000); } else if (ConfigHelper.ReportType.ToUpper() == "LONG") { string line = $"AT+CMGS={suid},1,0,45{SerialKey.CR}{SerialKey.LF}0A59A6840C08{SerialKey.CTRLZ}"; SafeMobileLib.Utils.WriteLine($"Change Report Type to LONG for Radio {suid}... ", ConsoleColor.Magenta); serialWrite(line); Thread.Sleep(1000); } } else if (lipDecoder.reasonForSendingBinaryValue == "00000001") //ARS OFF { if (htSU[suid] != null) ((htCell_t)htSU[suid]).state = false; SU_ChangeState(suid, false); AddEvent("ARS OFF from radio " + suid); } else if (lipDecoder.reasonForSending == "DMO ON") { } else SendPositionOnMessageBus(ht); SafeMobileLib.Utils.WriteLine("Reason for sending GPS: " + lipDecoder.reasonForSending, ConsoleColor.DarkCyan); } #endregion } public void SendPositionOnMessageBus(htCell_t cell) { if (cell.spd == null) cell.spd = "0"; try { String[] toSendString = new String[4]; toSendString[0] = DateTo70Format(cell.location_time).ToString(); toSendString[1] = cell.spd.ToString(); toSendString[2] = cell.lat.ToString(); toSendString[3] = cell.lng.ToString(); SafeMobileLib.Utils.WriteLine(String.Format("»»» " + (cell.poll ? "Poll resp" : "Position") + " [{0:0.0000},{1:0.0000}] from {2} [{3} kmh]", Math.Round(Double.Parse(cell.lat), 4), Math.Round(Double.Parse(cell.lng), 4), cell.suid, cell.spd)); AddEvent(String.Format("»»» " + (cell.poll ? "Poll resp" : "Position") + " [{0:0.0000},{1:0.0000}] from {2} [{3} kmh]", Math.Round(Double.Parse(cell.lat), 4), Math.Round(Double.Parse(cell.lng), 4), cell.suid, cell.spd)); Byte[] toSendMulticast = Utils.CreateLocationMessage(cell.poll ? (int)MessageBusCmds.PollResponseReceived : (int)MessageBusCmds.LocationReceived, cell.suid, toSendString); udpMulticast.Send(toSendMulticast, toSendMulticast.Length); //SafeMobileLib.Utils.WriteLine("Send #131 location data: " + xml); try { this.Invoke((MethodInvoker)delegate { lbUpdateVAL.Text = DateTime.Now.ToString(); }); } catch { SafeMobileLib.Utils.WriteLine("Failed to update timestamp in UI", ConsoleColor.Red); } } catch (Exception e) { SafeMobileLib.Utils.WriteLine("error on send #131 location data \n" + e.ToString(), ConsoleColor.Red); } } private void DisplayReqId(byte b, string suid) { switch (b) { case (byte)Request_Identifier.SU_is_powered_ON: SafeMobileLib.Utils.WriteLine($"Unit {suid} sent ARS ON", ConsoleColor.Blue); break; case (byte)Request_Identifier.SU_is_powered_OFF: SafeMobileLib.Utils.WriteLine($"Unit {suid} sent ARS OFF", ConsoleColor.Blue); break; case (byte)Request_Identifier.Emergency_condition_detected: SafeMobileLib.Utils.WriteLine($"Unit {suid} is in Emergency", ConsoleColor.DarkBlue); break; case (byte)Request_Identifier.PTT_condition_detected: SafeMobileLib.Utils.WriteLine(Request_Identifier.PTT_condition_detected.ToString(), ConsoleColor.Green); break; case (byte)Request_Identifier.Status: SafeMobileLib.Utils.WriteLine(Request_Identifier.Status.ToString(), ConsoleColor.Green); break; case (byte)Request_Identifier.Transmit_Inhibit_Mode_ON: SafeMobileLib.Utils.WriteLine(Request_Identifier.Transmit_Inhibit_Mode_ON.ToString(), ConsoleColor.Green); break; case (byte)Request_Identifier.Transmit_Inhibit_Mode_OFF: SafeMobileLib.Utils.WriteLine(Request_Identifier.Transmit_Inhibit_Mode_OFF.ToString(), ConsoleColor.Green); break; case (byte)Request_Identifier.System_access: SafeMobileLib.Utils.WriteLine(Request_Identifier.System_access.ToString(), ConsoleColor.Green); break; case (byte)Request_Identifier.DMO_ON: SafeMobileLib.Utils.WriteLine(Request_Identifier.DMO_ON.ToString(), ConsoleColor.Green); break; case (byte)Request_Identifier.Enter_service: SafeMobileLib.Utils.WriteLine(Request_Identifier.Enter_service.ToString(), ConsoleColor.Green); break; case (byte)Request_Identifier.Leave_service: SafeMobileLib.Utils.WriteLine(Request_Identifier.Leave_service.ToString(), ConsoleColor.Green); break; case (byte)Request_Identifier.Cell_reselection: SafeMobileLib.Utils.WriteLine(Request_Identifier.Cell_reselection.ToString(), ConsoleColor.Green); break; case (byte)Request_Identifier.Low_battery: SafeMobileLib.Utils.WriteLine(Request_Identifier.Low_battery.ToString(), ConsoleColor.Green); break; case (byte)Request_Identifier.SU_connected_Digital_Car_Kit: SafeMobileLib.Utils.WriteLine(Request_Identifier.SU_connected_Digital_Car_Kit.ToString(), ConsoleColor.Green); break; case (byte)Request_Identifier.SU_disconnected_Digital_Car_Kit: SafeMobileLib.Utils.WriteLine(Request_Identifier.SU_disconnected_Digital_Car_Kit.ToString(), ConsoleColor.Green); break; case (byte)Request_Identifier.Loss_of_coverage: SafeMobileLib.Utils.WriteLine(Request_Identifier.Loss_of_coverage.ToString(), ConsoleColor.Green); break; case (byte)Request_Identifier.Recovery_of_coverage: SafeMobileLib.Utils.WriteLine(Request_Identifier.Recovery_of_coverage.ToString(), ConsoleColor.Green); break; case (byte)Request_Identifier.SU_movement_by_amount: SafeMobileLib.Utils.WriteLine(Request_Identifier.SU_movement_by_amount.ToString(), ConsoleColor.Green); break; case (byte)Request_Identifier.Predefined_text_message: SafeMobileLib.Utils.WriteLine(Request_Identifier.Predefined_text_message.ToString(), ConsoleColor.Green); break; case (byte)Request_Identifier.Periodic_report: SafeMobileLib.Utils.WriteLine($"Unit {suid} sent periodic Location Report", ConsoleColor.Blue); break; default: SafeMobileLib.Utils.WriteLine("Unknown Request: 0x" + b.ToString("X"), ConsoleColor.DarkRed); break; } } private void EmergencyAlarm(String suid) { SafeMobileLib.Utils.WriteLine("Emergency alarm received, inserting into db"); try { SafeMobileLib.Utils.WriteLine("Received emergency from radio id: " + suid); AddEvent("Received emergency from radio id: " + suid); string seqID = "0.0"; string toSend = "#138#" + suid + "#"; String cmdok = "#" + seqID + toSend; Int32 tmp = cmdok.Length + 1; tmp += tmp.ToString().Length; cmdok = "#" + tmp.ToString() + cmdok; Encoding enc = Encoding.ASCII; byte[] buf = enc.GetBytes(cmdok); //put on multicast bus SafeMobileLib.Utils.WriteLine("Emergency alarm sent on multicast bus: " + cmdok); udpMulticast.Send(buf, buf.Length); try { this.Invoke((MethodInvoker)delegate { lbUpdateVAL.Text = DateTime.Now.ToString(); }); } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("Failed to update timestamp in UI: " + ex.ToString(), ConsoleColor.Red); } if (htSU[suid] != null) { // ((htCell_t)htSU[suid]).activity_time = DateTime.Now; //((htCell_t)htSU[suid]).changeState(true); } } catch (Exception e) { SafeMobileLib.Utils.WriteLine("emergencyAlarm Exception: " + e.ToString(), ConsoleColor.Red); } //} } public void SendSMSOnMessageBus(Int64 radioID, string message) { string msg = "#" + (int)MessageBusCmds.SMSReceived + "#" + radioID + "#" + message + "#hyt#"; SendOnMsgBus(msg); SU_ChangeState(radioID + "", true); } /// /// Send a string on the message bus. The string will be converted into a byte array before /// beeing sent /// /// The message which needs to be sent on the message bus public void SendOnMsgBus(string commandMsg) { String seqID = "1." + (Utils.GetSecondsLocalFromDT(DateTime.Now)) + DateTime.Now.Millisecond.ToString(); byte[] buf = smutils.Convert_text_For_multicast("#" + seqID + commandMsg); SendOnMessageBus(buf, buf.Length); } /// /// Send a byte array of a specific length on the message bus /// /// Data which needs to be sent on the message bus /// Data which needs to be sent on the message bus private void SendOnMessageBus(byte[] message, int length) { if (udpMulticast != null) { udpMulticast.Send(message, length); SafeMobileLib.Utils.WriteLine(String.Format("+++ MB [{0}] ", ConvertBytesToString(message)), ConsoleColor.White); } else { SM.Debug("••• Could not send on MB, it is null"); } } private void ConfirmSMS(string suid, byte hb, byte lb) { int i; try { serialPort.DiscardOutBuffer(); SafeMobileLib.Utils.WriteLine("Confirming SMS"); string line = "AT+CMGS=" + suid + ",1,0,32"; serialPort.Write(line); // AT+CMGS=suid,1,0,len (len of buf+header in bits) SafeMobileLib.Utils.WriteLine(line); byte[] buf = { 13, (byte)'8', (byte)'2', (byte)'1', (byte)'0', (byte)'0', (byte)'0', (byte)'0', (byte)'0'}; // dummy fill (2B) for msg id buf[7] = hb; buf[8] = lb; serialPort.Write(buf, 0, 9); // 82 10 00 id buf[0] = 26; serialPort.Write(buf, 0, 1); // string saux = ""; for (i = 1; i < 9; i++) { char c = (char)buf[i]; saux += c; if (i % 2 == 0) saux += " "; } SafeMobileLib.Utils.WriteLine(saux + "\r\nEND"); } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("ConfirmSMS Exception:" + ex.Message, ConsoleColor.Red); } } public void InsertXML(htCell_t cell) { String xml = ""; // this is the xml message that will be uploaded into the DB xml = "id=\"100001\" mode=\"GPRS\" Hw_Type=\"NAVL\" subscriber=\"" + cell.suid; xml += "\" time=\"" + DateTo70Format(cell.location_time).ToString() + "\" latitude=\"" + cell.lat + "\" longitude=\"" + cell.lng; xml += "\" speed=\"" + cell.spd + "\" dgr=\"" + "0"; xml += "\" ai1=\"" + "0" + "\" ai2=\"" + "0"; xml += "\" ai3=\"" + "0" + "\" ai4=\"" + "0"; xml += "\" ai5=\"" + "0" + "\" ai6=\"" + "0"; xml += "\" ai7=\"" + "0" + "\" ai8=\"" + "0"; xml += "\" di=\"" + "0" + "\" do=\"" + "0" + "\""; if (xml.Length > 0) { xml = ""; } if (cell.spd == null) cell.spd = "0"; try { String[] toSendString = new String[4]; toSendString[0] = DateTo70Format(cell.location_time).ToString(); toSendString[1] = cell.spd.ToString(); toSendString[2] = cell.lat.ToString(); toSendString[3] = cell.lng.ToString(); String eventConsole = ""; SafeMobileLib.Utils.WriteLine(eventConsole = String.Format("»»» Position [{0:0.0000},{1:0.0000}] from {2} [{3} kmh]", Math.Round(Double.Parse(cell.lat), 4), Math.Round(Double.Parse(cell.lng), 4), cell.suid, cell.spd)); AddEvent(eventConsole); Byte[] toSendMulticast = Utils.CreateLocationMessage(131, cell.suid, toSendString); udpMulticast.Send(toSendMulticast, toSendMulticast.Length); //SafeMobileLib.Utils.WriteLine("Send #131 location data: " + xml); try { this.Invoke((MethodInvoker)delegate { lbUpdateVAL.Text = DateTime.Now.ToString(); }); } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("Failed to update timestamp in UI: " + ex.Message, ConsoleColor.Red); } } catch (Exception e) { SafeMobileLib.Utils.WriteLine("error on send #131 location data \n" + e.ToString(), ConsoleColor.Red); } } private void RestartApp() { try { Process oldProcess = Process.GetCurrentProcess(); oldProcess.WaitForExit(5000); System.Diagnostics.Process.Start(Application.ExecutablePath, "-c"); Application.Exit(); } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("Error on restart thread:" + ex.ToString(), ConsoleColor.Red); } } private void CloseSerialOnExit() { try { serialPort.Close(); //close the serial port } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("CloseSerialOnExit error: " + ex.Message, ConsoleColor.Red); //MessageBox.Show(ex.Message); //catch any serial port closing error messages } this.Invoke((MethodInvoker)delegate () { NowClose(this, new EventArgs()); }); //this.Invoke(new EventHandler(NowClose)); //now close back in the main thread } private void NowClose(object sender, EventArgs e) { this.Close(); //now close the form } #endregion methods #region voice commands to serial port private void InitPrivateCall(string imei) { string line = null; hasPresenceCheck = ConfigHelper.HasPresenceCheck; SafeMobileLib.Utils.WriteLine("Set call parameters"); if(isDMO && !hasPresenceCheck) line = "AT+CTSDC=0,0,0,1,1,0,4,1,0,0,0\r\n"; else if (isDMO && hasPresenceCheck) line = "AT+CTSDC=0,0,0,1,1,0,0,1,0,0\r\n"; else if(!isDMO) line = "AT+CTSDC=0,0,0,0,0,0,0,1,0,0\r\n"; serialPort.WriteTimeout = 500; serialPort.Write(line); Thread.Sleep(299); SafeMobileLib.Utils.WriteLine($"call unit {imei}"); //line = $"ATD{imei}\r\n"; line = $"ATD{imei}\r\n"; serialPort.WriteTimeout = 500; serialPort.Write(line); Thread.Sleep(299); } private void EndPrivateCall() { SafeMobileLib.Utils.WriteLine("Set end call parameters"); string line = "ATH\r\n"; serialPort.WriteTimeout = 500; serialPort.Write(line); Thread.Sleep(299); } private void InitGroupCall(string grp) { SafeMobileLib.Utils.WriteLine("Set call parameters"); string line = "AT+CTSDC=0,0,0,1,1,0,1,1,0,0\r\n"; serialPort.WriteTimeout = 500; serialPort.Write(line); Thread.Sleep(299); SafeMobileLib.Utils.WriteLine($"call group {grp}"); line = $"ATD{grp}\r\n"; serialPort.WriteTimeout = 500; serialPort.Write(line); Thread.Sleep(299); } private void EndGroupCall() { string line = $"AT+CUTXC={callInstance}\r\n"; SafeMobileLib.Utils.WriteLine("Set end call parameters: " + line, ConsoleColor.Cyan); serialPort.WriteTimeout = 500; serialPort.Write(line); Thread.Sleep(299); } #endregion voice commands to serial port #region utils private static string Byte2Str(char c) { char[] Byte2Char = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; byte b = (byte)c; byte hb = b; hb >>= 4; hb &= 0x0f; char hc = Byte2Char[hb]; byte lb = b; lb &= 0x0f; char lc = Byte2Char[lb]; string ret = hc.ToString() + lc.ToString(); return ret; } private DateTime ProcessTime(Byte[] data, int startIndex, int len) { // (yyyy*2^26) + (MM*2^22) + (DD*2^17) + (hh*2^12) + (mm*2^6) + ss Byte B1 = data[startIndex]; Byte B2 = data[startIndex + 1]; Byte B3 = data[startIndex + 2]; Byte B4 = data[startIndex + 3]; Byte B5 = data[startIndex + 4]; int hh, mm, ss, YY, MM, DD; ss = B5 & 0x3F; // remove first 2b mm = B4 & 0x0F; mm <<= 2; mm |= ((B5 >> 6) & 0x03); hh = B3 & 0x01; hh <<= 4; hh |= ((B4 & 0xf0) >> 4); DD = B3 & 0x3E; DD >>= 1; MM = B2 & 0x03; MM <<= 2; MM |= ((B3 >> 6) & 0x03); YY = B1; YY <<= 6; YY |= ((B2 >> 2) & 0x3F); SafeMobileLib.Utils.WriteLine("\tGPSTime : " + YY + "/" + MM + "/" + DD + " " + hh + ":" + mm + ":" + ss); return new DateTime(YY, MM, DD, hh, mm, ss, DateTimeKind.Utc); } private double ProcessLat(Byte[] data, int startIndex, int len) { bool sign = false; if ((data[0] & 0x80) != 0) { sign = true; } ulong l = (ulong)data[startIndex]; if (sign) l ^= 0x80; // remove the sign l <<= 8; l |= (ulong)data[startIndex + 1]; l <<= 8; l |= (ulong)data[startIndex + 2]; l <<= 8; l |= (ulong)data[startIndex + 3]; //Console.WriteLine("lat ulong=0x" + l.ToString("X")); double ld = (double)l; ld *= 90; ld /= 1024; ld /= 1024; ld /= 1024; ld /= 2; if (sign) ld *= -1; return ld; } private double ProcessLng(Byte[] data, int startIndex, int len) { bool sign = false; if ((data[startIndex] & 0x80) != 0) { sign = true; } ulong l = (ulong)data[startIndex]; if (sign) l ^= 0x80; // remove the sign l <<= 8; l |= (ulong)data[startIndex + 1]; l <<= 8; l |= (ulong)data[startIndex + 2]; l <<= 8; l |= (ulong)data[startIndex + 3]; //Console.WriteLine("lng ulong=0x" + l.ToString("X")); double ld = (double)l; ld *= 360; ld /= 1024; ld /= 1024; ld /= 1024; ld /= 4; if (sign) { ld = 180 - ld; ld *= -1; } return ld; } private void ParseSMS(string msg, string suid, int len) { //SafeMobileLib.Utils.WriteLine("SMS len=" + len); int i = 2; byte type = GetNextByte(msg, ref i); //SafeMobileLib.Utils.WriteLine("Type:" + type); switch (type) { case 0x06: case 0x04:// this is a SMS message i = 8; Byte[] receivedBytes = new Byte[len + 4]; receivedBytes[0] = (Byte)((len + 2) / 256); receivedBytes[1] = (Byte)((len + 2) % 256); receivedBytes[2] = 0x00; receivedBytes[3] = 0x00; Char[] cs = new Char[150]; for (int k = 0; k < len; k++) { byte b = GetNextByte(msg, ref i); cs[k] = (char)b; receivedBytes[k + 4] = b; } string s = new string(cs, 0, len); //string key = suid + " | " + DateTime.Now; SafeMobileLib.Utils.WriteLine("The SMS is [" + s + "]"); // confirm sms ConfirmSMS(suid, (byte)msg[4], (byte)msg[5]); if (htSU[suid] != null) { //((htCell_t)htSU[suid]).activity_time = DateTime.Now; //((htCell_t)htSU[suid]).changeState(true); } String sms = s; // remove first 24 characters if is fug if (s.Length > 24 && Utils.isFug) sms = s.Substring(24).Trim(); AddEvent($"Text message [{sms}] received from radio {suid}"); // send message on message bus SendSMSOnMessageBus(Int64.Parse(suid), sms); try { this.Invoke((MethodInvoker)delegate { lbUpdateVAL.Text = DateTime.Now.ToString(); }); } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("Failed to update timestamp in UI" + ex.ToString(), ConsoleColor.Red); } break; case 0x10: // this is a sms confirmation byte ack = GetNextByte(msg, ref i); if (ack == 0) { byte id = GetNextByte(msg, ref i); SafeMobileLib.Utils.WriteLine("Received confirmation for message with ID = " + id); AddEvent($"Received text message ack form message with id {id}"); } else { SafeMobileLib.Utils.WriteLine("No acknowledge received for sent message."); AddEvent($"No acknowledge received for sent message"); } if (htSU[suid] != null) { //((htCell_t)htSU[suid]).activity_time = DateTime.Now; //((htCell_t)htSU[suid]).changeState(true); } break; default: SafeMobileLib.Utils.WriteLine("Error: ParseSMS: Unknown message type"); break; } } public static string ConvertBytesToString(Byte[] receivedBytes) { string response = ""; for (int i = 0; i < receivedBytes.Length; i++) { response = $"{response}{(char)receivedBytes[i]}"; } return response; } /// /// takes 2chars from the string, and returns creates a byte from them /// (hex to byte) /// /// /// /// private byte GetNextByte(string msg, ref int i) { if (i >= msg.Length) return 0; byte high_nibble = bVal(msg[i]); byte low_nibble = bVal(msg[i + 1]); byte ret = high_nibble; ret <<= 4; ret |= low_nibble; i += 2; return ret; } /// /// char -> byte value /// /// /// private byte bVal(char c) { byte ret; if (c >= '0' && c <= '9') { ret = (byte)(c - '0'); } else { ret = (byte)(c - 'A'); ret += 10; } return ret; } private uint DateTo70Format(DateTime time) { long nOfSeconds; DateTime dt70 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); TimeSpan span = time - dt70; nOfSeconds = (long)span.TotalSeconds; return ((uint)nOfSeconds); } #endregion utils #region worker private void FindPortsWorker_DoWork(object sender, DoWorkEventArgs e) { Utils.GetAvailableSerialPorts(ref portHT); ports = Utils.GetOpenPorts(); } private void FindPortsWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { RadListDataItem[] radCBItems = new RadListDataItem[ports.Length]; for (int i = 0; i < ports.Length; i++) { String portName = ports[i]; RadListDataItem item = new RadListDataItem(); // item.Name = portName; item.Text = portName; radCBItems[i] = item; } if (SerialPort.GetPortNames().Length > 0) { radCBPorts.Items.AddRange(radCBItems); int s = 0; foreach (RadListDataItem li in radCBPorts.Items) { if (portHT.Contains(li.Text)) radCBPorts.SelectedIndex = s; s++; } if (ConfigHelper.SerialPort != null) { if (portHT.Contains(ConfigHelper.SerialPort)) { radCBPorts.Text = ConfigHelper.SerialPort; } } btConnect.Enabled = true; } else { lbStatusVAL.Text = "No COM port found"; } if (ConfigHelper.SerialPort != null) { if (portHT.Contains(ConfigHelper.SerialPort)) { ckAutoconnect.Checked = ConfigHelper.GW_Autoconnect; if (ConfigHelper.GW_Autoconnect) { btConnect.PerformClick(); } } else { SafeMobileLib.Utils.WriteLine(String.Format("Port: {0} not available", ConfigHelper.SerialPort)); } } } private void rbApplyAudioConfiguration_Click(object sender, EventArgs e) { selectedOUTDevice = OutputSoundList.SelectedIndex; selectedINDevice = InputSoundList.SelectedIndex; StartnVoice(); ConfigHelper.SaveSpeakerDevice(OutputSoundList.SelectedItem.Text); ConfigHelper.SaveMicDevice(InputSoundList.SelectedItem.Text); } private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) { SafeMobileLib.Utils.WriteLine("serialPort_DataReceived " + msgReceived, ConsoleColor.Green); msgReceived = 0; //this.Invoke(new EventHandler(CheckMessage)); CheckMessage(null, null); } private void serialPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e) { SafeMobileLib.Utils.WriteLine("serialPort_ErrorReceived: " + e.ToString(), ConsoleColor.Red); } #endregion worker #region update /// /// Check for new version release on SafeMobile Portal /// The check is done by comparing Current Assembly Version with the one /// written in a xml file on the portal. /// private void CheckForUpdate() { App appType = App.GW_TETRA; AutoUpdate au = new AutoUpdate(appType) { IsDevelop = Utils.isDevelop }; au.OnNewVersionAvailable += delegate (string version) { notifyIcon1.Text = "New version available"; notifyIcon1.ShowBalloonTip(2500, $"{App.GetAppName(appType)} version {version} available", $"Press to download and install the latest version of {App.GetAppName(appType)}.", ToolTipIcon.Info); notifyIcon1.BalloonTipClicked += delegate (object sender, EventArgs e) { if (notifyIcon1.Text.Equals("New version available")) { UpdateForm uf = new UpdateForm(appType, true) { IsDevelop = Utils.isDevelop }; uf.Show(); } }; }; // call method to check for new updated au.CheckUpdate(); } #endregion update #region AT Commands //MCC & MNC parse needed //$"AT+MCTGDR=1,{SerialKey.CR}"; //Reboot - GW needs to re-register //$"ATR{SerialKey.CR}"; //Boud Rate Set/Read/Test //$"AT+IRP={SerialKey.CR}"; //$"AT+IPR?{SerialKey.CR}"; //$"AT+IPR=?{SerialKey.CR}"; //Radio Volume //$"AT+CLVL?{SerialKey.CR}"; //$"AT+CLVL=6{SerialKey.CR}"; //Change reporting to LIP LONG: $"AT+CMGS=102,1,0,45{SerialKey.CR}{SerialKey.LF}0A59A6840C08{SerialKey.CTRLZ}"; //Change reporting to LIP Short: $"AT+CMGS=102,1,0,45{SerialKey.CR}{SerialKey.LF}0A59E6840C08{SerialKey.CTRLZ}"; private void radButton1_Click(object sender, EventArgs e) { String line = $"AT+CTSDC=?\r\n"; SafeMobileLib.Utils.WriteLine("Test CTSDC: " + line, ConsoleColor.Cyan); serialWrite(line); Thread.Sleep(1000); line = $"AT+CTSDC?\r\n"; SafeMobileLib.Utils.WriteLine("Read CTSDC: " + line, ConsoleColor.Cyan); serialWrite(line); Thread.Sleep(1000); } private void rebootRadio_Click(object sender, EventArgs e) { //Test(); RebootRadio(); } private void tmoDMO_Click(object sender, EventArgs e) { String line = $"AT+CTOM?{SerialKey.CR}"; SafeMobileLib.Utils.WriteLine("Radio Mode: " + line, ConsoleColor.Magenta); serialWrite(line); Thread.Sleep(1000); } private void RebootRadio() { String line = $"ATR{SerialKey.CR}"; SafeMobileLib.Utils.WriteLine("Rebooting Gateway Radio...", ConsoleColor.Magenta); serialWrite(line); Thread.Sleep(1000); needToRegister = true; } #endregion #region Testing methods public void Test() { string line = $"AT+IRP=9600{SerialKey.CR}"; serialWrite(line); Thread.Sleep(1000); } #endregion #region EVENTS public delegate void RegistrationCompleted(RegistrationResponse response); public event RegistrationCompleted OnRegistrationCompleted; #endregion } }