using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; using SafeMobileLib; using System.Threading; using SafeMobileLib.MessageDecoders; namespace MotoRepeater { public class DataBaseSN : DataBaseInterface { private DBconnThread dbConnection; public static Thread DBThreadobjARS = null; public static Thread DBThreadobjGPS = null; public static Thread DBThreadobjAux = null; public static Thread DBThreadobjSMS = null; public static Thread DBThreadobjSMS_conf = null; public static Thread DBThreadobjAddr = null; public static Thread DBThreadobjPOLL = null; public static Thread DBThreadobjTallysman = null; private Thread checkUpdateInQueue = null; public static InterthreadMessageQueue tallysmanEventsQueue = new InterthreadMessageQueue(); /// /// Default Constructor /// public DataBaseSN() { /*string MyConString = "SERVER=" + MotoRepeater_GW.cfg.DB_SERVER + "; " + "DATABASE=" + MotoRepeater_GW.cfg.DB_DATABASE + "; " + "UID=" + MotoRepeater_GW.cfg.DB_USERNAME + "; " + "PASSWORD=" + MotoRepeater_GW.cfg.DB_PASSWORD + "; Pooling=true;max pool size = 100";*/ dbConnection = new DBconnThread(MotoRepeater_GW.cfg.DB_SERVER, MotoRepeater_GW.cfg.DB_DATABASE, MotoRepeater_GW.cfg.DB_USERNAME, MotoRepeater_GW.cfg.DB_PASSWORD, MotoRepeater_GW.cfg.GWCODE + ""); dbConnection.StartDB(); // start the threads which will bring the list of smss, polls, etc StartDBService(); checkUpdateInQueue = new Thread(delegate() { while (MotoRepeater_GW.isRunning) { CheckForPollRequests(); Thread.Sleep(50); CheckForSMSRequests(); Thread.Sleep(950); } }); checkUpdateInQueue.Start(); /* // add event listener for when a Poll request is received mBus.OnPollRequest += delegate(Int64 radioID) { PollRequestEventArgs e = new PollRequestEventArgs(); e.RadioID = radioID; // raise the event OnPollRequestReceived(null, e); }; // add event listener for when a radio needs to be enabled/disabled mBus.OnRadioEnableDisableRequest += delegate(Int64 radioID, bool enable, Wireline.SlotNumber slot) { RadioEnableDisableRequestEventArgs e = new RadioEnableDisableRequestEventArgs(); e.Enabled = enable; e.RadioID = radioID; e.Slot = slot; // raise the event this.OnRadioEnableDisableRequest(null, e); }; mBus.OnEmergencyAckRequest += delegate(Int64 radioID, Wireline.SlotNumber slot) { EmergencyAckEventArgs e = new EmergencyAckEventArgs(); e.RadioID = radioID; e.Slot = slot; // raise the event this.OnEmergencyAckRequest(null, e); }; mBus.OnChannelQueryRequest += delegate(Int64 radioGWID) { ChannelQueryEventArgs e = new ChannelQueryEventArgs(); e.RadioGwID = radioGWID; // raise the event OnChannelQuery(null, e); }; #region PRIVATECALL // intercept events for Private Call mBus.OnInitPrivateCallRequest += delegate(Int64 radioID, string broadcastAddress, Wireline.SlotNumber slot) { this.OnInitPrivateCallRequest(radioID, broadcastAddress, slot); }; mBus.OnEndPrivateCallRequest += delegate(Int64 radioID, string broadcastAddress, Wireline.SlotNumber slot) { this.OnEndPrivateCallRequest(radioID, broadcastAddress, slot); }; #endregion #region GROUPCALL // intercept events for Group Call mBus.OnInitGroupCallRequest += delegate(Int64 groupID, string broadcastAddress, Wireline.SlotNumber slot) { this.OnInitGroupCallRequest(groupID, broadcastAddress, slot); }; mBus.OnEndGroupCallRequest += delegate(Int64 groupID, string broadcastAddress, Wireline.SlotNumber slot) { this.OnEndGroupCallRequest(groupID, broadcastAddress, slot); }; #endregion #region ALLCALL // intercept events for All Call mBus.OnInitAllCallRequest += delegate(string broadcastAddress, Wireline.SlotNumber slot) { this.OnInitAllCallRequest(broadcastAddress, slot); }; mBus.OnEndAllCallRequest += delegate(string broadcastAddress, Wireline.SlotNumber slot) { this.OnEndAllCallRequest(broadcastAddress, slot); }; #endregion */ } public void PollResponseReceived(long radioID, DateTime locationTime, int speed, double latitude, double longitude, Int64 seqID) { htCell_t cell = new htCell_t(); cell.suid = radioID + ""; cell.d_lat = latitude; cell.d_lng = longitude; cell.seqID = seqID; cell.lat = latitude + ""; cell.lng = longitude + ""; cell.spd = speed+""; cell.location_time = locationTime; lock (SN_Queues.ht_POLL_List.SyncRoot) { foreach (DictionaryEntry item in SN_Queues.ht_POLL_List) { Utils.WriteLine("REQ " + ((POLLmsg)item.Value).requestID + " | seqID " + seqID , ConsoleColor.Red); // check to see if this poll will ACK a poll request if (((POLLmsg)item.Value).requestID == seqID) { ((POLLmsg)item.Value).response = cell.location_time; ((POLLmsg)item.Value).lat = cell.lat; ((POLLmsg)item.Value).lng = cell.lng; ((POLLmsg)item.Value).speed = cell.spd; // add position to the queue SN_Queues.DBQueueLocation.PostItem(cell); // add poll to the queue SN_Queues.recvPOLLQueue.PostItem((POLLmsg)item.Value); SN_Queues.ht_POLL_List.Remove(item); break; } } // remove poll from pending list lock (SafeMobileLib.SN_Queues.ht_pendingMsg.SyncRoot) { try { Hashtable tmp = new Hashtable(); foreach (DictionaryEntry de in SafeMobileLib.SN_Queues.ht_pendingMsg) { MotoTRBOcmdMsg m = (MotoTRBOcmdMsg)de.Value; // add message in the pending hash is the response is stil not received if (m.m_seqID != seqID) tmp.Add(m.m_seqID, m); } SafeMobileLib.SN_Queues.ht_pendingMsg = tmp; lastHashVerify = DateTime.Now; } catch (Exception e) { //LOGS.LOG("Error: cannot reset pending messages HashTable" + e.ToString(), ConsoleColor.Red); } }//release lock } } public void LocationResponseReceived(long radioID, DateTime locationTime, int speed, double latitude, double longitude) { htCell_t cell = new htCell_t(); cell.suid = radioID + ""; cell.d_lat = latitude; cell.d_lng = longitude; cell.lat = latitude + ""; cell.lng = longitude + ""; cell.spd = speed + ""; cell.location_time = locationTime; // add location to the queue SN_Queues.DBQueueLocation.PostItem(cell); } public void LocationReceived(LocationEventArgs e) { htCell_t cell = new htCell_t(); cell.suid = e.RadioID+""; cell.d_lat = e.Latitude; cell.d_lng = e.Longitude; cell.lat = e.Latitude + ""; cell.lng = e.Longitude + ""; cell.spd = e.Speed + ""; cell.location_time = (new DateTime(1970, 1, 1)).AddSeconds(e.GPSTime); //Utils.UnixTimeStampToDateTime(e.Time); // add level of confidence only if received if (e.LevelOfConfidence > -1) cell.level_confidence = (int)e.LevelOfConfidence; // add location to the queue SN_Queues.DBQueueLocation.PostItem(cell); } public void ARSStateReceived(long radioID, bool isON) { try { ArsMSG ars = new ArsMSG(); ars.imei = radioID+""; ars.msg = isON ? "ON" : "OFF"; SN_Queues.arsMsgQueue.PostItem(ars); } catch (Exception e) { Utils.WriteLine("ERROR ARS " + e.ToString()); } } // radioID is equal with the suID public void SMSReceived(long radioID, byte[] received) { // NOT IN SAFENET } public void SMSReceived(long radioID, string message) { bool result = dbConnection.DB.insertSMSinDB("" + radioID, message); if(!result) { Utils.WriteLine("COULD NOT INSERT SMS", ConsoleColor.Red); } else Utils.WriteLine("SMS INSERTED", ConsoleColor.Gray); } public void SMSAckReceived(byte[] received, string seq_no) { Utils.WriteLine("»»» SMS ACK with sequence nr. " + seq_no); lock (SN_Queues.waitConfSMSList.SyncRoot) { int index = -1; int count = 0; foreach (SMSmsg msg in SN_Queues.waitConfSMSList) { Int16 seqNo = 0; Int16.TryParse(seq_no, out seqNo); if (msg.seq_no == seqNo) { index = count; SN_Queues.confSMSQueue.PostItem(msg); } count++; } if (index > -1) //we've found the message SN_Queues.waitConfSMSList.RemoveAt(index); } } public void TelemetryReceived(long radioID, byte[] received) { // NOT IN SAFENET } public void TelemetryReceived(TelemetryReceivedEventArgs telemetryArgs) { // NOT IN SAFENET } public void RadioEnableDisableStatusReceived(long radioID, Wireline.SlotNumber slot, bool isEnabled) { //mBus.RadioEnableDisableStatusBroadcast(radioID, isEnabled); } public void EmergencyReceived(long radioID, Wireline.SlotNumber slot) { //mBus.SendEmergencyReceived(radioID); } public void CallStatusBroadcastReceived(long sourceID, long targertID, CallType callType, CallStatus callStatus, Wireline.SlotNumber slot) { //mBus.CallStatusBroadcast(sourceID, targertID, (int)callType, (int)callStatus, slot); } public void TallysmanEventReceived(TallysmanEventArgs tallysmanArgs) { // add received event to a queue tallysmanEventsQueue.PostItem(tallysmanArgs); } public void SendChannelBroadcastMessage(long radioGWID) { //mBus.sendChannelBroadcastMessage(radioGWID); } public void Stop() { StopDBService(); } /// /// Start threads and database connections /// void StartDBService() { try { dbConnection.OnGPSInsertedBlocked += delegate () { OnGPSInsertedBlocked?.Invoke(); DBThreadobjGPS?.Abort(); DBThreadobjGPS = null; DBThreadobjGPS = new Thread(new ThreadStart(dbConnection.HandleConnectionGPS)); DBThreadobjGPS.IsBackground = true; DBThreadobjGPS.Start(); }; //Start GPS DB thread DBThreadobjGPS = new Thread(new ThreadStart(dbConnection.HandleConnectionGPS)); DBThreadobjGPS.IsBackground = true; DBThreadobjGPS.Start(); Thread.Sleep(200); //Start ARS DB thread DBThreadobjARS = new Thread(new ThreadStart(dbConnection.HandleConnectionARS)); DBThreadobjARS.IsBackground = true; DBThreadobjARS.Start(); Thread.Sleep(200); //Start Units DB thread DBThreadobjAux = new Thread(new ThreadStart(dbConnection.HandleConnectionAux)); DBThreadobjAux.IsBackground = true; DBThreadobjAux.Start(); Thread.Sleep(200); //Start SMS DB thread DBThreadobjSMS = new Thread(new ThreadStart(dbConnection.HandleConnectionSMS)); DBThreadobjSMS.IsBackground = true; DBThreadobjSMS.Start(); Thread.Sleep(200); //Start SMS DB thread DBThreadobjSMS_conf = new Thread(new ThreadStart(dbConnection.HandleConnectionSMS_conf)); DBThreadobjSMS_conf.IsBackground = true; DBThreadobjSMS_conf.Start(); Thread.Sleep(200); //Start Addres insert thread DBThreadobjAddr = new Thread(new ThreadStart(dbConnection.HandleConnectionAddr)); DBThreadobjAddr.IsBackground = true; //DBThreadobjAddr.Start(); Thread.Sleep(200); //Start POLL thread DBThreadobjPOLL = new Thread(new ThreadStart(dbConnection.HandleConnectionPOLL)); DBThreadobjPOLL.IsBackground = true; DBThreadobjPOLL.Start(); Thread.Sleep(200); //Start Tallysman thread DBThreadobjTallysman = new Thread(new ThreadStart(dbConnection.HandleTallysmanEvents)); DBThreadobjTallysman.IsBackground = true; DBThreadobjTallysman.Start(); Thread.Sleep(200); } catch (Exception e) { Utils.WriteLine("Could not intialize the connection with location server!\r\n" + e.Message + "\r\nPlease check your internet connection !!", ConsoleColor.Red); //System.Environment.Exit(1); } } /// /// Stop all threads and database connections /// private void StopDBService() { if (dbConnection != null) { dbConnection.StopDB(); } if (DBThreadobjARS != null) { DBThreadobjARS.Abort(); } if (DBThreadobjGPS != null) { DBThreadobjGPS.Abort(); } if (DBThreadobjAux != null) { DBThreadobjAux.Abort(); } if (DBThreadobjSMS != null) { DBThreadobjSMS.Abort(); } if (DBThreadobjSMS_conf != null) { DBThreadobjSMS_conf.Abort(); } if (DBThreadobjAddr != null) { DBThreadobjAddr.Abort(); } if (DBThreadobjPOLL != null) { DBThreadobjPOLL.Abort(); } if (DBThreadobjTallysman != null) { DBThreadobjTallysman.Abort(); } } #region POLL REQUESTS MANAGEMENT private int reqID_send = 0; private DateTime lastHashVerify = DateTime.Now; private void CheckForPollRequests() { MotoTRBOcmdMsg msg = SN_Queues.locationQueue.GetItem(100); if (msg != null) { //Console.WriteLine("Processing command"); //Console.WriteLine("SN_Queues.locationQueue.Count:" + SN_Queues.locationQueue.Count); ProcessPollCommand(msg); //this will update the m_seqID and m_time SafeMobileLib.SN_Queues.ht_pendingMsg.Add(msg.m_seqID, msg); msg = null; //Console.WriteLine("Processing end"); } //is now answer within 30 secconds resend if (SafeMobileLib.SN_Queues.ht_pendingMsg.Count > 0) { if ((DateTime.Now.Ticks - lastHashVerify.Ticks) > 5 * 1000 * 10000) { lock (SafeMobileLib.SN_Queues.ht_pendingMsg.SyncRoot) { try { Hashtable tmp = new Hashtable(); //Utils.WriteLine("GPS answers check at :" + DateTime.Now); foreach (DictionaryEntry de in SafeMobileLib.SN_Queues.ht_pendingMsg) { MotoTRBOcmdMsg m = (MotoTRBOcmdMsg)de.Value; // resend after 30 seconds if no response received if (DateTime.Now.Ticks - m.m_created.Ticks > 180 * 1000 * 10000) { //Utils.WriteLine("I CAN DELETE postItem", ConsoleColor.Cyan); // do not add the message again in the queue } else if (DateTime.Now.Ticks - m.m_created.Ticks > 30 * 1000 * 10000) { if (DateTime.Now.Ticks - m.m_time.Ticks > 30 * 1000 * 10000) { //Utils.WriteLine("I HAVE TO RESEND MESSAGE", ConsoleColor.Magenta); m.m_cmd = (byte)MotoTRBOcmd.SEND_POLL; //LOGS.LOG("PUT back in ht_pendingMsg :" + m.m_suid); //Utils.WriteLine("PUT back in ht_pendingMsg :" + m.m_suid); SN_Queues.locationQueue.PostItem(m); } else tmp.Add(m.m_seqID, m); } else tmp.Add(m.m_seqID, m); } SafeMobileLib.SN_Queues.ht_pendingMsg = tmp; lastHashVerify = DateTime.Now; } catch (Exception e) { //LOGS.LOG("Error: cannot reset pending messages HashTable" + e.ToString(), ConsoleColor.Red); } }//release lock //LOGS.LOG("Debug: UN-LOCK1"); } } } /// /// Process a poll request which needs to be send and then added to /// the Poll Hashtable where all the pending requests are stored /// /// A custom message containing the poll values private void ProcessPollCommand(MotoTRBOcmdMsg p_msg) { try { reqID_send++; if (reqID_send == byte.MaxValue) reqID_send = 1; p_msg.m_seqID = BitConverter.ToInt32(new byte[] { (byte)reqID_send, 0xAC, 0x68, 0x24 }, 0); p_msg.m_time = DateTime.Now; if (p_msg.m_cmd == (byte)MotoTRBOcmd.SEND_POLL) { PollRequestEventArgs e = new PollRequestEventArgs(); e.RadioID = p_msg.m_suid; e.SeqID = reqID_send; OnPollRequestReceived(null, e); //SendPollRequest(p_msg.m_suid, reqID_send); //Utils.ConsWrite(DebugMSG_Type.GPS, "Poll request sent for unit:" + p_msg.m_suid); lock (SN_Queues.ht_POLL_List.SyncRoot) { foreach (DictionaryEntry item in SN_Queues.ht_POLL_List) { try { if (((POLLmsg)item.Value).suid == p_msg.m_suid && ((POLLmsg)item.Value).DBid.ToString() == p_msg.m_payload) { ((POLLmsg)item.Value).sent = DateTime.Now.ToUniversalTime(); ((POLLmsg)item.Value).requestID = 0x24*256*256*256 + 0x68*256*256 + 0xAC*256 + reqID_send; //Utils.WriteLine("ADDED POLL WITH REQID : " + ((POLLmsg)item.Value).requestID + " [0x24 0x68 0xAC 0x" + reqID_send + "]", ConsoleColor.Cyan); //Utils.ConsWrite(DebugMSG_Type.DB, "Poll request found in MotoTRBOGW.ht_POLL_List for unit:" + p_msg.m_suid); //Utils.ConsWrite(DebugMSG_Type.DB, "reqID_send:" + reqID_send); SN_Queues.sentPOLLQueue.PostItem((POLLmsg)item.Value); break; } } catch (Exception ex) { Utils.WriteLine("ERROR in foreach (DictionaryEntry item in SN_Queues.ht_POLL_List):" + ex.ToString(), ConsoleColor.Red); } } } } } catch (Exception e) { Utils.WriteLine("Could not send Location Request to unit: " + e.ToString(), ConsoleColor.Red); } } #endregion #region SMS REQUESTS MANAGEMENT private int reqID_sms = 2; //private DateTime lastHashVerify = DateTime.Now; private void CheckForSMSRequests() { try { //MotoTRBOcmdMsg msg = MotoTRBOGW.locationQueue.GetItem(100); SMSmsg msg = SN_Queues.sendSMSQueue.GetItem(100);//block until message is in queue // exit if not message if (msg == null) return; // set the sequence number msg.seq_no = reqID_sms++; SMSRequestEventArgs e = new SMSRequestEventArgs(); e.RadioID = msg.suid; e.seqID = msg.seq_no; e.isACKWanted = msg.req_conf; e.message = msg.msg; // trigger event OnSMSRequestReceived(null, e); if (msg.req_conf) { //Utils.ConsWrite(DebugMSG_Type.SMS, "Requesting SMS Confirmation!!!!"); lock (SN_Queues.waitConfSMSList.SyncRoot) { msg.waitConfSMSList_time = DateTime.Now; SN_Queues.waitConfSMSList.Add(msg); } } Thread.Sleep(1200);//minimum interval between SMS as per MotoTRBO specs } catch (Exception ex) { Utils.WriteLine("MUST HANDLE THIS EXCEPTION : " + ex.ToString()); } } #endregion /// /// Get the reporting interval from the Database for a particular unit /// /// Radio Id of the unit for which /// public int GetReportingIntervalForUnit(string radioID) { int reportInterval = 60; if (SN_Queues.ht_SUInfo.ContainsKey(radioID)) reportInterval = ((SUinfo)SN_Queues.ht_SUInfo[radioID]).repInterval; else reportInterval = -1; return reportInterval; } public bool UnitIsAssignedToGw(string radioID) { if (SN_Queues.ht_SUInfo.ContainsKey(radioID)) return true; else return false; } #region EVENTS #region AUDIO EVENTS 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; #endregion #region POLL EVENT /// /// Events for Poll Request Received /// private object _lockPoll = new object(); public event EventHandler OnPollRequestReceived; event EventHandler DataBaseInterface.OnPollRequestReceived { add { lock (_lockPoll) { OnPollRequestReceived += value; } } remove { lock (_lockPoll) { OnPollRequestReceived -= value; } } } #endregion #region RADIO ENABLE DISABLE EVENT private object _lockRadioED = new object(); public event EventHandler OnRadioEnableDisableRequest; event EventHandler DataBaseInterface.OnRadioEnableDisableRequest { add { lock (_lockRadioED) { OnRadioEnableDisableRequest += value; } } remove { lock (_lockRadioED) { OnRadioEnableDisableRequest -= value; } } } #endregion #region EMERGENCY ACK EVENT private object _lockEmergencyAck = new object(); public event EventHandler OnEmergencyAckRequest; event EventHandler DataBaseInterface.OnEmergencyAckRequest { add { lock (_lockEmergencyAck) { OnEmergencyAckRequest += value; } } remove { lock (_lockEmergencyAck) { OnEmergencyAckRequest -= value; } } } #endregion #region CHANNEL QUERY EVENT private object _lockChannelQuery = new object(); public event EventHandler OnChannelQuery; event EventHandler DataBaseInterface.OnChannelQuery { add { lock (_lockChannelQuery) { OnChannelQuery += value; } } remove { lock (_lockChannelQuery) { OnChannelQuery -= value; } } } #endregion #region SMS REQUEST EVENT private object _lockSMSRequest = new object(); public event EventHandler OnSMSRequestReceived; event EventHandler DataBaseInterface.OnSMSRequestReceived { add { lock (_lockSMSRequest) { OnSMSRequestReceived += value; } } remove { lock (_lockSMSRequest) { OnSMSRequestReceived -= value; } } } #endregion #region GROUP SMS REQUEST EVENT private object _lockGroupSMSRequest = new object(); public event EventHandler OnGroupSMSRequestReceived; event EventHandler DataBaseInterface.OnGroupSMSRequestReceived { add { lock (_lockGroupSMSRequest) { OnGroupSMSRequestReceived += value; } } remove { lock (_lockGroupSMSRequest) { OnGroupSMSRequestReceived -= value; } } } #endregion #region TELEMETRY REQUEST EVENT private object _lockTelemetryRequest = new object(); public event EventHandler OnTelemetryRequestReceived; event EventHandler DataBaseInterface.OnTelemetryRequestReceived { add { lock (_lockTelemetryRequest) { OnTelemetryRequestReceived += value; } } remove { lock (_lockTelemetryRequest) { OnTelemetryRequestReceived -= value; } } } #endregion #endregion public delegate void GPSInsertedBlockedDel(); public event GPSInsertedBlockedDel OnGPSInsertedBlocked; } }