SafeDispatch/MotoTrbo_GW/RadioComHandler.cs

1380 lines
59 KiB
C#

using System;
using SafeMobileLib;
using MotoTRBO_XNL_Cmd;
using MotoTRBO_GW;
using System.ComponentModel;
using System.Threading;
using NAudio.Wave;
namespace MotoTrbo_GW
{
public class RadioComHandler : INotifyPropertyChanged
{
private bool connected = false;
private RADIO_STATUS RadioStatus;
public RADIO_STATUS RadioStatusProp
{
get { return RadioStatus; }
set
{
RadioStatus = value;
RadioStatusChanged("RadioStatusProp");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private int radioID, radioIMEI,radioNetworkID;
private string radioIP;
private int INdevId, OUTdevID;
private UdpMulticast udp4VoiceSend;
private UdpMulticast udp4VoiceRecv;
private RadioConnection radioCon;
private System.Threading.Timer tCheckPTT;
private System.Threading.Timer tCheckSTATUS;
bool speakersOn = false;
bool PTTbussy = false;
private int voice_port = 17234;
#region LINX
#if LINXB
public int CallType
{
get { return callType; }
set { callType = value; }
}
/// <summary>
/// Returns true if the base station is in PTT, else returns false
/// </summary>
public bool IsPTTbussy
{
get { return PTTbussy; }
}
/// <summary>
/// Returns the radio id of the attached mobile radio
/// </summary>
public int RadioID
{
get { return radioID; }
}
private LINX.LinxCall _linxCallInfo;
/// <summary>
/// Gets or sets information about linx call
/// </summary>
public LINX.LinxCall LinxCallInfo {
get { return _linxCallInfo; }
set {
_linxCallInfo = value;
}
}
public bool GroupCallInitiatedByRadio { get; set; }
private const int MS_TO_WAIT_FOR_LINX_CALL_SETUP = 3000;
private System.Timers.Timer _timerPrivatePTTToLinx = null;
#endif
#endregion
bool monitorRequest = false;
int monitorID = 0;
private int CALLER_ID = 0;
private int CALL_TYPE = 0;
private int callType=0;
private string callSeqID="0.0";
private string voiceMulticastIP4Send;
private string voiceMulticastIP4Recv;
private int sw_zone_nr=0, sw_channel_nr=0;
private static int id = 0;
private int id_local = 0;
private Thread listenThread;
public BufferedWaveProvider buffWaveProvider = null;
// voice settings region
private AudioManager _audioManager = null;
public int OutDevIDProperty { get { return OUTdevID; } }
public int InDevIDProperty { get { return INdevId; } }
//
protected void RadioStatusChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
PropertyChangedEventArgs e =new PropertyChangedEventArgs(name);
handler(this, e);
}
}
/// <summary>
/// HAndles messageBus->GW com & GW->radio com
/// </summary>
/// <param name="radioID"></param>
/// <param name="radioIP"></param>
/// <param name="messageBusIP"></param>
/// <param name="messageBusPort"></param>
/// <param name="INdevID"></param>
/// <param name="OUTdevID"></param>
public RadioComHandler(RadioConnection rc,int radioID,
string radioIP,int radioNetworkID, int radioIMEI,
int INdevID, int OUTdevID)
{
id++;
id_local = id;
SafeMobileLib.Utils.WriteLine(id_local + "Constructor for radioConHandler with ID:" + radioID);
RadioStatusProp = RADIO_STATUS.OFF;
this.radioIP = radioIP;
this.radioNetworkID = radioNetworkID;
this.radioIMEI = radioIMEI;
this.radioID = radioID;
this.INdevId = INdevID; this.OUTdevID = OUTdevID;
//start radio com
//radioCon = new RadioConnection(radioIP, 8002, user4radioCon);
radioCon = rc;
//radioCon.OnAuthDone2 += new RadioConnection.AuthDoneDEl2(radioCon_OnAuthDone);
radioCon.OnChannelEvent += new RadioConnection.ChannelEvent(radioCon_OnChannelEvent);
radioCon.OnCallEvent += new RadioConnection.CallEvent(radioCon_OnCallEvent);
radioCon.OnSpeakersEvent += new RadioConnection.SpeakersEvent(radioCon_OnSpeakersEvent);
radioCon.OnRemoteControlEvent += new RadioConnection.RemoteControlEvent(radioCon_OnRemoteControlEvent);
radioCon.OnTransmitEvent += new RadioConnection.TransmitEvent(radioCon_OnTransmitEvent);
radioCon.OnRestartEvent += new RadioConnection.RestartEvent(radioCon_OnRestartEvent);
//start voice bus for send
voiceMulticastIP4Send = "224.10." + Main.GWID.ToString() + "." + radioID.ToString();
udp4VoiceSend = new UdpMulticast(voiceMulticastIP4Send, voice_port);
RadioStatusProp = RADIO_STATUS.FREE;
listenThread = new Thread(new ThreadStart(Listen2MessageBus));
listenThread.IsBackground = true;
listenThread.Start();
#region LINX
#if LINXB
_timerPrivatePTTToLinx = new System.Timers.Timer(MS_TO_WAIT_FOR_LINX_CALL_SETUP);
_timerPrivatePTTToLinx.Elapsed += _timerLinx_Elapsed;
_timerPrivatePTTToLinx.AutoReset = false;
#endif
#endregion
}
private void Listen2MessageBus()
{
//SafeMobileLib.Utils.WriteLine("UDP multicast listen thread started!!!"+mcastGroup);
while (true)
{
try
{
if (MessageBusHandler.MBMessageQueues_Hash.ContainsKey(radioID))
{
MessageBusMessage msg = ((InterthreadMessageQueue<MessageBusMessage>)
MessageBusHandler.MBMessageQueues_Hash[radioID]).GetItem(100);
if (msg!=null)
BusMessageParser(msg);
}
Thread.Sleep(100);
}
catch (ThreadAbortException)
{
break;
}
catch (Exception ex)
{
SafeMobileLib.Utils.WriteLine("RadioComHandler.cs->Listen2MessageBus" + ex.ToString());
Thread.Sleep(10);
}
}
}
private void BusMessageParser(MessageBusMessage msg)
{
SafeMobileLib.Utils.WriteLine("Got " + msg.OPcode, ConsoleColor.Red);
if ((RadioStatus != RADIO_STATUS.FREE)
&& (msg.OPcode != 111)//all call stop
&& (msg.OPcode != 112)//private call stop
&& (msg.OPcode != 113)//group call stop
&& (msg.OPcode != 160)//Dkey
&& (RadioStatus != RADIO_STATUS.HangTime))
{
SendRadioBussy(msg.SeqID, RadioStatus);
return;
}
switch (msg.OPcode)
{
case 104:
SafeMobileLib.Utils.WriteLine("RadioComHandler ID:"+radioID+" processing zone and channel change request");
channelQuerry_seqID = msg.SeqID;
RadioStatusProp = RADIO_STATUS.ChannelQuery;
StartCheckStatusTimer();
//send channel change request to radio
radioCon.SendChannelChange(msg.ZoneNr, msg.ChannelNr);
break;
case 94:
SafeMobileLib.Utils.WriteLine("RadioComHandler ID:" + radioID + "processing SOFTWARE zone and channel change request ");
channelQuerry_seqID = msg.SeqID;
SafeMobileLib.Utils.WriteLine("SOFTWARE channel broadcast sending it to message bus(opcode-124)");
//build string
string test = "#124#" + Main.GWID + "." + radioID + "#" + sw_zone_nr.ToString() + "." + sw_channel_nr.ToString() + "#";
if (channelQuerry_seqID.Length > 2) MessageBusHandler.SendOnMsgBuss(channelQuerry_seqID, test);
else MessageBusHandler.SendOnMsgBuss("0.0", test);//Broadcast
break;
case 101:
SafeMobileLib.Utils.WriteLine($"RadioComHandler - processing all call request radioID = {radioID} ");
//setting status to all call ini and starting timer
RadioStatusProp = RADIO_STATUS.ALLcall_INIT;
StartCheckStatusTimer();
if (PTTbussy)
{
SafeMobileLib.Utils.WriteLine("PTTbussy=" + PTTbussy + " speakersOn=" + speakersOn);
test = "#121#" + Main.GWID + "." + radioID + "#2#";
MessageBusHandler.SendOnMsgBuss(msg.SeqID, test, $"It is busy. cannot process all call request radioID = {radioID}");
break;
}
radioCon.SendCallType(2, 0);
bool ret = radioCon.SendPTTon();
if (ret)
{
voiceMulticastIP4Recv = msg.VoiceMulticastIP4Send;
callType = 101;
callSeqID = msg.SeqID;
#if LINXB
// Reset Linx call info to default value just in case
ResetLinxCallInfoValue();
#endif
}
else
{
test = "#121#" + Main.GWID + "." + radioID + "#2#";
MessageBusHandler.SendOnMsgBuss(msg.SeqID, test, $"cannot process all call request radioID = {radioID}");
}
break;
case 111:
SafeMobileLib.Utils.WriteLine($"RadioComHandler - processing all call stop for radioID = {radioID}");
if (RadioStatus != RADIO_STATUS.ALLcall_INPROGRES)
{
SafeMobileLib.Utils.WriteLine("Radio status!= ALLcall_INPROGRES could not process all call stop.Current Status:" + RadioStatus);
//send 115 failed to SD
string message = "#115#" + Main.GWID + "." + radioID + "#2#";
MessageBusHandler.SendOnMsgBuss(msg.SeqID, message, $"Not in progres, cannot process all call stop for radioID = {radioID}");
break;
}
if (PTTbussy == true)
{
callType = 101;
callSeqID = msg.SeqID;
radioCon.SendPTToff();
SafeMobileLib.Utils.WriteLine("UDP4VoiceRecv - Stop Listen " + " PTT BUSY 111");
udp4VoiceRecv.StopListen();
StopCheckPTTTimer();
}
else
{
SafeMobileLib.Utils.WriteLine("PTTbussy != true could not process all call stop");
//send 115 failed to SD
string message = "#115#" + Main.GWID + "." + radioID + "#2#";
MessageBusHandler.SendOnMsgBuss(msg.SeqID, message);
}
break;
case 102:
SafeMobileLib.Utils.WriteLine($"RadioComHandler - processing private call request for radioID = {radioID}");
//temporary removed speakersOn from IF
if (PTTbussy)
{
SafeMobileLib.Utils.WriteLine("PTTbussy=" + PTTbussy + " speakersOn=" + speakersOn);
test = "#122#" + Main.GWID + "." + radioID + "#2#";
MessageBusHandler.SendOnMsgBuss(msg.SeqID, test, $"It is busy, cannot process all call request for radioID = {radioID}");
break;
}
if (callType != 102 || RadioStatus != RADIO_STATUS.HangTime)
{
SafeMobileLib.Utils.WriteLine("Changing call type to private call 102");
radioCon.SendCallType(1, msg.SUID);
}
//seting status to private call and starting timer
RadioStatusProp = RADIO_STATUS.PrivateCall_INIT;
StartCheckStatusTimer();
bool ret2 = radioCon.SendPTTon();
if (ret2)
{
voiceMulticastIP4Recv = msg.VoiceMulticastIP4Send;
callType = 102;
callSeqID = msg.SeqID;
#if LINXB
// Reset Linx call info to default value just in case
ResetLinxCallInfoValue();
#endif
}
else
{
SafeMobileLib.Utils.WriteLine("SendPTTon command has failed");
test = "#122#" + Main.GWID + "." + radioID + "#2#";
MessageBusHandler.SendOnMsgBuss(msg.SeqID, test, $"cannot process all call request for radioID = {radioID}");
}
break;
case 112:
SafeMobileLib.Utils.WriteLine($"RadioComHandler - processing private call stop for radioID = {radioID}");
if (RadioStatus != RADIO_STATUS.PrivateCall_INPROGRES)
{
SafeMobileLib.Utils.WriteLine("Radio status!= PrivateCall_INPROGRES could not process private call stop.Current Status:" + RadioStatus);
//send 115 failed to SD
string message = "#116#" + Main.GWID + "." + radioID + "#2#";
MessageBusHandler.SendOnMsgBuss(msg.SeqID, message, $"Not in progress, cannot process private call stop for radioID = {radioID}");
break;
}
if (PTTbussy == true)
{
callType = 102;
callSeqID = msg.SeqID;
radioCon.SendPTToff();
SafeMobileLib.Utils.WriteLine("UDP4VoiceRecv - Stop Listen " + " PTT Busy 112");
udp4VoiceRecv.StopListen();
StopCheckPTTTimer();
}
else
{
SafeMobileLib.Utils.WriteLine("PTTbussy != true could not process private call stop");
//send 115 failed to SD
string message = "#116#" + Main.GWID + "." + radioID + "#2#";
MessageBusHandler.SendOnMsgBuss(msg.SeqID, message, $"Not in call, cannot process private call stop for radioID = {radioID}");
}
break;
case 103:
SafeMobileLib.Utils.WriteLine($"RadioComHandler - processing group call request radioID = {radioID}");
if (PTTbussy)
{
SafeMobileLib.Utils.WriteLine("PTTbussy=" + PTTbussy + " speakersOn=" + speakersOn);
test = "#123#" + Main.GWID + "." + radioID + "#2#";
MessageBusHandler.SendOnMsgBuss(msg.SeqID, test, $"It is busy, cannot process group call request for radioID = {radioID}");
break;
}
if (callType!=103 || RadioStatus != RADIO_STATUS.HangTime)
{
SafeMobileLib.Utils.WriteLine("Changing call type to group call 103");
radioCon.SendCallType(0, msg.GroupID);
}
RadioStatusProp = RADIO_STATUS.GroupCall_INIT;
StartCheckStatusTimer();
ret = radioCon.SendPTTon();
if (ret)
{
voiceMulticastIP4Recv = msg.VoiceMulticastIP4Send;
callType = 103;
callSeqID = msg.SeqID;
#if LINXB
// Reset Linx call info to default value just in case
ResetLinxCallInfoValue();
#endif
}
else
{
test = "#123#" + Main.GWID + "." + radioID + "#2#";
MessageBusHandler.SendOnMsgBuss(msg.SeqID, test, $"cannot process group call request for radioID = {radioID}");
}
break;
case 113:
SafeMobileLib.Utils.WriteLine($"RadioComHandler - processing group call stop for radioID = {radioID}");
if (RadioStatus != RADIO_STATUS.GroupCall_INPROGRES)
{
SafeMobileLib.Utils.WriteLine("Radio status!= GroupCall_INPROGRES could not process group call stop.Current Status:" + RadioStatus);
//send 115 failed to SD
string message = "#117#" + Main.GWID + "." + radioID + "#2#";
MessageBusHandler.SendOnMsgBuss(msg.SeqID, message, $"Not in progress, cannot process group call stop for radioID = {radioID}");
break;
}
if (PTTbussy == true)
{
callType = 103;
callSeqID = msg.SeqID;
radioCon.SendPTToff();
SafeMobileLib.Utils.WriteLine("UDP4VoiceRecv - Stop Listen " + " PTT Busy 113");
udp4VoiceRecv.StopListen();
StopCheckPTTTimer();
}
else
{
SafeMobileLib.Utils.WriteLine("PTTbussy != true could not process group call stop");
//send 115 failed to SD
string message = "#117#" + Main.GWID + "." + radioID + "#2#";
MessageBusHandler.SendOnMsgBuss(msg.SeqID, message, $"Not in call, cannot process group call stop for radioID = {radioID}");
break;
}
break;
case 158:
{
// Got new update available
SafeMobileLib.Utils.WriteLine("GOT Update available " + msg.versionNumber, ConsoleColor.Green);
OnNewVersionAvailable?.Invoke(msg.versionNumber);
break;
}
case 160:
SafeMobileLib.Utils.WriteLine("RadioComHandler ID:" + radioID + "processing DeKey");
RadioStatusProp = RADIO_STATUS.DKEY;
StartCheckStatusTimer();
radioCon.SendDeKey();
break;
case 161:
SafeMobileLib.Utils.WriteLine("RadioComHandler ID:" + radioID + "processing remote monitor request." + "Id for remote monitor:" + msg.SUID);
if (RadioStatus != RADIO_STATUS.FREE)
{
SendRadioBussy(msg.SeqID, RadioStatus);
break;
}
RadioStatusProp = RADIO_STATUS.RemoteMonitor;
StartCheckStatusTimer();
radioCon.SendRemoteMonitor(msg.SUID);
RemoteseqID = msg.SeqID;
break;
case 238:
{
SafeMobileLib.Utils.WriteLine("GOT EMERGENCY ACK " + "[ type " + msg.AlarmType + "] for " + msg.SUID);
if(msg.AlarmType != AlarmTypes.unknown)
radioCon.SendEmergencyAck(msg.SUID);
break;
}
default:
//SafeMobileLib.Utils.WriteLine("Unknown opcode for BusMessageParser file: RADIOCOMHANDLER.cs " + opCode);
break;
}
}
private string GetCallType()
{
switch (RadioStatus)
{
case RADIO_STATUS.ALLcall_INIT:
case RADIO_STATUS.ALLcall_INPROGRES:
return "all call";
case RADIO_STATUS.PrivateCall_INIT:
case RADIO_STATUS.PrivateCall_INPROGRES:
return "private call";
case RADIO_STATUS.GroupCall_INIT:
case RADIO_STATUS.GroupCall_INPROGRES:
return "group call";
default:
return "unknown call";
}
}
void udp4VoiceRecv_OnNewDataRecv(byte[] data, int dataLen)
{
SafeMobileLib.Utils.WriteLine($"Voice ({GetCallType()}) form SD on ip {voiceMulticastIP4Recv} -> Radio (IMEI: {this.radioIMEI}; IP: {this.radioIP}; soundIn: {INdevId}; soundOut: {OUTdevID}) ");
try
{
buffWaveProvider?.AddSamples(data, 0, dataLen);
}
catch (InvalidOperationException)
{
// Buffer is full
SafeMobileLib.Utils.WriteLine($"Radio (IMEI: {this.radioIMEI}; IP: {this.radioIP}; soundIn: {INdevId}; soundOut: {OUTdevID}) has voice from SD buffer full",
ConsoleColor.Red);
}
catch (Exception ex)
{
SafeMobileLib.Utils.WriteLine(ex.ToString(), ConsoleColor.Red);
}
}
private void waveInClass_DataAvailable(object sender, WaveInEventArgs e)
{
VoiceReceivedFromRadio(e.Buffer, e.BytesRecorded);
}
public void VoiceReceivedFromRadio(byte[] voiceBuffer, int nbOfAudioBytes)
{
if (speakersOn && nbOfAudioBytes != 0 && PTTbussy && !monitorRequest)
{
#if LINXB
if (LinxCallInfo != LINX.LinxCall.DefaultValue)
{
// voice to linx
RadioVoiceToLinx?.Invoke(this, new LINX.RadioVoiceToLinxEventArgs(voiceBuffer, nbOfAudioBytes));
if (CALL_TYPE == 103 && GroupCallInitiatedByRadio)
{
// Group call initiated by radio
// Send voice to dispatcher also
udp4VoiceSend.Send(voiceBuffer, nbOfAudioBytes);
}
}
else
{
//SafeMobileLib.Utils.WriteLine("catre bigu Length: "+dataLen+"#" + voiceMulticastIP4Send);
udp4VoiceSend.Send(voiceBuffer, nbOfAudioBytes);
}
#else
SafeMobileLib.Utils.WriteLine($"Radio (IMEI: {this.radioIMEI}, IP: {this.radioIP}, soundIN: {INdevId}, soundOUT: {OUTdevID}) puts voice on multicast; " + nbOfAudioBytes + "#" + voiceMulticastIP4Send);
udp4VoiceSend.Send(voiceBuffer, nbOfAudioBytes);
#endif
}
if (speakersOn && nbOfAudioBytes != 0 && monitorRequest)
{
//SafeMobileLib.Utils.WriteLine("Sending audio data for ROMOTE MONITORING");
udp4VoiceSend.Send(voiceBuffer, nbOfAudioBytes);
}
}
#region radio connection events
static int count = 0;
void radioCon_OnRestartEvent()
{
throw new NotImplementedException();
}
void radioCon_OnRemoteControlEvent(bool status, REMOTE_RADIO_FUNCS func, int remote_radioId)
{
if (func == REMOTE_RADIO_FUNCS.Monitor)
{
if (status)
{
string test = "#162#" + Main.GWID + "." + radioID + "." + remote_radioId + "#1#";
MessageBusHandler.SendOnMsgBuss(RemoteseqID, test);
monitorID = remote_radioId;
monitorRequest = true;
//start voice buss for send
RadioStatusProp = RADIO_STATUS.RemoteMonitor_INPROGRES;
}
else
{
string test = "#162#" + Main.GWID + "." + radioID + "." + remote_radioId + "#2#";
MessageBusHandler.SendOnMsgBuss(RemoteseqID, test);
RadioStatusProp = RADIO_STATUS.FREE;
}
}
}
void radioCon_OnChannelEvent(int zoneNr, int channelNr)
{
sw_zone_nr = zoneNr;
sw_channel_nr = channelNr;
//seqID = "0.0";
SafeMobileLib.Utils.WriteLine(id_local+"Got a channel broadcast sending it to message bus(opcode-124)");
//build string
string test = "#124#" + Main.GWID + "." + radioID + "#" + zoneNr.ToString() + "." + channelNr.ToString() + "#";
if (channelQuerry_seqID.Length > 2) MessageBusHandler.SendOnMsgBuss(channelQuerry_seqID, test);
else MessageBusHandler.SendOnMsgBuss("0.0", test);//Broadcast
RadioStatusProp = RADIO_STATUS.FREE;
//send event to GW
if (this.OnChannelEvent != null)
{
this.OnChannelEvent(zoneNr, channelNr);
}
}
void radioCon_OnCallEvent(CALL_STATUS status, int callerID, int callType, int groupID)
{
if (radioIMEI != callerID && callerID != 0)
{
//SafeMobileLib.Utils.WriteLine("#### " + status);
SafeMobileLib.Utils.WriteLine("Portable On Call Event #### " + status, ConsoleColor.Magenta);
//register route
if (!Main.capacityPlus)
{
SafeMobileLib.Utils.WriteLine("RadioGW received a call from field unit with ID " + callerID + " on gateway radio with IP " + radioIP + " \n\r Adding route to route table if route not present.", ConsoleColor.Red);
if (RouteManager.NetworkIDs_Hash.ContainsKey(radioIP))
{
//RoutingUtils.addRoute(callerID.ToString(), radioIP, RouteManager.NetworkIDs_Hash[radioIP].ToString());
RoutingUtils.addRoute_withBuffer(callerID.ToString(), radioIP, RouteManager.NetworkIDs_Hash[radioIP].ToString());
}
else
{
SafeMobileLib.Utils.WriteLine("RouteManager.NetworkIDs_Hash does not contain a key for " + radioIP);
}
//RoutingUtils.displayRoutes();
}
CALLER_ID = callerID;
int callStatus = 0;
int _callType = 101;
if (callType == 0x04)
{
_callType = 102;
}
else
{
_callType = (groupID == 0xffffff) ? 101 : 103;
}
CALL_TYPE = _callType;
string message = "";
switch (status)
{
case CALL_STATUS.INIT:
if ((_callType == 101)) // all call
{
SafeMobileLib.Utils.WriteLine("------------------------------------------------");
SafeMobileLib.Utils.WriteLine("Got INITIAL call from:" + callerID + " callType:" + callType + " groupID:" + groupID);
callStatus = 1;
//send broadcast
message = "#125#" + Main.GWID + "." + radioID + "." + callerID.ToString() + "#" + callStatus + "#" + _callType + "#" + groupID + "#";
MessageBusHandler.SendOnMsgBuss("0.0", message, "all call - init");
//setting voice on/off
PTTbussy = true;
RadioStatusProp = RADIO_STATUS.ALLcall_INPROGRES;
}
break;
case CALL_STATUS.INCALL:
if (_callType == 102 || _callType == 103) // private or group call
{
SafeMobileLib.Utils.WriteLine("Got INCALL call from:" + callerID + " callType:" + callType + " groupID:" + groupID);
callStatus = 1;
#if LINXB
bool isGroupCall = (_callType == 103);
int? linxIDForPrivateCall = null;
if (LinxCallInfo != LINX.LinxCall.DefaultValue) // Check if I'm in hangtime with a Linx
{
if (_callType == 102)
{
// Start timer just for private calls
_timerPrivatePTTToLinx.Start();
}
}
else if (_callType == 102 && (linxIDForPrivateCall = LinxIDForPrivateCall(callerID)) != null) // Check if i make a private call to a linx
{
this.LinxCallInfo = new LINX.LinxCall(linxIDForPrivateCall.Value.ToString(), GetRadioSipID(callerID, false));
}
else
{
// normal info for mBus
//build string
message = "#125#" + Main.GWID + "." + radioID + "." + callerID.ToString() + "#" + callStatus + "#" + _callType + "#" + groupID + "#";
MessageBusHandler.SendOnMsgBuss("0.0", message);
}
CallLinx?.Invoke(this, new LINX.CallLinxEventArgs(callerID, isGroupCall, groupID));
#else
//send broadcast
message = "#125#" + Main.GWID + "." + radioID + "." + callerID.ToString() + "#" + callStatus + "#" + _callType + "#" + groupID + "#";
MessageBusHandler.SendOnMsgBuss("0.0", message, "broadcast inCall");
#endif
//setting voice on/off
PTTbussy = true;
RadioStatusProp = ( _callType == 102 ) ? RADIO_STATUS.PrivateCall_INPROGRES : RADIO_STATUS.GroupCall_INPROGRES;
}
break;
case CALL_STATUS.HANGTIMER:
if (_callType == 102 || _callType == 103)
{
SafeMobileLib.Utils.WriteLine("Got HANGtimmer call from:" + callerID + " callType:" + callType + " groupID:" + groupID);
callStatus = 2;
#if LINXB
// Check if I'm in hangtime with a Linx
if (LinxCallInfo != LINX.LinxCall.DefaultValue)
{
RadioEndsPTTtoLinx?.Invoke(this, new EventArgs());
if (this.CALL_TYPE == 103)
{
// group call, send hang time command to SD
// normal info for mBus
//build string
message = "#125#" + Main.GWID + "." + radioID + "." + callerID.ToString() + "#" + callStatus + "#" + _callType + "#" + groupID + "#";
MessageBusHandler.SendOnMsgBuss("0.0", message);
}
}
else
{
// normal info for mBus
//build string
message = "#125#" + Main.GWID + "." + radioID + "." + callerID.ToString() + "#" + callStatus + "#" + _callType + "#" + groupID + "#";
MessageBusHandler.SendOnMsgBuss("0.0", message);
}
#else
//send broadcast
message = "#125#" + Main.GWID + "." + radioID + "." + callerID.ToString() + "#" + callStatus + "#" + _callType + "#" + groupID + "#";
MessageBusHandler.SendOnMsgBuss("0.0", message, "broadcast hangtime");
#endif
//setting voice on/off
PTTbussy = false;
RadioStatusProp = RADIO_STATUS.HangTime;
}
break;
case CALL_STATUS.CALLEND:
SafeMobileLib.Utils.WriteLine("Got callend from:" + callerID + " callType:" + callType + " groupID:" + groupID);
callStatus = 3;
#if LINXB
if (RadioStatusProp != RADIO_STATUS.GroupCall_INIT && LinxCallInfo != LINX.LinxCall.DefaultValue)
{
// Clear the details of the previous linx call
ResetLinxCallInfoValue();
GroupCallInitiatedByRadio = false;
if (this.CALL_TYPE == 103)
{
// If is group call, send call end on mbus for dispatcher
message = "#125#" + Main.GWID + "." + radioID + "." + callerID.ToString() + "#" + callStatus + "#" + _callType + "#" + groupID + "#";
MessageBusHandler.SendOnMsgBuss("0.0", message);
}
}
else
{
//build string
message = "#125#" + Main.GWID + "." + radioID + "." + callerID.ToString() + "#" + callStatus + "#" + _callType + "#" + groupID + "#";
MessageBusHandler.SendOnMsgBuss("0.0", message);
}
#else
//send broadcast
message = "#125#" + Main.GWID + "." + radioID + "." + callerID.ToString() + "#" + callStatus + "#" + _callType + "#" + groupID + "#";
MessageBusHandler.SendOnMsgBuss("0.0", message, "broadcast callend");
#endif
//setting voice on/off
PTTbussy = false;
RadioStatusProp = RADIO_STATUS.FREE;
SafeMobileLib.Utils.WriteLine("------------------------------------------------");
break;
}
}
else
{
//this is for calls made from SD to GW.
//callerID is the same as the ID of base station
SafeMobileLib.Utils.WriteLine("Base Station On Call Event #### " + status, ConsoleColor.Magenta);
if (status == CALL_STATUS.HANGTIMER)
{
//send broadcast
string test = "#125#" + Main.GWID + "." + radioID + "." + callerID.ToString() + "#2#0#0#";
MessageBusHandler.SendOnMsgBuss("0.0", test, "broadcast hangtime");
RadioStatusProp = RADIO_STATUS.FREE;
SafeMobileLib.Utils.WriteLine("------------------------------------------------");
}
if (status == CALL_STATUS.CALLEND)
{
#if LINXB
if (RadioStatusProp != RADIO_STATUS.GroupCall_INIT && LinxCallInfo != LINX.LinxCall.DefaultValue)
{
// Clear the details of the previous linx call
ResetLinxCallInfoValue();
GroupCallInitiatedByRadio = false;
}
else
{
string test = "#125#" + Main.GWID + "." + radioID + "." + callerID.ToString() + "#3#0#0#";
MessageBusHandler.SendOnMsgBuss("0.0", test);
}
#else
//send broadcast
string test = "#125#" + Main.GWID + "." + radioID + "." + callerID.ToString() + "#3#0#0#";
MessageBusHandler.SendOnMsgBuss("0.0", test, "broadcast callend");
#endif
RadioStatusProp = RADIO_STATUS.FREE;
SafeMobileLib.Utils.WriteLine("------------------------------------------------");
}
}
}
void radioCon_OnSpeakersEvent(bool onOFF)
{
if (onOFF) { SafeMobileLib.Utils.WriteLine("=============================="); }
SafeMobileLib.Utils.WriteLine("speakers "+onOFF);
if (!onOFF) { SafeMobileLib.Utils.WriteLine("=============================="); }
speakersOn = onOFF;
if (monitorRequest && !speakersOn)
{
SafeMobileLib.Utils.WriteLine("Speakers off.Turning remote monitor OFF");
RadioStatusProp = RADIO_STATUS.FREE;
monitorRequest = false;
string test = "#172#" + Main.GWID + "." + radioID + "." + monitorID + "#1#";
MessageBusHandler.SendOnMsgBuss("0.0", test);
}
//hangtimmer for private call is handled in speakers event
//if (RadioStatus == RADIO_STATUS.CallEvent && !speakersOn && CALL_TYPE==102)
if (RadioStatus == RADIO_STATUS.PrivateCall_INPROGRES && !speakersOn && CALL_TYPE == 102)
{
SafeMobileLib.Utils.WriteLine("Got HANGtimmer call from:" + CALLER_ID + " callType:" + callType + " groupID:0");
bool onOff = false;
int callStatus = 2;
//send broadcast
string message = "#125#" + Main.GWID + "." + radioID + "." + CALLER_ID.ToString() + "#" + callStatus + "#102#0#";
MessageBusHandler.SendOnMsgBuss("0.0", message);
//setting voice on/off
PTTbussy = onOff;
RadioStatusProp = RADIO_STATUS.FREE;
}
PTTbussy = onOFF;
}
void radioCon_OnTransmitEvent(bool onOFF)
{
try
{
//if call originate from BASE stattion it means that the base sation made a call
// 101-all call 102 - private call 103- group call
// send back to SD the appropiete response(call on/off)
SafeMobileLib.Utils.WriteLine($"radioCon_OnTransmitEvent CALL TYPE : {callType}" );
if (callType != 0)
{
switch (callType)
{
case 101:
if (onOFF)
{
SendALLcallACK2SD(callSeqID);
}
else
{
if (RadioStatusProp == RADIO_STATUS.ALLcall_INIT)
{
//ALL call could not be performend!!!(channel bussy or something)
radioCon.SendPTToff();
}
//send ack to SD
string test = "#115#" + Main.GWID + "." +radioID + "#1#";
MessageBusHandler.SendOnMsgBuss(callSeqID, test, "all call off - send ack to SD");
PTTbussy = false;
RadioStatusProp = RADIO_STATUS.FREE;
tCheckPTT = null;
}
callType = 0;
break;
case 102:
if (onOFF)
SendPrivateCallACK2SD(callSeqID);
else
{
if (RadioStatusProp == RADIO_STATUS.PrivateCall_INIT)
{
//Private call could not be performend!!!(channel bussy or something)
radioCon.SendPTToff();
}
//send ack to SD
string test = "#116#" +Main.GWID + "." + radioID +"#1#";
MessageBusHandler.SendOnMsgBuss(callSeqID, test, "private call off - send ack to SD");
PTTbussy = false;
RadioStatusProp = RADIO_STATUS.FREE;
tCheckPTT = null;
}
callType = 0;
break;
#if LINXB
case 1002: // Private linx call
if (onOFF)
{
PTTbussy = true;
RadioStatusProp = RADIO_STATUS.PrivateCall_INPROGRES;
// Send 122 to notify dispatchers on mbus that radio gw is busy
MessageBusHandler.SendOnMsgBuss("123456789", "#122#" + Main.GWID + "." + radioID + "#1#");
if (LinxCallInfo != LINX.LinxCall.DefaultValue)
{
// Fire event - linx call established
LinxCallEstablished?.Invoke(this, new EventArgs());
}
}
else
{
if (RadioStatusProp == RADIO_STATUS.PrivateCall_INIT)
{
//Private call could not be performend!!!(channel bussy or something)
radioCon.SendPTToff();
if (LinxCallInfo != LINX.LinxCall.DefaultValue)
{
// Notify the Linx
LinxCallFailed?.Invoke(this, new EventArgs());
}
}
PTTbussy = false;
RadioStatusProp = RADIO_STATUS.FREE;
// send 116 on mbus to notify dispatchers that the radio gw is free
string test = "#116#" + Main.GWID + "." + radioID + "#1#";
MessageBusHandler.SendOnMsgBuss("123456789", test);
// tCheckPTT = null is not necessary
}
break;
#endif
case 103:
if (onOFF)
SendGroupCallACK2SD(callSeqID);
else
{
if (RadioStatusProp == RADIO_STATUS.GroupCall_INIT)
{
//Group call could not be performend!!!(channel bussy or something)
radioCon.SendPTToff();
}
//send ack to SD
string test = "#117#" + Main.GWID + "." + radioID + "#1#";
MessageBusHandler.SendOnMsgBuss(callSeqID, test, "group call off - send ack to SD");
PTTbussy = false;
RadioStatusProp = RADIO_STATUS.FREE;
tCheckPTT = null;
}
callType = 0;
break;
#if LINXB
case 1003: // Group Linx call
if (onOFF)
{
PTTbussy = true;
RadioStatusProp = RADIO_STATUS.GroupCall_INPROGRES;
// Send 123 to notify dispatchers on mbus that radio gw is busy
MessageBusHandler.SendOnMsgBuss("123456789", "#123#" + Main.GWID + "." + radioID + "#1#");
if (LinxCallInfo != LINX.LinxCall.DefaultValue)
{
// Fire event - linx call established
LinxCallEstablished?.Invoke(this, new EventArgs());
}
else
SafeMobileLib.Utils.WriteLine("------------- Here i should start the call but i dont do it", ConsoleColor.Red);
}
else
{
if (RadioStatusProp == RADIO_STATUS.GroupCall_INIT)
{
//Group call could not be performend!!!(channel bussy or something)
radioCon.SendPTToff();
if (LinxCallInfo != LINX.LinxCall.DefaultValue)
{
// Notify linx to close the call
LinxCallFailed?.Invoke(this, new EventArgs());
}
}
PTTbussy = false;
RadioStatusProp = RADIO_STATUS.FREE;
// send 117 on mbus to notify dispatchers that the readio gw is free
string test = "#117#" + Main.GWID + "." + radioID + "#1#";
MessageBusHandler.SendOnMsgBuss(callSeqID, test);
// tCheckPTT = null; this in useless
}
break;
#endif
}
}
}
catch (Exception ex)
{
SafeMobileLib.Utils.WriteLine(ex.ToString());
}
}
//if timer expired(1min) auto send PTT off
private void CheckPTT(Object state)
{
SafeMobileLib.Utils.WriteLine("@@@@@@@@@ PTT timer expired ... sending PTT oFF !!!!!!!!for:"+radioIP+"@@@@@@@@@@");
if (PTTbussy == true)
{
radioCon.SendPTToff();
SafeMobileLib.Utils.WriteLine("UDP4VoiceRecv - Stop Listen " + " PTT Expired ");
udp4VoiceRecv.StopListen();
}
}
private void CheckSTATUS(Object state)
{
if ((RadioStatus != RADIO_STATUS.ALLcall_INPROGRES) &&
(RadioStatus != RADIO_STATUS.PrivateCall_INPROGRES)&&
(RadioStatus != RADIO_STATUS.GroupCall_INPROGRES)&&
(RadioStatus != RADIO_STATUS.RemoteMonitor_INPROGRES)&&
(RadioStatus != RADIO_STATUS.HangTime) &&
(RadioStatus != RADIO_STATUS.FREE))
{
RadioStatusProp = RADIO_STATUS.FREE;
SafeMobileLib.Utils.WriteLine("!!!!!!!!Timer expired and nothing happend... setting radio status to FREE!!!!!");
}
}
private String RemoteseqID = "";
private string channelQuerry_seqID = "";
#endregion
//methods for GW
#region methods for GW
public bool Start()
{
SafeMobileLib.Utils.WriteLine("IndecId:" + INdevId + "outdev:" + OUTdevID);
//test radio com
if (radioCon.Connected)
{
//start messageBus listner
//udp.StartListen();
//start voice
if ((INdevId != -1) && (OUTdevID != -1))
{
NAudio.Wave.WaveFormat waveFormat = new NAudio.Wave.WaveFormat(Main.sampleRate, Main.bitdepth, 1);
buffWaveProvider = new BufferedWaveProvider(waveFormat);
if (Main.AudioDriver == AudioDriverType.Windows)
{
_audioManager = new AudioManager(OUTdevID, INdevId, Main.recordedBufferMiliseconds, waveFormat);
_audioManager.WaveInAudioAvailable += waveInClass_DataAvailable;
_audioManager.Init(buffWaveProvider);
_audioManager.WaveInStartRecording();
_audioManager.Play();
}
connected = true;
return true;
}
else
{
SafeMobileLib.Utils.WriteLine("Unable to start audio device");
connected = false;
return false;
}
}
else
return false;
}
public void Stop()
{
connected = false;
//send stop message to MSG bus
string test = "#100#" + Main.GWID + "." + radioID + "#0#";
MessageBusHandler.SendOnMsgBuss("0.0", test);
_audioManager?.Dispose();
if (udp4VoiceRecv != null)
{
SafeMobileLib.Utils.WriteLine("UDP4VoiceRecv - Stop Listen " + " STOP");
udp4VoiceRecv.StopListen();
}
//detach events
radioCon.OnChannelEvent -= new RadioConnection.ChannelEvent(radioCon_OnChannelEvent);
radioCon.OnCallEvent -= new RadioConnection.CallEvent(radioCon_OnCallEvent);
radioCon.OnSpeakersEvent -= new RadioConnection.SpeakersEvent(radioCon_OnSpeakersEvent);
radioCon.OnRemoteControlEvent -= new RadioConnection.RemoteControlEvent(radioCon_OnRemoteControlEvent);
radioCon.OnTransmitEvent -= new RadioConnection.TransmitEvent(radioCon_OnTransmitEvent);
radioCon.OnRestartEvent -= new RadioConnection.RestartEvent(radioCon_OnRestartEvent);
if (listenThread != null)
{
listenThread.Abort();
listenThread = null;
}
}
public void SendZoneChannelChange(int zoneNr, int channelNr)
{
radioCon.SendChannelChange(zoneNr, channelNr);
}
public void StartCheckStatusTimer()
{
tCheckSTATUS = new System.Threading.Timer(CheckSTATUS, null, 5000, System.Threading.Timeout.Infinite);
}
#endregion
private void StartCheckPTTTimer()
{
if (tCheckPTT != null)
tCheckPTT.Dispose();
tCheckPTT = new System.Threading.Timer(CheckPTT, null, 55000, System.Threading.Timeout.Infinite);
}
private void StopCheckPTTTimer()
{
if (tCheckPTT != null)
tCheckPTT.Dispose();
tCheckPTT = null;
}
#region events
public delegate void ChannelEvent(int zoneNr, int channelNr);
public event ChannelEvent OnChannelEvent;
public delegate void AuthDoneDEl();
public event AuthDoneDEl OnAuthDone;
#endregion
private void SendALLcallACK2SD(string _seqID)
{
string test = "#121#" + Main.GWID + "." + radioID + "#1#";
MessageBusHandler.SendOnMsgBuss(_seqID, test, "all call on - send ack to SD");
SafeMobileLib.Utils.WriteLine("\n\n########### **************** ALL CALL VOICE ACK: " + voiceMulticastIP4Recv);
SafeMobileLib.Utils.WriteLine("########### **************** GwID =" + Main.GWID + " | radioID = " + radioID + " | \n\n");
PTTbussy = true;
//start voice buss for send
StartVoiceBuss();
StartCheckPTTTimer();
RadioStatusProp = RADIO_STATUS.ALLcall_INPROGRES;
}
private void SendPrivateCallACK2SD(string _seqID)
{
string test = "#122#" + Main.GWID + "." + radioID + "#1#";
MessageBusHandler.SendOnMsgBuss(_seqID, test, "private call on - send ack to SD");
SafeMobileLib.Utils.WriteLine("\n\n########### **************** PRIVATE CALL VOICE ACK: " + voiceMulticastIP4Recv);
SafeMobileLib.Utils.WriteLine("########### **************** GwID =" + Main.GWID + " | radioID = " + radioID + " | \n\n");
PTTbussy = true;
//start voice buss for send
StartVoiceBuss();
StartCheckPTTTimer();
RadioStatusProp = RADIO_STATUS.PrivateCall_INPROGRES;
}
private void StartVoiceBuss()
{
udp4VoiceRecv = new UdpMulticast(voiceMulticastIP4Recv, voice_port);
udp4VoiceRecv.OnNewDataRecv += new UdpMulticast.newData4Send(udp4VoiceRecv_OnNewDataRecv);
udp4VoiceRecv.StartListen(Main.LocalIP);
}
private void SendGroupCallACK2SD(string _seqID)
{
string test = "#123#" + Main.GWID + "." + radioID + "#1#";
MessageBusHandler.SendOnMsgBuss(_seqID, test, "group call on - send ack to SD");
SafeMobileLib.Utils.WriteLine("\n\n########### **************** GROUP CALL VOICE ACK: " + voiceMulticastIP4Recv);
SafeMobileLib.Utils.WriteLine("########### **************** GwID = " + Main.GWID + " | radioID = " + radioID + " | \n\n");
PTTbussy = true;
//start voice buss for send
StartVoiceBuss();
StartCheckPTTTimer();
RadioStatusProp = RADIO_STATUS.GroupCall_INPROGRES;
}
private void SendRadioBussy(string _seqID,RADIO_STATUS status)
{
SafeMobileLib.Utils.WriteLine("Sending Radio bussy. reason "+status +" status byte:"+((byte)status));
//string test = "#10#" + Main.GWID + "." + radioID + "#"+((byte)status).ToString()+"#2#";
string test = "#122#" + Main.GWID + "." + radioID + "#2#";
MessageBusHandler.SendOnMsgBuss(_seqID, test, "Radio is busy!");
}
internal void ClearVoiceResources()
{
//if (r.rcHandler.waveOutClass != null)
//{
// r.rcHandler.waveOutClass.Dispose();
// r.rcHandler.waveOutClass = null;
//}
//if (r.rcHandler.waveInClass != null)
//{
// r.rcHandler.waveInClass.DataAvailable -= r.rcHandler.waveInClass_DataAvailable;
// r.rcHandler.waveInClass.Dispose();
// r.rcHandler.waveInClass = null;
//}
if (_audioManager != null)
{
_audioManager.WaveInAudioAvailable -= waveInClass_DataAvailable;
_audioManager.Dispose();
}
}
public delegate void NewVersionAvailableDel(String version);
public event NewVersionAvailableDel OnNewVersionAvailable;
#region METHODS for Linx
#if LINXB
internal bool InviteFromLinx(string linxSipID, int radioSipID, int radioID, bool isGroupCall)
{
bool success = false;
if (IsPTTbussy)
{
SafeMobileLib.Utils.WriteLine($@"Decline the inivite from sip id {linxSipID} to radio {radioID}
because base station {this.radioID} is ptt busy", ConsoleColor.DarkRed);
}
else
{
if (isGroupCall)
{
radioCon.SendCallType(0, radioID); // group radio ptt
RadioStatusProp = RADIO_STATUS.GroupCall_INIT;
}
else
{
radioCon.SendCallType(1, radioID); // private radio ptt
RadioStatusProp = RADIO_STATUS.PrivateCall_INIT;
}
// start the tCheckStatus timer
StartCheckStatusTimer();
success = radioCon.SendPTTon();
if (success)
{
this.LinxCallInfo = new LINX.LinxCall(linxSipID, radioSipID);
callType = isGroupCall ? 1003 : 1002;
}
else
SafeMobileLib.Utils.WriteLine($@"Decline the inivite from sip id {linxSipID} to radio {radioID}
because base station {this.radioID} failed to send PTT", ConsoleColor.DarkRed);
}
return success;
}
internal void LinxReceivesPTTFromRadio(LINX.LinxCall linxCall)
{
if (this.CALL_TYPE == 102)
{
// Stop the timer for private calls
_timerPrivatePTTToLinx.Stop();
}
else if (this.CALL_TYPE == 103)
{
// Ensure that voice is being sent to LINX
this.LinxCallInfo = linxCall;
}
}
private void _timerLinx_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// If timer has elapsed then the dialog with linx has not been established on portable ptt button press
// I will send dekey to the portable in this case
if (RadioStatusProp == RADIO_STATUS.CallEvent)
{
RadioStatusProp = RADIO_STATUS.DKEY;
StartCheckStatusTimer();
radioCon.SendDeKey();
RadioEndsPTTtoLinx?.Invoke(this, new EventArgs());
}
}
private int GetRadioSipID(int radioID, bool isGroup)
{
int? radioSipID = RadioSipIDRequested?.Invoke(radioID, isGroup);
return radioSipID ?? -1;
}
private int? LinxIDForPrivateCall(int radioID)
{
int? linxID = LinxIDForPrivateCallRequested?.Invoke(radioID);
return linxID;
}
public void ResetLinxCallInfoValue()
{
this.LinxCallInfo = LINX.LinxCall.DefaultValue;
}
#endif
#endregion
#region EVENTS for Linx
#if LINXB
public event EventHandler LinxCallEstablished;
public event EventHandler LinxCallFailed;
public event EventHandler<LINX.CallLinxEventArgs> CallLinx;
public event EventHandler<LINX.RadioVoiceToLinxEventArgs> RadioVoiceToLinx;
public event EventHandler RadioEndsPTTtoLinx;
public delegate int? LinxIDForPrivateCallDel(int radioID);
public event LinxIDForPrivateCallDel LinxIDForPrivateCallRequested;
public delegate int RadioSipIDRequestedDel(int radioID, bool isGroup);
public event RadioSipIDRequestedDel RadioSipIDRequested;
#endif
#endregion
}
public enum RADIO_STATUS
{
OFF = 0x00,
FREE = 0x01,
ALLcall_INIT = 101,
ALLcall_INPROGRES = 121,
PrivateCall_INIT = 102,
PrivateCall_INPROGRES = 122,
GroupCall_INIT = 103,
GroupCall_INPROGRES = 123,
ChannelQuery = 104,
CallEvent = 125,
RemoteMonitor = 161,
RemoteMonitor_INPROGRES = 162,
DKEY = 160,
EnableDisable = 150,
HangTime = 108,
}
}