3654 lines
114 KiB
C#
3654 lines
114 KiB
C#
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
|
||
}
|
||
}
|