SafeDispatch/GatewayTetraVoice/MainForm.cs
2024-02-22 18:43:59 +02:00

3654 lines
114 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<Tuple<string, string>> 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<String> eventsList = new BindingList<String>();
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<RadioGateway> 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<Tuple<string,string>>();
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<Gateway> 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<RadioGateway> getRadioGWsFromDB(Int64 gatewayID, DBgatewaysManager gatewayManager)
{
List<RadioGateway> list = gatewayManager.gelAllRadioGateways(gatewayID);
List<RadioGateway> listtoreturn = new List<RadioGateway>();
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<String> seqIds = new List<string>();
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<string, string>(seqId, atCommand));
SafeMobileLib.Utils.WriteLine("Posted msg: " + atCommand);
}
private void ConsumeMessage()
{
while (true)
{
Tuple<string, string> 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<bool> RadioConnectAsync()
{
return await Task.Factory.StartNew<bool>(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;
}
}
/// <summary>
///
/// </summary>
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;
}
/// <summary>
/// Checks if no msg was received from the gateway and reboots it after 20 seconds of no information
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
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);
}
}
/// <summary>
/// Parse the CME Error message received on a serial connection
/// </summary>
/// <param name="msg">Message containing the CME Error flag, it containg the error code</param>
/// <returns></returns>
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;
}
/// <summary>
/// Parse a CNUMF message received on serial connection
/// </summary>
/// <param name="msg">Message containing the TETRA Identities (ITSI, PABX, PSTN, Store & Forward Service centre addresses)</param>
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());
}
}
}
/// <summary>
/// Detects Mobil Radio Operating Mode (0 - TMO/1 - DMO/5-DM-Gateway/6-DM-Repeater
/// </summary>
/// <param name="msg"></param>
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);
}
/// <summary>
/// Receiving Status, Alarm, SDS type 1, 2, 3 and 4 messages (also covers SDS-TL and UDH).
/// </summary>
/// <param name="msg"></param>
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 + "");
}
}
/// <summary>
/// Parse the message that comes after the <CR> flag
/// </summary>
/// <param name="msg">Current parsing message that can be seen as a payload</param>
/// <param name="nm">Message that contains this payload. Has informations regarding the subscriber that sent this message</param>
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);
}
}
/// <summary>
/// Parse a LIP location received over the serial connection
/// </summary>
/// <param name="message">Location message that was received</param>
/// <param name="suid">Subscriber id from which the location was received</param>
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);
}
/// <summary>
/// Send a string on the message bus. The string will be converted into a byte array before
/// beeing sent
/// </summary>
/// <param name="commandMsg">The message which needs to be sent on the message bus</param>
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);
}
/// <summary>
/// Send a byte array of a specific length on the message bus
/// </summary>
/// <param name="data">Data which needs to be sent on the message bus</param>
/// <param name="length">Data which needs to be sent on the message bus</param>
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); // <cr> 82 10 00 id <ctrl+z>
buf[0] = 26;
serialPort.Write(buf, 0, 1); // <ctrl+z>
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 = "<rsp " + xml + "></rsp>";
}
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;
}
/// <summary>
/// takes 2chars from the string, and returns creates a byte from them
/// (hex to byte)
/// </summary>
/// <param name="msg"></param>
/// <param name="i"></param>
/// <returns></returns>
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;
}
/// <summary>
/// char -> byte value
/// </summary>
/// <param name="c"></param>
/// <returns></returns>
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
/// <summary>
/// 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.
/// </summary>
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=<baud rate>{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
}
}