SafeDispatch/MotoRepeaterCore/DataBaseSN.cs

779 lines
29 KiB
C#
Raw Normal View History

2024-02-22 16:43:59 +00:00
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<TallysmanEventArgs> tallysmanEventsQueue
= new InterthreadMessageQueue<TallysmanEventArgs>();
/// <summary>
/// Default Constructor
/// </summary>
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();
}
/// <summary>
/// Start threads and database connections
/// </summary>
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);
}
}
/// <summary>
/// Stop all threads and database connections
/// </summary>
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");
}
}
}
/// <summary>
/// Process a poll request which needs to be send and then added to
/// the Poll Hashtable where all the pending requests are stored
/// </summary>
/// <param name="p_msg">A custom message containing the poll values</param>
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
/// <summary>
/// Get the reporting interval from the Database for a particular unit
/// </summary>
/// <param name="radioID">Radio Id of the unit for which </param>
/// <returns></returns>
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
/// <summary>
/// Events for Poll Request Received
/// </summary>
private object _lockPoll = new object();
public event EventHandler<PollRequestEventArgs> OnPollRequestReceived;
event EventHandler<PollRequestEventArgs> 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<RadioEnableDisableRequestEventArgs> OnRadioEnableDisableRequest;
event EventHandler<RadioEnableDisableRequestEventArgs> 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<EmergencyAckEventArgs> OnEmergencyAckRequest;
event EventHandler<EmergencyAckEventArgs> 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<ChannelQueryEventArgs> OnChannelQuery;
event EventHandler<ChannelQueryEventArgs> 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<SMSRequestEventArgs> OnSMSRequestReceived;
event EventHandler<SMSRequestEventArgs> 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<SMSRequestEventArgs> OnGroupSMSRequestReceived;
event EventHandler<SMSRequestEventArgs> 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<TelemetryRequestEventArgs> OnTelemetryRequestReceived;
event EventHandler<TelemetryRequestEventArgs> DataBaseInterface.OnTelemetryRequestReceived
{
add { lock (_lockTelemetryRequest) { OnTelemetryRequestReceived += value; } }
remove { lock (_lockTelemetryRequest) { OnTelemetryRequestReceived -= value; } }
}
#endregion
#endregion
public delegate void GPSInsertedBlockedDel();
public event GPSInsertedBlockedDel OnGPSInsertedBlocked;
}
}