SafeDispatch/GatewayTetraVoice/MainForm.cs

3654 lines
114 KiB
C#
Raw Normal View History

2024-02-22 16:43:59 +00:00
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
}
}