SafeDispatch/MotoRepeaterCore/MessageBus.cs
2024-02-22 18:43:59 +02:00

567 lines
30 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SafeMobileLib;
namespace MotoRepeater
{
class MessageBus
{
private UdpMulticast udpMulticast;
private String mIP;
private Int32 mPort;
public static bool wait4ack = true;
public MessageBus(String multicastID, Int32 multicastPort)
{
mIP = multicastID;
mPort = multicastPort;
try
{
udpMulticast = new UdpMulticast(mIP, mPort);
Utils.WriteLine("MessageBus thread successfully registered to multicast group");
udpMulticast.OnNewDataRecv += new UdpMulticast.newData4Send(udpMulticast_OnNewDataRecv);
udpMulticast.StartListen();
}
catch (Exception ex)
{
Utils.WriteLine("Thread exception while joining the multicast group: " + ex.ToString());
}
}
void udpMulticast_OnNewDataRecv(byte[] data, int dataLen)
{
try
{
string str = System.Text.Encoding.ASCII.GetString(data, 0, dataLen);
String[] tempArray = str.Trim().Split('#');
Wireline.SlotNumber slot = Wireline.SlotNumber.BothSlots;
if (tempArray.Length > 3)
{
int gwid_recv = 0;
if (tempArray[4].Contains('.'))
Int32.TryParse((tempArray[4].Split('.'))[0], out gwid_recv);
int opertationCode = int.Parse(tempArray[3]);
//Utils.WriteLine("GWID RECV : " + gwid_recv + " | " + (tempArray[4].Split('.'))[0], ConsoleColor.Cyan);
#region DESIGNATED FOR THIS GATEWAY
if (gwid_recv == MotoRepeater_GW.cfg.GWID)
{
//Utils.WriteLine("OP Code: " + opertationCode, ConsoleColor.Red);
if (opertationCode == (int)MessageBusCmds.PollRequest)
{
//Console.WriteLine("LocationThread received from multicast bus: " + str.Trim());
string SUID = (tempArray[4].Split('.'))[2];
// fire event
OnPollRequest(Int64.Parse(SUID));
}
else if (opertationCode == (int)MessageBusCmds.EmergencyACK)
{
try
{
// check if slot parameter is selected or not
if (tempArray.Length > 6)
slot = (int.Parse(tempArray[5]) == 1 ? Wireline.SlotNumber.Slot1 :
(int.Parse(tempArray[5]) == 2 ? Wireline.SlotNumber.Slot2 : Wireline.SlotNumber.BothSlots));
// trigger event for slot 1 even if both is selected
if (slot == Wireline.SlotNumber.Slot1 || slot == Wireline.SlotNumber.BothSlots)
OnEmergencyAckRequest(Int64.Parse((tempArray[4].Split('.'))[2]), Wireline.SlotNumber.Slot1);
// trigger event for slot 2 even if both is selected
if (slot == Wireline.SlotNumber.Slot2 || slot == Wireline.SlotNumber.BothSlots)
OnEmergencyAckRequest(Int64.Parse((tempArray[4].Split('.'))[2]), Wireline.SlotNumber.Slot2);
Utils.WriteLine(String.Format("--- Emergency ACK for {0} [{1}]",
Int64.Parse((tempArray[4].Split('.'))[2]), slot), ConsoleColor.White, ConsoleType.MB);
}
catch (Exception ex)
{
Utils.WriteLine("Exception ex " + ex.ToString());
}
}
else if (opertationCode == (int)MessageBusCmds.RadioEnableDisableRequest)
{
// check if slot parameter is selected or not
if (tempArray.Length > 7)
slot = (int.Parse(tempArray[6]) == 1 ? Wireline.SlotNumber.Slot1 : Wireline.SlotNumber.Slot2);
Utils.WriteLine(String.Format("--- {0} for {1} [{2}]", (int.Parse(tempArray[5]) == 0 ? "Radio Disable" : "Radio Enable"),
Int64.Parse((tempArray[4].Split('.'))[2]), slot), ConsoleColor.White);
// trigger event for slot 1 even if both is selected
if(slot == Wireline.SlotNumber.Slot1 || slot == Wireline.SlotNumber.BothSlots)
OnRadioEnableDisableRequest(Int64.Parse((tempArray[4].Split('.'))[2]), int.Parse(tempArray[5]) == 0 ? false : true, Wireline.SlotNumber.Slot1);
// trigger event for slot 2 even if both is selected
if (slot == Wireline.SlotNumber.Slot2 || slot == Wireline.SlotNumber.BothSlots)
OnRadioEnableDisableRequest(Int64.Parse((tempArray[4].Split('.'))[2]), int.Parse(tempArray[5]) == 0 ? false : true, Wireline.SlotNumber.Slot2);
}
else if (opertationCode == (int)MessageBusCmds.InitAllCall || opertationCode == (int)MessageBusCmds.InitPrivateCall || opertationCode == (int)MessageBusCmds.InitGroupCall)
{
// check if slot parameter is selected or not
if (tempArray.Length > 7)
slot = (int.Parse(tempArray[6]) == 1 ? Wireline.SlotNumber.Slot1 : Wireline.SlotNumber.Slot2);
switch (opertationCode)
{
case (int)MessageBusCmds.InitAllCall:
Utils.WriteLine(String.Format("--- Init {0} [{1}]", "All Call", slot), ConsoleColor.White);
// trigger event for slot 1 even if both is selected
if (slot == Wireline.SlotNumber.Slot1 || slot == Wireline.SlotNumber.BothSlots)
OnInitAllCallRequest(tempArray[5], Wireline.SlotNumber.Slot1);
/*
// trigger event for slot 2 even if both is selected
if (slot == Wireline.SlotNumber.Slot2 || slot == Wireline.SlotNumber.Both)
OnInitAllCallRequest(tempArray[5], Wireline.SlotNumber.Slot2);
//*/
break;
case (int)MessageBusCmds.InitPrivateCall:
Utils.WriteLine(String.Format("--- Init {0} for {1} [{2}]", "Private Call", Int64.Parse((tempArray[4].Split('.'))[2]), slot), ConsoleColor.White);
// trigger event for slot 1 even if both is selected
if (slot == Wireline.SlotNumber.Slot1 || slot == Wireline.SlotNumber.BothSlots)
OnInitPrivateCallRequest(Int64.Parse((tempArray[4].Split('.'))[2]), tempArray[5], Wireline.SlotNumber.Slot1);
/*
// trigger event for slot 2 even if both is selected
if (slot == Wireline.SlotNumber.Slot2 || slot == Wireline.SlotNumber.Both)
OnInitPrivateCallRequest(Int64.Parse((tempArray[4].Split('.'))[2]), tempArray[5], Wireline.SlotNumber.Slot2);
//*/
break;
case (int)MessageBusCmds.InitGroupCall:
Utils.WriteLine(String.Format("--- Init {0} for {1} [{2}]", "Group Call", Int64.Parse((tempArray[4].Split('.'))[2]), slot), ConsoleColor.White);
// trigger event for slot 1 even if both is selected
if (slot == Wireline.SlotNumber.Slot1 || slot == Wireline.SlotNumber.BothSlots)
OnInitGroupCallRequest(Int64.Parse((tempArray[4].Split('.'))[2]), tempArray[5], Wireline.SlotNumber.Slot1);
/*
// trigger event for slot 2 even if both is selected
if (slot == Wireline.SlotNumber.Slot2 || slot == Wireline.SlotNumber.Both)
OnInitGroupCallRequest(Int64.Parse((tempArray[4].Split('.'))[2]), tempArray[5], Wireline.SlotNumber.Slot2);
//*/
break;
}
}
#region END CALL
else if (opertationCode == (int)MessageBusCmds.EndAllCall || opertationCode == (int)MessageBusCmds.EndPrivateCall || opertationCode == (int)MessageBusCmds.EndGroupCall)
{
// check if slot parameter is selected or not
if (tempArray.Length > 7)
slot = (int.Parse(tempArray[6]) == 1 ? Wireline.SlotNumber.Slot1 : Wireline.SlotNumber.Slot2);
switch (opertationCode)
{
case (int)MessageBusCmds.EndAllCall:
Utils.WriteLine(String.Format("--- End {0} [{1}]", "All Call", slot), ConsoleColor.White);
// trigger event for slot 1 even if both is selected
if (slot == Wireline.SlotNumber.Slot1 || slot == Wireline.SlotNumber.BothSlots)
OnEndAllCallRequest(tempArray[5], Wireline.SlotNumber.Slot1);
/*
// trigger event for slot 2 even if both is selected
if (slot == Wireline.SlotNumber.Slot2 || slot == Wireline.SlotNumber.Both)
OnEndAllCallRequest(tempArray[5], Wireline.SlotNumber.Slot2);
//*/
break;
case (int)MessageBusCmds.EndPrivateCall:
Utils.WriteLine(String.Format("--- End {0} for {1} [{2}]", "Private Call", Int64.Parse((tempArray[4].Split('.'))[2]), slot), ConsoleColor.White);
// trigger event for slot 1 even if both is selected
if (slot == Wireline.SlotNumber.Slot1 || slot == Wireline.SlotNumber.BothSlots)
OnEndPrivateCallRequest(Int64.Parse((tempArray[4].Split('.'))[2]), tempArray[5], Wireline.SlotNumber.Slot1);
/*
// trigger event for slot 2 even if both is selected
if (slot == Wireline.SlotNumber.Slot2 || slot == Wireline.SlotNumber.Both)
OnEndPrivateCallRequest(Int64.Parse((tempArray[4].Split('.'))[2]), tempArray[5], Wireline.SlotNumber.Slot2);
//*/
break;
case (int)MessageBusCmds.EndGroupCall:
Utils.WriteLine(String.Format("--- End {0} for {1} [{2}]", "Group Call", Int64.Parse((tempArray[4].Split('.'))[2]), slot), ConsoleColor.White);
// trigger event for slot 1 even if both is selected
if (slot == Wireline.SlotNumber.Slot1 || slot == Wireline.SlotNumber.BothSlots)
OnEndGroupCallRequest(Int64.Parse((tempArray[4].Split('.'))[2]), tempArray[5], Wireline.SlotNumber.Slot1);
/*
// trigger event for slot 2 even if both is selected
if (slot == Wireline.SlotNumber.Slot2 || slot == Wireline.SlotNumber.Both)
OnEndGroupCallRequest(Int64.Parse((tempArray[4].Split('.'))[2]), tempArray[5], Wireline.SlotNumber.Slot2);
//*/
break;
}
}
#endregion
#region CHANNEL QUERY
else if (opertationCode == (int)MessageBusCmds.ChannelQueryRequest)
{
int radiogwid_recv = 0;
Int32.TryParse((tempArray[4].Split('.'))[1], out radiogwid_recv);
foreach (RadioGateway radio in MotoRepeater_GW.radioGWs)
{
if (radio.Id == radiogwid_recv)
{
OnChannelQueryRequest(radiogwid_recv);
}
}
}
#endregion
#region SMS REQUEST
else if (opertationCode == (int)MessageBusCmds.SendSMSRequest || opertationCode == (int)MessageBusCmds.SendSMSRequest2)
{
int sms_seq_id;
// Console.WriteLine("SMSSendThread received from multicast bus: " + str.Trim());
int sched_timeGMT = 0;
if (tempArray.Length > 6)
sched_timeGMT = Convert.ToInt32(tempArray[6]);
// Console.WriteLine("SMS sched time={0} and current time ={1}",sched_timeGMT, DBmanager.DateTo70Format(DateTime.Now.ToUniversalTime()));
if (sched_timeGMT <= DateTime.Now.ToUniversalTime().DateTo70Format())
{
String IMEI = (tempArray[4].Split('.'))[2];
sms_seq_id = SMSConfirm.addToConfirmationQueue(tempArray[2]);
// Console.WriteLine("SMSSendThread received from multicast bus: " + str.Trim());
if ((sms_seq_id != -1) && wait4ack)
{
Utils.WriteLine("««« SMS ACK with header [" + sms_seq_id + "]");
// trigger the event
OnSMSRequestReceived(IMEI, tempArray[5], true, sms_seq_id);
}
else
{
Utils.WriteLine("««« SMS without ACK");
// trigger the event
OnSMSRequestReceived(IMEI, tempArray[5], false, sms_seq_id);
byte[] buf = SafeMobileLib.Utils.Convert_text_For_multicast("#" + tempArray[2] + "#242#1#");
//send SMS ack
SendOnMessageBus(buf, buf.Length);
}
}
//}
}
#endregion
#region SMS GROUP REQUEST
else if (opertationCode == (int)MessageBusCmds.SendGroupSMSRequest || opertationCode == (int)MessageBusCmds.SendGroupSMSRequest2)
{
int sms_seq_id;
// Console.WriteLine("SMSSendThread received from multicast bus: " + str.Trim());
int sched_timeGMT = 0;
if (tempArray.Length > 6)
sched_timeGMT = Convert.ToInt32(tempArray[6]);
if (sched_timeGMT <= DateTime.Now.ToUniversalTime().DateTo70Format())
{
SM.Debug("««« Group SMS without ACK [" + tempArray[5] + "] to " + tempArray[4]); //+ " received... sending it to radio");
String cpsID = (tempArray[4].Split('.'))[2];
sms_seq_id = SMSConfirm.addToConfirmationQueue(tempArray[2]);
// trigger the event
OnGroupSMSRequestReceived(cpsID, tempArray[5], true, sms_seq_id);
byte[] buf = SafeMobileLib.Utils.Convert_text_For_multicast("#" + tempArray[2] + "#244#1#");
//send SMS ack
SendOnMessageBus(buf, buf.Length);
}
//}
}
#endregion
}
#endregion
#region DESIGNATED FOR ALL GATEWAYS
else
{
if (opertationCode == (int)MessageBusCmds.TelemetryRequest)
{
//Utils.WriteLine("TelemetrySend thread received data from multicast bus");
String seqId = tempArray[2];
int transactionID = TelemetryConfirm.addToConfirmationQueue(seqId);
String radioID = (tempArray[4].Split('.'))[2];
String[] temp = tempArray[5].Split('.');
if (temp.Length == 2)
{
String gpio = temp[0];
String type = temp[1];
OnTelemetryRequestReceived(radioID, gpio, type, transactionID);
}
}
}
#endregion
}
}
catch (Exception ex)
{
SM.Debug(ex.ToString());
}
}
/// <summary>
/// Get the database id from the selected slot.
/// </summary>
/// <param name="slot">Slot number for which the db is required</param>
/// <returns>A integer value representing the database id of the slot</returns>
private int GetDB4RadioGateway(Wireline.SlotNumber slot)
{
foreach (RadioGateway rgw in MotoRepeater_GW.radioGWs)
if (rgw.Imei == (int)slot)
return rgw.Id;
return 0;
}
public void SendEmergencyReceived(Int64 radioID)
{
string msg = "#" + (int)MessageBusCmds.RadioEmergencyReceived + "#" + radioID + "#";
// add message length and # header
SendOnMsgBuss(msg);
}
public void RadioEnableDisableStatusBroadcast(Int64 radioID, bool isEnable)
{
string msg = "#" + (int)MessageBusCmds.RadioEnableDisableStatusBroadcast + "#" + radioID + "#" + (isEnable ? "1" : "0") + "#";
SendOnMsgBuss(msg);
}
public void CallStatusBroadcast(Int64 sourceID, Int64 targetID, int callType, int callStatus, Wireline.SlotNumber slot)
{
string msg = "#" + (int)MessageBusCmds.CallStatusBroadcast + "#" + MotoRepeater_GW.cfg.GWID + "." + GetDB4RadioGateway(slot) + "." + sourceID + "#" + callStatus + "#"
+ callType + "#" + targetID + "#";
SendOnMsgBuss(msg);
}
public void SendARS(Int64 radioID, ARSStatus arsStatus)
{
string msg = "#" + (int)MessageBusCmds.ARSReceived + "#" + radioID + "#" + arsStatus.ToString() + "#";
SendOnMsgBuss(msg);
}
public void SendAssignedGwForRadio(Int64 radioID)
{
// get the radio gateway of one station
string radioGWIP = "127.0.0.1";
if (MotoRepeater_GW.radioGWs.Count > 0)
radioGWIP = MotoRepeater_GW.radioGWs[0].Ip;
string msg = "#" + (int)MessageBusCmds.SubscriberGatewayUpdate + "#" + MotoRepeater_GW.cfg.GWID + "#" + radioGWIP + "#" + radioID + "#";
SendOnMsgBuss(msg);
}
public void SendGPS(string radioID, uint date70format, string speed, string lat, string lng, int poll)
{
String[] toSendString = new String[4];
toSendString[0] = date70format.ToString();
toSendString[1] = speed;
toSendString[2] = lat;
toSendString[3] = lng;
byte[] toSendMulticast = createLocationMessage((poll == 0) ? (int)MessageBusCmds.LocationReceived :
(int)MessageBusCmds.PollResponseReceived,
radioID, toSendString);
SendOnMessageBus(toSendMulticast, toSendMulticast.Length);
//Utils.WriteLine("Location manager successfully sent data to message bus");
//SM.DebugSharp("+++ TX Multicast from Location manager " + toSendMulticast);
}
public void SendLocation(Int64 radioID, DateTime date, int speed, double lat, double lng, bool isPoll)
{
String[] toSendString = new String[4];
toSendString[0] = date.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds + "";
Utils.WriteLine("POSITION AFTER CONV BEFORE MB IS : " + toSendString[0]);
toSendString[1] = speed.ToString();
toSendString[2] = lat.ToString();
toSendString[3] = lng.ToString();
byte[] toSendMulticast = createLocationMessage((isPoll) ? (int)MessageBusCmds.PollResponseReceived :
(int)MessageBusCmds.LocationReceived,
radioID.ToString(), toSendString);
SendOnMessageBus(toSendMulticast, toSendMulticast.Length);
//Utils.WriteLine("Location manager successfully sent data to message bus");
}
public void SendSMS(Int64 radioID, string message)
{
string msg = "#" + (int)MessageBusCmds.SMSReceived + "#" + radioID + "#" + message + "#hyt#";
SendOnMsgBuss(msg);
}
public void SendSMS(Int64 radioID, byte[] receivedBytes)
{
SendOnMsgBuss(Utils.createMulticastMessage((int)MessageBusCmds.SMSReceived, radioID.ToString(), receivedBytes));
}
/// <summary>
/// Send the telemetry received bytes on the message bus
/// </summary>
/// <param name="radioID">Radio ID which sent the Telemetry message</param>
/// <param name="receivedBytes">Containing bytes of the Telemetry message</param>
public void SendTelemetry(Int64 radioID, byte[] receivedBytes)
{
SendOnMsgBuss(Utils.createMulticastMessage((int)MessageBusCmds.TelemetryReceived, radioID.ToString(), receivedBytes));
}
/// <summary>
/// Send telemetry on the message bus. The message is already parsed here,
/// so the flag hyt has to be used
/// </summary>
/// <param name="radioID">Radio ID which sent the Telemetry message</param>
/// <param name="GPIO">GPIO pin which raised the event</param>
public void SendParsedTelemetry(String radioID, string GPIO)
{
string msg = "#" + (int)MessageBusCmds.TelemetryReceived + "#" + radioID + "#" + GPIO + "#hyt#";
SendOnMsgBuss(msg);
}
/// <summary>
/// Send a byte array on the message bus
/// </summary>
/// <param name="data">Data which needs to be sent on the message bus</param>
public void SendOnMsgBuss(byte[] data)
{
SendOnMessageBus(data, data.Length);
}
/// <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 SendOnMsgBuss(string commandMsg)
{
String seqID = "1." + (Utils.GetSecondsLocalFromDT(DateTime.Now)) + DateTime.Now.Millisecond.ToString();
byte[] buf = SafeMobileLib.Utils.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);
Utils.WriteLine(String.Format("+++ MB [{0}] ", Utils.ConvertBytesToString(message)), ConsoleColor.White);
}
else
{
SM.Debug("••• Could not send on MB, it is null");
}
}
public void sendChannelBroadcastMessage(Int64 radioGWID)
{
int zoneNr = 1;
int channelNr = 1;
SendOnMsgBuss(String.Format("#{0}#{1}.{2}#{3}.{4}#", (int)MessageBusCmds.ChannelBroadcast, MotoRepeater_GW.cfg.GWID, radioGWID,zoneNr, channelNr));
}
//utils
public static Byte[] createLocationMessage(int opCode, string suid, String[] dataString)
{
string msg = "";
msg = "#1." + (Utils.GetSecondsLocalFromDT(DateTime.Now)) + DateTime.Now.Millisecond.ToString() + "#" + opCode + "#" + suid + "#";
msg = msg + dataString[0] + "#" + dataString[1] + "#" + dataString[2] + "#" + dataString[3];
int totalSize = 5 + msg.Length;
string sizeMsg = String.Format("#{0:000}", totalSize);
msg = sizeMsg + msg;
//Utils.WriteLine(String.Format("+++ MB {0}", msg));
//SM.Debug("TX(multi):" + msg, false);
Byte[] toSendMulticast = new Byte[totalSize];
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
Byte[] toSendMulticastPartial = encoding.GetBytes(msg);
for (int i = 0; i < toSendMulticastPartial.Length; i++)
{
toSendMulticast[i] = toSendMulticastPartial[i];
}
toSendMulticast[totalSize - 1] = 35;//'#'
return toSendMulticast;
}
private static DateTime UnixTimeStampToDateTime(double unixTimeStamp)
{
// Unix timestamp is seconds past epoch
System.DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
dtDateTime = dtDateTime.AddSeconds(unixTimeStamp).ToLocalTime();
return dtDateTime;
}
private static double DateTimeToUnixTimestamp(DateTime dateTime)
{
return (dateTime - new DateTime(1970, 1, 1).ToLocalTime()).TotalSeconds;
}
#region EVENTS REGION
public delegate void PollRequest(Int64 radioID);
public event PollRequest OnPollRequest;
public delegate void EmergencyAck(Int64 radioID, Wireline.SlotNumber slot);
public event EmergencyAck OnEmergencyAckRequest;
public delegate void RadioEnableDisableRequest(Int64 radioID, bool enable, Wireline.SlotNumber slot);
public event RadioEnableDisableRequest OnRadioEnableDisableRequest;
public delegate void ChannelQueryReceived(Int64 radioGWID);
public event ChannelQueryReceived OnChannelQueryRequest;
public delegate void InitPrivateCallRequest(Int64 radioID, String broadcastAddress, Wireline.SlotNumber slot);
public event InitPrivateCallRequest OnInitPrivateCallRequest;
public delegate void EndPrivateCallRequest(Int64 radioID, String broadcastAddress, Wireline.SlotNumber slot);
public event EndPrivateCallRequest OnEndPrivateCallRequest;
public delegate void InitGroupCallRequest(Int64 groupID, String broadcastAddress, Wireline.SlotNumber slot);
public event InitGroupCallRequest OnInitGroupCallRequest;
public delegate void EndGroupCallRequest(Int64 groupID, String broadcastAddress, Wireline.SlotNumber slot);
public event EndGroupCallRequest OnEndGroupCallRequest;
public delegate void InitAllCallRequest(String broadcastAddress, Wireline.SlotNumber slot);
public event InitAllCallRequest OnInitAllCallRequest;
public delegate void EndAllCallRequest(String broadcastAddress, Wireline.SlotNumber slot);
public event EndAllCallRequest OnEndAllCallRequest;
public delegate void SMSRequestReceived(String radioID, String message, Boolean isAckWanted, int seqID);
public event SMSRequestReceived OnSMSRequestReceived;
public delegate void GroupSMSRequestReceived(String groupID, String message, Boolean isAckWanted, int seqID);
public event GroupSMSRequestReceived OnGroupSMSRequestReceived;
public delegate void TelemetryRequestReceived(String radioID, String GPIO, String type, int seqID);
public event TelemetryRequestReceived OnTelemetryRequestReceived;
#endregion
}
}