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()); } } /// /// Get the database id from the selected slot. /// /// Slot number for which the db is required /// A integer value representing the database id of the slot 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)); } /// /// Send the telemetry received bytes on the message bus /// /// Radio ID which sent the Telemetry message /// Containing bytes of the Telemetry message public void SendTelemetry(Int64 radioID, byte[] receivedBytes) { SendOnMsgBuss(Utils.createMulticastMessage((int)MessageBusCmds.TelemetryReceived, radioID.ToString(), receivedBytes)); } /// /// Send telemetry on the message bus. The message is already parsed here, /// so the flag hyt has to be used /// /// Radio ID which sent the Telemetry message /// GPIO pin which raised the event public void SendParsedTelemetry(String radioID, string GPIO) { string msg = "#" + (int)MessageBusCmds.TelemetryReceived + "#" + radioID + "#" + GPIO + "#hyt#"; SendOnMsgBuss(msg); } /// /// Send a byte array on the message bus /// /// Data which needs to be sent on the message bus public void SendOnMsgBuss(byte[] data) { SendOnMessageBus(data, data.Length); } /// /// Send a string on the message bus. The string will be converted into a byte array before /// beeing sent /// /// The message which needs to be sent on the message bus 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); } /// /// Send a byte array of a specific length on the message bus /// /// Data which needs to be sent on the message bus /// Data which needs to be sent on the message bus 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 } }