1164 lines
46 KiB
C#
1164 lines
46 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Net.Sockets;
|
|
using System.Net;
|
|
using MySql.Data.MySqlClient;
|
|
using System.Collections;
|
|
using SafeNetLib;
|
|
using System.Diagnostics;
|
|
|
|
namespace ConnectPlus_SOC
|
|
{
|
|
class WatcherServerThread
|
|
{
|
|
private TcpClient client;
|
|
private IPEndPoint serverEndPoint;
|
|
private Thread listenThread;
|
|
private Thread intervalThread;
|
|
private Thread checkThread;
|
|
private Thread subscribThread;
|
|
private System.Threading.Timer tResendSub;
|
|
private System.Threading.Timer tResendGPS;
|
|
public static DateTime lastPingTime = DateTime.Now;
|
|
private NetworkStream clientStream;
|
|
byte[] message;
|
|
private string p_ctrIP;
|
|
private int port;
|
|
|
|
string connString;
|
|
string gwID;
|
|
string report;
|
|
int totalUsers;
|
|
|
|
public DateTime dt_lastSUB;
|
|
|
|
public static bool connDown = false;
|
|
|
|
private System.Timers.Timer checkForTime;
|
|
private int timerCount = 0;
|
|
|
|
public WatcherServerThread(string _ctrlIP, int port, string p_connString, string p_gwID, string p_report)
|
|
{
|
|
Utils.ConsWrite(DebugMSG_Type.CTRL, "WatcherServerThread Constructor");
|
|
message = new byte[128];
|
|
p_ctrIP = _ctrlIP;
|
|
this.port = port;
|
|
totalUsers = 0;
|
|
|
|
connString = p_connString;
|
|
gwID = p_gwID;
|
|
report = p_report;
|
|
|
|
checkForTime = new System.Timers.Timer(180 * 60 * 1000);
|
|
checkForTime.Elapsed += delegate(object sender, System.Timers.ElapsedEventArgs e)
|
|
{
|
|
Utils.WriteLine("Three hours elapsed, must check subscription again. [" + (++timerCount) + "]", ConsoleColor.Cyan );
|
|
SubscribeALL(1234);
|
|
};
|
|
checkForTime.Enabled = true;
|
|
}
|
|
|
|
public void Stop()
|
|
{
|
|
if (clientStream != null)
|
|
{
|
|
clientStream.Close();
|
|
}
|
|
if (listenThread.IsAlive)
|
|
{
|
|
listenThread.Abort();
|
|
}
|
|
|
|
if (intervalThread.IsAlive)
|
|
{
|
|
intervalThread.Abort();
|
|
}
|
|
|
|
if (checkForTime != null)
|
|
checkForTime.Stop();
|
|
}
|
|
|
|
public void Start()
|
|
{
|
|
try
|
|
{
|
|
IPAddress ctrIP = null;
|
|
if (!IPAddress.TryParse(ConnectPlus_GW.cfg.ctrlIP, out ctrIP))
|
|
{
|
|
ctrIP = Dns.GetHostAddresses(ConnectPlus_GW.cfg.ctrlIP)[0];
|
|
Utils.ConsWrite(DebugMSG_Type.always, "Host name : " + ConnectPlus_GW.cfg.ctrlIP + " IP:" + ctrIP.ToString());
|
|
}
|
|
if (ctrIP == null)
|
|
{
|
|
Utils.ConsWrite(DebugMSG_Type.always, "Location Thread invalid host address for: " + ConnectPlus_GW.cfg.ctrlIP);
|
|
}
|
|
|
|
client = new TcpClient();
|
|
serverEndPoint = new IPEndPoint(ctrIP, port);
|
|
//client.Connect(serverEndPoint);
|
|
client.Connect(ConnectPlus_GW.cfg.ctrlIP, port);
|
|
Utils.ConsWrite(DebugMSG_Type.CTRL, "WatcherServerThread connected on " + ConnectPlus_GW.cfg.ctrlIP + ":" + port);
|
|
clientStream = client.GetStream();
|
|
if (clientStream != null)
|
|
{
|
|
//set read timeout to 35 seconds, according to Motorola Connect Plus PN_Watcher specifications
|
|
clientStream.ReadTimeout = 35000;
|
|
connDown = false;
|
|
}
|
|
else
|
|
{
|
|
connDown = true;
|
|
Utils.ConsWrite(DebugMSG_Type.always, "WatcherServerThread -> clientStream==null");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
//Utils.ConsWrite(DebugMSG_Type.always, "Erorr WatcherServerThread connecting to " + ConnectPlus_GW.cfg.ctrlIP + " \n" + ex.ToString());
|
|
Utils.WriteLine("Error connecting to the controller " + ConnectPlus_GW.cfg.ctrlIP + Environment.NewLine + ex.ToString(), ConsoleColor.Red);
|
|
connDown = true;
|
|
}
|
|
|
|
|
|
listenThread = new Thread(new ThreadStart(HandleClientComm));
|
|
listenThread.IsBackground = true;
|
|
listenThread.Start();
|
|
Utils.ConsWrite(DebugMSG_Type.CTRL, "============ WatcherServerThread Listenning ============");
|
|
|
|
intervalThread = new Thread(new ThreadStart(HandleInterval));
|
|
intervalThread.IsBackground = true;
|
|
intervalThread.Start();
|
|
|
|
checkThread = new Thread(new ThreadStart(CheckLastPing));
|
|
checkThread.IsBackground = true;
|
|
checkThread.Start();
|
|
|
|
subscribThread = new Thread(new ParameterizedThreadStart(SubscribeALLinDB_del));
|
|
subscribThread.IsBackground = true;
|
|
|
|
tResendSub = new System.Threading.Timer(ResendSUB, null, new TimeSpan(1, 0, 0), new TimeSpan(1, 0, 0));
|
|
tResendGPS = new System.Threading.Timer(ResendGPS, null, new TimeSpan(0, 1, 0), new TimeSpan(0, 1, 0));
|
|
|
|
|
|
new Thread(delegate()
|
|
{
|
|
Thread.Sleep(30000);
|
|
while (true)
|
|
{
|
|
Console.ForegroundColor = ConsoleColor.Red;
|
|
Console.Write("WRITING FAKE SUBSCRIBE MESSAGE");
|
|
Console.ForegroundColor = ConsoleColor.Gray;
|
|
|
|
|
|
byte[] bytesToSend = new byte[72] {0x04, 0x01, 0x00, 0x03, 0x01, 0x02, 0x0a, 0x08, 0x31,
|
|
0x00, 0x30, 0x00, 0x38, 0x00, 0x39, 0x00, 0x02, 0x02, 0x32, 0x00, 0x0e, 0x02, 0x32, 0x00,
|
|
|
|
0x04, 0x01, 0x00, 0x03, 0x01, 0x02, 0x0a, 0x08, 0x31, 0x00, 0x30, 0x00, 0x38, 0x00, 0x36, 0x00, 0x02, 0x02,
|
|
0x32, 0x00, 0x0e, 0x02, 0x32, 0x00,
|
|
|
|
0x04, 0x01, 0x00, 0x03, 0x01, 0x02, 0x0a, 0x08, 0x31, 0x00, 0x30, 0x00, 0x38, 0x00, 0x34, 0x00,
|
|
0x02, 0x02, 0x32, 0x00, 0x0e, 0x02, 0x32, 0x00};
|
|
|
|
Decode(bytesToSend, 72);
|
|
Thread.Sleep(15000);
|
|
}
|
|
|
|
});//.Start();
|
|
}
|
|
|
|
public void RestartTCP()
|
|
{
|
|
Utils.ConsWrite(DebugMSG_Type.always, "\n\n\n\n RESTART TCP \n\n\n\n");
|
|
|
|
try
|
|
{
|
|
IPAddress ctrIP = null;
|
|
if (!IPAddress.TryParse(ConnectPlus_GW.cfg.ctrlIP, out ctrIP))
|
|
{
|
|
ctrIP = Dns.GetHostAddresses(ConnectPlus_GW.cfg.ctrlIP)[0];
|
|
Utils.ConsWrite(DebugMSG_Type.always, "Host name : " + ConnectPlus_GW.cfg.ctrlIP + " IP:" + ctrIP.ToString());
|
|
}
|
|
if (ctrIP == null)
|
|
{
|
|
Utils.ConsWrite(DebugMSG_Type.always, "Reconnecting to controlle invalid host address for: " + ConnectPlus_GW.cfg.ctrlIP);
|
|
}
|
|
|
|
//add gateway status!!
|
|
GWstatus gws = new GWstatus();
|
|
gws.gw_id = gwID;
|
|
gws.status = 0;
|
|
SN_Queues.gwstatusQueue.PostItem(gws);
|
|
|
|
LOGS.LOG("Reconnecting to controller ip:" + p_ctrIP + " port:" + port.ToString());
|
|
Utils.ConsWrite(DebugMSG_Type.CTRL, "Reconnecting to controller ip:"+p_ctrIP+" port:"+ port.ToString());
|
|
if (client != null)
|
|
{
|
|
if (client.Connected)
|
|
client.Close();
|
|
client = null;
|
|
}
|
|
|
|
if (clientStream != null)
|
|
{
|
|
try
|
|
{
|
|
clientStream.Close();
|
|
clientStream.Dispose();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.ForegroundColor = ConsoleColor.Red;
|
|
Utils.ConsWrite(DebugMSG_Type.always, "ClientStream Exception ex: " + ex.ToString());
|
|
Console.ForegroundColor = ConsoleColor.Gray;
|
|
}
|
|
}
|
|
|
|
client = new TcpClient();
|
|
serverEndPoint = new IPEndPoint(ctrIP, port);
|
|
//client.Connect(serverEndPoint);
|
|
client.Connect(ConnectPlus_GW.cfg.ctrlIP, port);
|
|
|
|
Utils.ConsWrite(DebugMSG_Type.CTRL, "WatcherServerThread connected on " + port);
|
|
LOGS.LOG("WatcherServerThread connected on " + port);
|
|
clientStream = client.GetStream();
|
|
if (clientStream != null)
|
|
{
|
|
//set read timeout to 35 seconds, according to Motorola Connect Plus PN_Watcher specifications
|
|
clientStream.ReadTimeout = 35 * 1000;
|
|
|
|
//resend subscribe all
|
|
Thread.Sleep(100);
|
|
SubscribeALL(1234);
|
|
//SubscribeALLinDB(1234);
|
|
dt_lastSUB = DateTime.UtcNow;
|
|
connDown = false;
|
|
}
|
|
else
|
|
{
|
|
connDown = true;
|
|
Thread.Sleep(500);
|
|
Utils.ConsWrite(DebugMSG_Type.always, "WatcherServerThread -> clientStream==null");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Utils.ConsWrite(DebugMSG_Type.always, "Restart FAILED!!!!\n " + ex.ToString());
|
|
}
|
|
}
|
|
|
|
//IF THE UNIT IS NOT IN ht_SUInfo dont process the message
|
|
private void HandleClientComm()
|
|
{
|
|
Thread.Sleep(500);
|
|
|
|
while (ConnectPlus_GW.isRunning)
|
|
{
|
|
try
|
|
{
|
|
// wait until the client Stream is ready
|
|
if (clientStream == null || connDown)
|
|
{
|
|
RestartTCP();
|
|
continue;
|
|
}
|
|
|
|
clientStream.ReadTimeout = 30 * 1000;
|
|
//Console.WriteLine("Waiting for stuff...");
|
|
//read LEN first
|
|
byte[] msgLen = new byte[2];
|
|
int result = clientStream.Read(msgLen, 0, msgLen.Length);
|
|
int msgLength = msgLen[0] * 265 + msgLen[1];
|
|
|
|
message = new byte[msgLength];
|
|
result = clientStream.Read(message, 0, msgLength);
|
|
/*
|
|
Console.ForegroundColor = ConsoleColor.Cyan;
|
|
Utils.printBytesArray(message);
|
|
Console.ForegroundColor = ConsoleColor.Gray;
|
|
*/
|
|
|
|
//Console.Write(DateTime.Now + "-> ");
|
|
//if we got PING send Pong
|
|
if (message[0] == 0xff)
|
|
{
|
|
LOGS.LOG("PING received");
|
|
lastPingTime = DateTime.Now;
|
|
ConnectPlus_GW.lastActivityTime = DateTime.Now;
|
|
//Print(message, result, true, "PING");
|
|
Utils.ConsWrite(DebugMSG_Type.always, "########### PING received ##########################");
|
|
|
|
//add to GW status queue for DB entry
|
|
GWstatus gws = new GWstatus();
|
|
gws.gw_id = gwID;
|
|
gws.status = 1;
|
|
gws.message = "PING RECEIVED [" + String.Format("{0:HH:mm:ss}", lastPingTime) + "]";
|
|
SN_Queues.gwstatusQueue.PostItem(gws);
|
|
|
|
Thread.Sleep(500);
|
|
PONG();
|
|
}
|
|
else
|
|
{
|
|
//Print(message, result, true);
|
|
List<NotifyRespons> responses = Decode(message, result);
|
|
foreach (NotifyRespons resp in responses)
|
|
{
|
|
if (resp.Error)
|
|
{
|
|
Utils.ConsWrite(DebugMSG_Type.DEV, "Response error suid:" + resp.SUID);
|
|
}
|
|
|
|
if (resp.DialogID != 1234)
|
|
{
|
|
Utils.ConsWrite(DebugMSG_Type.DEV, "Got one time resp from suid:" + resp.SUID);
|
|
}
|
|
|
|
//test if unit is in DB
|
|
if (SN_Queues.ht_SUInfo != null)
|
|
{
|
|
if (!SN_Queues.ht_SUInfo.ContainsKey(resp.SUID))
|
|
{
|
|
LOGS.LOG("Unit :" + resp.SUID + " NOT assigned to GWID:" + gwID);
|
|
Utils.WriteLine("Unit :" + resp.SUID + " NOT assigned to GWID:" + gwID, ConsoleColor.DarkGray);
|
|
//Utils.ConsWrite(DebugMSG_Type.ARS, "Unit :" + resp.SUID + " NOT assigned to GWID:" + gwID);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
totalUsers++;
|
|
|
|
if (resp.Active)
|
|
{
|
|
//Utils.ConsWrite(DebugMSG_Type.CTRL, "SU " + resp.SUID + " ON ### Total users: " + totalUsers);
|
|
int repInter = Convert.ToInt32(report);
|
|
|
|
//get reporting interval
|
|
repInter = ((SUinfo)SN_Queues.ht_SUInfo[resp.SUID]).repInterval;
|
|
/*
|
|
Utils.ConsWrite(DebugMSG_Type.GPS, "Interval for SUID:" + resp.SUID + " =" + repInter);
|
|
if (resp.DialogID != 1234)
|
|
Utils.ConsWrite(DebugMSG_Type.DEV, "new Interval for SUID:" + resp.SUID + " =" + repInter);
|
|
*/
|
|
|
|
//create location message!!
|
|
MotoTRBOcmdMsg msg = new MotoTRBOcmdMsg();
|
|
msg.m_cmd = (byte)MotoTRBOcmd.SET_REPORT_INTERVAL;
|
|
msg.m_suid = resp.SUID;
|
|
msg.m_payload = repInter.ToString();
|
|
if (repInter != 0)
|
|
{
|
|
Utils.WriteLine(String.Format("Unit {0} has interval set to {1} sec", resp.SUID, repInter), ConsoleColor.Yellow);
|
|
SN_Queues.locationQueue.PostItem(msg);
|
|
//Utils.ConsWrite(DebugMSG_Type.DEV, "Interval for SUID:" + resp.SUID + " =" + repInter);
|
|
}
|
|
else
|
|
{
|
|
Utils.WriteLine(String.Format("Unit {0} has no interval set", resp.SUID), ConsoleColor.Yellow);
|
|
//Utils.ConsWrite(DebugMSG_Type.GPS, "SUID:" + resp.SUID + " interval=0 , no GPS reporting needed.");
|
|
}
|
|
|
|
//send sms reg msq
|
|
SendSMSThread.Send_Reg_msg(resp.SUID + ".1");
|
|
}
|
|
|
|
//poll ars
|
|
//LOGS.LOG("Received ARS " + (resp.Active ? "ON" : "OFF") + " from one time request. unit:" + resp.SUID);
|
|
|
|
//if previous ars state was OFF mark unit as ON
|
|
if (((SUinfo)SN_Queues.ht_SUInfo[resp.SUID]).ARSon != resp.Active)
|
|
{
|
|
InsertARSinQueue(resp.SUID, resp.Active ? "ON" : "OFF");
|
|
LOGS.LOG("Adding ARS " + (resp.Active ? "ON" : "OFF") + " prev state was OFF:" + resp.SUID);
|
|
}
|
|
|
|
Utils.ConsWrite(DebugMSG_Type.CTRL, "»»» ARS " + (resp.Active ? "ON" : "OFF") + " for " + resp.SUID);
|
|
|
|
//add ars info to HT
|
|
((SUinfo)SN_Queues.ht_SUInfo[resp.SUID]).arsCheckTime = DateTime.UtcNow;
|
|
((SUinfo)SN_Queues.ht_SUInfo[resp.SUID]).GPSlasttime = DateTime.UtcNow;
|
|
((SUinfo)SN_Queues.ht_SUInfo[resp.SUID]).ARSon = resp.Active;
|
|
}
|
|
}
|
|
}
|
|
catch (System.IO.IOException ex)
|
|
{
|
|
Utils.ConsWrite(DebugMSG_Type.always, "I/O exception!!");
|
|
Utils.ConsWrite(DebugMSG_Type.always, ex.ToString());
|
|
|
|
Thread.Sleep(500);
|
|
connDown = true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Utils.ConsWrite(DebugMSG_Type.always, ex.ToString());
|
|
int coun = 0;
|
|
while ((coun++) < 60 && ConnectPlus_GW.isRunning)
|
|
{
|
|
Thread.Sleep(500);
|
|
}
|
|
connDown = true;
|
|
}
|
|
|
|
int tcpResetCount = 0;
|
|
while (connDown == true && ConnectPlus_GW.isRunning)
|
|
{
|
|
if ((tcpResetCount++) % 120 == 0)
|
|
{
|
|
Utils.ConsWrite(DebugMSG_Type.always, "\n\n\n\n connDown== true Restarting TCP \n\n\n\n");
|
|
RestartTCP();
|
|
tcpResetCount = 0;
|
|
}
|
|
else if (tcpResetCount % 20 == 0)
|
|
Utils.WriteLine("WatchServer - TCP Connection is down", ConsoleColor.Red);
|
|
Thread.Sleep(500);
|
|
}
|
|
//Thread.Sleep(100);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Event Handler triggered each time a new radio is added in the system or when the reporting interval
|
|
/// had changed
|
|
/// </summary>
|
|
private void HandleInterval()
|
|
{
|
|
// wait until the units are loaded and then clear the new interval queue
|
|
// because the first time I do not need to send the SubscribeOneTime
|
|
while (!ConnectPlus_GW.unitsLoaded)
|
|
{
|
|
Thread.Sleep(500);
|
|
}
|
|
SN_Queues.NewIntervalQueue.Clear();
|
|
|
|
|
|
while (true)
|
|
{
|
|
string suid = "";
|
|
int dialogID = -1;
|
|
try
|
|
{
|
|
//test if we have a change in reporting interval
|
|
SUinfo info = SN_Queues.NewIntervalQueue.GetItem(100);
|
|
if (info != null)
|
|
{
|
|
Utils.ConsWrite(DebugMSG_Type.always, "Sending SubscribeOneTime to:" + info.suid);
|
|
dialogID = 0x1111;
|
|
//SubscribeALL(dialogID);
|
|
SubscribeOneTime(dialogID, info.suid);
|
|
|
|
// send triggered location request for this unit
|
|
if (info.repInterval > 0)
|
|
{
|
|
//create location message!!
|
|
MotoTRBOcmdMsg msg = new MotoTRBOcmdMsg();
|
|
msg.m_cmd = (byte)MotoTRBOcmd.SET_REPORT_INTERVAL;
|
|
msg.m_suid = info.suid;
|
|
msg.m_payload = info.repInterval.ToString();
|
|
|
|
SN_Queues.locationQueue.PostItem(msg);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{ Utils.ConsWrite(DebugMSG_Type.always, "Error HandleInterval for suid:" + suid + " dialogID:" + dialogID); }
|
|
}
|
|
}
|
|
|
|
private void CheckLastPing()
|
|
{
|
|
lastPingTime = DateTime.Now;
|
|
|
|
String processName = Process.GetCurrentProcess().ProcessName;
|
|
Process[] pname = Process.GetProcessesByName(processName);
|
|
while (pname.Length > 0)
|
|
{
|
|
Thread.Sleep(5000);
|
|
Utils.ConsWrite(DebugMSG_Type.CTRL, "Curent time:" + DateTime.Now.ToString("HH:mm:ss")
|
|
+ " LastActivityTime:" + ConnectPlus_GW.lastActivityTime.ToString("HH:mm:ss") + "[Units: " + SN_Queues.ht_SUInfo.Count + "]");
|
|
//test if we have a change in reporting interval
|
|
TimeSpan ts = DateTime.Now.Subtract(ConnectPlus_GW.lastActivityTime);
|
|
/*
|
|
if (ts.TotalSeconds > 600)
|
|
{
|
|
Console.ForegroundColor = ConsoleColor.Red;
|
|
Utils.ConsWrite(DebugMSG_Type.CTRL, "Last ping was >30 sec forcing TCP restart.");
|
|
Console.ForegroundColor = ConsoleColor.Gray;
|
|
LOGS.LOG("<<<CheckLastPing>>>Curent time:" + DateTime.Now.ToString("HH:mm:ss")
|
|
+ " LastPing:" + ConnectPlus_GW.lastActivityTime.ToString("HH:mm:ss"));
|
|
|
|
|
|
|
|
//RestartTCP();
|
|
}
|
|
*/
|
|
|
|
// check if the process is still running
|
|
pname = Process.GetProcessesByName(processName);
|
|
}
|
|
}
|
|
|
|
private void ResendSUB(Object state)
|
|
{
|
|
// This method is executed by a thread pool thread
|
|
try
|
|
{
|
|
if (DateTime.UtcNow.DayOfYear > dt_lastSUB.DayOfYear)
|
|
{
|
|
if (DateTime.UtcNow.Hour > 5)
|
|
{
|
|
SubscribeALL(1234);
|
|
//SubscribeALLinDB(1234);
|
|
LOGS.LOG("<<<ResendingSubscribeALL>>>Curent time:" + DateTime.UtcNow.ToString()
|
|
+ " LastPing:" + dt_lastSUB.ToString());
|
|
dt_lastSUB = DateTime.UtcNow;
|
|
Utils.ConsWrite(DebugMSG_Type.CTRL, "Resending SubscribeALL.");
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Utils.ConsWrite(DebugMSG_Type.always, "Error on ResendSUB:" + ex.ToString());
|
|
}
|
|
}
|
|
|
|
int countGPSrefresh = 0;
|
|
private void ResendGPS(Object state)
|
|
{
|
|
// This method is executed by a thread pool thread
|
|
try
|
|
{
|
|
countGPSrefresh++;
|
|
if (countGPSrefresh > 1024) countGPSrefresh = 0;
|
|
|
|
Utils.ConsWrite(DebugMSG_Type.CTRL, "ResendGPS check starded.");
|
|
|
|
Hashtable temp = (Hashtable)SN_Queues.ht_SUInfo.Clone();
|
|
|
|
foreach (DictionaryEntry de in temp)
|
|
{
|
|
SUinfo info = (SUinfo)de.Value;
|
|
DateTime lastARStime = info.arsCheckTime;
|
|
if (info.ARSon == false)
|
|
continue;
|
|
|
|
/*
|
|
TimeSpan difference = DateTime.UtcNow - info.GPSlasttime;
|
|
|
|
//check if more then "ConnectPlus_GW.cfg.GPS_refresh" time has passed since last ARS
|
|
//if ((DateTime.UtcNow.Subtract(new TimeSpan(ConnectPlus_GW.cfg.GPS_refresh, 0, 0))).Gre > lastARStime)
|
|
if (difference.Hours >= ConnectPlus_GW.cfg.GPS_refresh)
|
|
{
|
|
Utils.ConsWrite(DebugMSG_Type.CTRL, "Sending SubscribeOneTime to:" + info.suid);
|
|
LOGS.LOG("<<<GPS expired for unit:" + info.suid + ">>>Curent time:" + DateTime.UtcNow.ToString()
|
|
+ " ||||| Last GPS refresh:" + info.GPSlasttime.ToString());
|
|
int dialogID = 0x1111;
|
|
//SubscribeALL(dialogID);
|
|
SubscribeOneTime(dialogID, info.suid);
|
|
}
|
|
else
|
|
{
|
|
//Utils.ConsWrite(DebugMSG_Type.CTRL, "Unit:" + info.suid + " GPS not expired yet!");
|
|
if((countGPSrefresh % 30)==0)
|
|
LOGS.LOG("<<<GPS not expired yet for unit:" + info.suid + ">>>Curent time:" + DateTime.UtcNow.ToString()
|
|
+ " ||||| Last GPS refresh:" + info.arsCheckTime.ToString());
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Utils.ConsWrite(DebugMSG_Type.always, "Error on ResendSUB:" + ex.ToString());
|
|
}
|
|
}
|
|
|
|
public delegate void MessageRecv(NotifyRespons resp);
|
|
public event MessageRecv OnMessageRecv;
|
|
|
|
|
|
public enum SubscribeTag
|
|
{
|
|
DeviceID = 0xA, IPv4Address = 0xD, PresenceState = 0xE,
|
|
Expires = 0x01, Event = 0x02, SubscriptionState = 0x03, TCPPortNumber = 0x06
|
|
};
|
|
|
|
private List<NotifyRespons> Decode(byte[] data, int recv)
|
|
{
|
|
List<NotifyRespons> notifyResponses = new List<NotifyRespons>();
|
|
//Console.WriteLine("Got notify message");
|
|
|
|
/*
|
|
NotifyRespons nResp = new NotifyRespons();
|
|
nResp.Active = false;
|
|
nResp.DialogID = 0;
|
|
nResp.Error = true;
|
|
nResp.SUID = "0";
|
|
* */
|
|
//int msgLength = data[0] * 265 + data[1];
|
|
//length doesent match... return error
|
|
//if (msgLength != recv-2) { Console.WriteLine("Received length({0}) doesent match with message length({1})..returning errror!!!",recv-2,msgLength); return nResp; }
|
|
|
|
//test if we got at least msgLen, msgID,dialogID,subscription state
|
|
if (recv < 6)
|
|
{
|
|
Utils.ConsWrite(DebugMSG_Type.always, "Incorect message.Message does not have the minimum size of 6bytes. actual length=" + recv);
|
|
Utils.ConsWrite(DebugMSG_Type.always, "!!!!!!!!!!!!subscription state TLV missing!!!!!!!!!!!");
|
|
return notifyResponses;
|
|
}
|
|
|
|
int pos = 0;
|
|
NotifyRespons response = null;
|
|
bool found0x2 = false, found0x3 = false, found0xA = false, found0xE = false;
|
|
while (pos <= data.Length)
|
|
{
|
|
// add message if finished was reached
|
|
if (pos == data.Length)
|
|
{
|
|
notifyResponses.Add(response);
|
|
break;
|
|
}
|
|
|
|
// complet notify response
|
|
if(found0x2 && found0x3 && found0xA && found0xE)
|
|
{
|
|
found0x2 = false;
|
|
found0x3 = false;
|
|
found0xA = false;
|
|
found0xE = false;
|
|
notifyResponses.Add(response);
|
|
}
|
|
|
|
// get messageID and dialogID only if not waiting for one of this
|
|
// following Tag types
|
|
if (found0x2 == false && found0x3 == false && found0xA == false && found0xE == false)
|
|
{
|
|
// get messageID
|
|
int messageID = data[pos++];
|
|
if (messageID != 4)
|
|
{
|
|
Console.ForegroundColor = ConsoleColor.Red;
|
|
Console.WriteLine("Incorect msgID:{0}. MsgID must be 4(reliable notify message)", messageID);
|
|
Console.ForegroundColor = ConsoleColor.Gray;
|
|
return notifyResponses;
|
|
}
|
|
else
|
|
{
|
|
// found a valid notify response
|
|
response = new NotifyRespons();
|
|
response.Active = false;
|
|
response.DialogID = 0;
|
|
response.Error = true;
|
|
response.SUID = "0";
|
|
|
|
int dialogID = data[pos++] * 256 + data[pos++];
|
|
response.DialogID = dialogID;
|
|
}
|
|
}
|
|
|
|
int tag = data[pos++];
|
|
//Console.WriteLine("TAG is " + tag);
|
|
// break if last byte is a tag
|
|
if (pos >= data.Length)
|
|
break;
|
|
|
|
int length = data[pos++];
|
|
//Console.WriteLine("LENGTH is " + length);
|
|
switch (tag)
|
|
{
|
|
case (byte)SubscribeTag.Event:
|
|
{
|
|
byte[] value_arr = new byte[length];
|
|
Array.Copy(data, pos, value_arr, 0, length);
|
|
string event_string = Encoding.Unicode.GetString(value_arr);
|
|
// jump over value field
|
|
pos = pos + length;
|
|
found0x2 = true;
|
|
//Console.WriteLine("Found Event");
|
|
break;
|
|
}
|
|
case (byte)SubscribeTag.SubscriptionState:
|
|
{
|
|
byte value = data[pos++];
|
|
switch (value)
|
|
{
|
|
case (byte)SubscriptionState.Accepted:
|
|
//Console.WriteLine("Subscription State:" + SubscriptionState.Accepted + " value:" + value);
|
|
break;
|
|
case (byte)SubscriptionState.RefreshAccepted:
|
|
//Console.WriteLine("Subscription State:" + SubscriptionState.RefreshAccepted + " value:" + value);
|
|
break;
|
|
case (byte)SubscriptionState.Rejected:
|
|
//Console.WriteLine("Subscription State:" + SubscriptionState.Rejected + " value:" + value);
|
|
break;
|
|
case (byte)SubscriptionState.Terminated:
|
|
//Console.WriteLine("Subscription State:" + SubscriptionState.Terminated + " value:" + value);
|
|
break;
|
|
default:
|
|
Utils.ConsWrite(DebugMSG_Type.CTRL, "Unknown subscription state:" + value);
|
|
break;
|
|
}
|
|
found0x3 = true;
|
|
//Console.WriteLine("Found SubscriptionState");
|
|
break;
|
|
}
|
|
case (byte)SubscribeTag.DeviceID:
|
|
{
|
|
byte[] value_arr = new byte[length];
|
|
Array.Copy(data, pos, value_arr, 0, length);
|
|
string suid = Encoding.Unicode.GetString(value_arr);
|
|
response.SUID = suid;
|
|
//Console.WriteLine("Entity(SUID):" + suid);
|
|
|
|
//jump to next tlv
|
|
pos = pos + length;
|
|
response.Error = false;
|
|
found0xA = true;
|
|
//Console.WriteLine("Found DeviceID ");
|
|
break;
|
|
}
|
|
case (byte)SubscribeTag.PresenceState:
|
|
{
|
|
byte[] value_arr = new byte[length];
|
|
Array.Copy(data, pos, value_arr, 0, length);
|
|
string presence = Encoding.Unicode.GetString(value_arr);
|
|
|
|
switch (presence)
|
|
{
|
|
case "0":
|
|
//Console.WriteLine("Presence state TLV: unknown value:" + presence);
|
|
break;
|
|
case "1":
|
|
response.Active = true;
|
|
//Console.WriteLine("Presence state TLV: present value:" + presence);
|
|
break;
|
|
case "2":
|
|
response.Active = false;
|
|
//Console.WriteLine("Presence state TLV: absent value:" + presence);
|
|
break;
|
|
}
|
|
|
|
//jump to next tlv
|
|
pos = pos + length;
|
|
found0xE = true;
|
|
//Console.WriteLine("Found PresenceState");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return notifyResponses;
|
|
}
|
|
|
|
public Boolean Send(byte[] data, int len)
|
|
{
|
|
if (clientStream != null)
|
|
{
|
|
clientStream.Write(data, 0, len);
|
|
clientStream.Flush();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
#region Subscribe messages and PONG message
|
|
/// <summary>
|
|
/// Send the subcribe message to the controler
|
|
/// </summary>
|
|
/// <param name="dialogID">unique dialog ID</param>
|
|
/// <param name="ID">ID of radio subscriber that is being watched</param>
|
|
/// <param name="expiresTime">time to live of the subscription</param>
|
|
public void Subscribe(int dialogID, int ID, byte expiresTime)
|
|
{
|
|
Utils.ConsWrite(DebugMSG_Type.DEV, "DialogID:" + dialogID);
|
|
byte[] tempID = convertInt2ByteLE(ID);
|
|
|
|
byte[] msg = new byte[18 + tempID.Length];
|
|
//length
|
|
msg[0] = 0x00;
|
|
msg[1] = Convert.ToByte(0x10 + tempID.Length);
|
|
// message ID
|
|
msg[2] = 0x03;
|
|
// Dialog ID
|
|
byte[] tempDialogID = BitConverter.GetBytes(dialogID);
|
|
msg[3] = tempDialogID[1];
|
|
msg[4] = tempDialogID[0];
|
|
//Message BODY
|
|
//The Expires TLV Field
|
|
msg[5] = 0x01;
|
|
msg[6] = 0x01;
|
|
msg[7] = expiresTime;
|
|
//The TCPPort TLV Field
|
|
msg[8] = 0x06;
|
|
msg[9] = 0x02;
|
|
byte[] tempPort = BitConverter.GetBytes(0x3344);
|
|
msg[10] = tempPort[1];
|
|
msg[11] = tempPort[0];
|
|
//The Entities TLV Field
|
|
msg[12] = 0x0a;
|
|
msg[13] = Convert.ToByte(tempID.Length);
|
|
// ID
|
|
for (int i = 0; i < tempID.Length; i++)
|
|
{
|
|
msg[14 + i] = tempID[i];
|
|
}
|
|
|
|
//The Events TLV Field
|
|
msg[14 + tempID.Length] = 0x02;
|
|
msg[14 + tempID.Length + 1] = 0x02;
|
|
msg[14 + tempID.Length + 2] = 0x31;
|
|
msg[14 + tempID.Length + 3] = 0x00;
|
|
|
|
Send(msg, msg.Length);
|
|
//Console.WriteLine("-----------Sent Subscribe to the controller-----");
|
|
//Print(msg, msg.Length, false);
|
|
}
|
|
|
|
public void SubscribeALL(int dialogID)
|
|
{
|
|
byte[] msg = new byte[23];
|
|
//length
|
|
msg[0] = 0x00;
|
|
msg[1] = 0x15;
|
|
// message ID
|
|
msg[2] = 0x03;
|
|
// Dialog ID
|
|
byte[] tempDialogID = BitConverter.GetBytes(dialogID);
|
|
msg[3] = tempDialogID[1];
|
|
msg[4] = tempDialogID[0];
|
|
|
|
//Message BODY
|
|
//The Expires TLV Field (94608000 sec ~= 3 years)
|
|
msg[5] = 0x01;
|
|
msg[6] = 0x04;
|
|
msg[7] = 0xff;
|
|
msg[8] = 0xff;
|
|
msg[9] = 0xff;
|
|
msg[10] = 0xff;
|
|
//The Entities TLV Field
|
|
msg[11] = 0x0a;
|
|
msg[12] = 0x02;
|
|
// ID:all
|
|
msg[13] = 0x2A;
|
|
msg[14] = 0x00;
|
|
//The Events TLV Field
|
|
msg[15] = 0x02;
|
|
msg[16] = 0x06;
|
|
msg[17] = (byte)'1';
|
|
msg[18] = 0x00;
|
|
msg[19] = (byte)',';
|
|
msg[20] = 0x00;
|
|
msg[21] = (byte)'2';
|
|
msg[22] = 0x00;
|
|
|
|
if (Send(msg, msg.Length))
|
|
Utils.WriteLine("Sent Subscribe ALL to the controller", ConsoleColor.Gray);
|
|
else
|
|
Utils.WriteLine("Failed to send Subscribe ALL to the controller", ConsoleColor.Gray);
|
|
//Print(msg, msg.Length, false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Query the controller for the status of a particular field unit
|
|
/// </summary>
|
|
/// <param name="dialogID">The unique identifier for this request</param>
|
|
/// <param name="suid">The field radio Id for which the status is required</param>
|
|
public void SubscribeOneTime(int dialogID, string suid)// TLV expire =0
|
|
{
|
|
//Utils.ConsWrite(DebugMSG_Type.DEV, "DialogID:" + dialogID);
|
|
char[] suidARR = suid.ToCharArray();
|
|
|
|
byte[] msg = new byte[18 + suidARR.Length*2];
|
|
//length
|
|
msg[0] = 0x00;
|
|
msg[1] = (byte)(16 + suidARR.Length * 2);
|
|
// message ID
|
|
msg[2] = 0x03;
|
|
// Dialog ID
|
|
byte[] tempDialogID = BitConverter.GetBytes(dialogID);
|
|
msg[3] = tempDialogID[1];
|
|
msg[4] = tempDialogID[0];
|
|
|
|
//Message BODY
|
|
//The Expires TLV Field
|
|
msg[5] = 0x01;
|
|
msg[6] = 0x01;
|
|
msg[7] = 0x00;//one time
|
|
//The Entities TLV Field
|
|
msg[8] = 0x0a;
|
|
msg[9] = (byte)(suidARR.Length*2);
|
|
for (int i = 0; i < suidARR.Length; i++)
|
|
{
|
|
byte b = (byte)suidARR[i];
|
|
//Console.WriteLine(b);
|
|
msg[10 + i * 2] = b;
|
|
msg[10 + i * 2 + 1] = 0x00;
|
|
}
|
|
//The Events TLV Field
|
|
msg[10 + suidARR.Length * 2] = 0x02;
|
|
msg[10 + suidARR.Length * 2 + 1] = 0x06;
|
|
msg[10 + suidARR.Length * 2 + 2] = (byte)'1';
|
|
msg[10 + suidARR.Length * 2 + 3] = 0x00;
|
|
msg[10 + suidARR.Length * 2 + 4] = (byte)',';
|
|
msg[10 + suidARR.Length * 2 + 5] = 0x00;
|
|
msg[10 + suidARR.Length * 2 + 6] = (byte)'2';
|
|
msg[10 + suidARR.Length * 2 + 7] = 0x00;
|
|
|
|
Send(msg, msg.Length);
|
|
//Console.WriteLine("-----------Sent Subscribe ALL to the controller-----");
|
|
//Print(msg, msg.Length, false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reliable Subscribe message for all the field radios from the controller
|
|
/// </summary>
|
|
public void SubscribeALL()
|
|
{
|
|
byte[] msg = new byte[20];
|
|
//length
|
|
msg[0] = 0x00;
|
|
msg[1] = 0x12;
|
|
// message ID
|
|
msg[2] = 0x03;
|
|
// Dialog ID
|
|
msg[3] = 0x33;
|
|
msg[4] = 0x44;
|
|
//Message BODY
|
|
//The Expires TLV Field
|
|
msg[5] = 0x01;
|
|
msg[6] = 0x01;
|
|
msg[7] = 0xff;
|
|
//The TCPPort TLV Field
|
|
msg[8] = 0x06;
|
|
msg[9] = 0x02;
|
|
byte[] temp = BitConverter.GetBytes(0x3344);
|
|
msg[10] = temp[1];
|
|
msg[11] = temp[0];
|
|
//The Entities TLV Field
|
|
msg[12] = 0x0a;
|
|
msg[13] = 0x02;
|
|
// ID:all
|
|
msg[14] = 0x2a;
|
|
msg[15] = 0x00;
|
|
//The Events TLV Field
|
|
msg[16] = 0x02;
|
|
msg[17] = 0x02;
|
|
msg[18] = 0x2a;
|
|
msg[19] = 0x00;
|
|
|
|
|
|
if (Send(msg, msg.Length))
|
|
Utils.WriteLine("Sent Subscribe ALL to the controller", ConsoleColor.Gray);
|
|
else
|
|
Utils.WriteLine("Failed to send Subscribe ALL to the controller", ConsoleColor.Gray);
|
|
//Print(msg, msg.Length, false);
|
|
}
|
|
|
|
|
|
public void SubscribeList(int dialogID, List<string> suids)// TLV expire =0
|
|
{
|
|
//Utils.ConsWrite(DebugMSG_Type.DEV, "DialogID:" + dialogID);
|
|
//create arr string: suid1,suid2,....,suidn
|
|
string strSUIDS="";
|
|
for (int i = 0; i < suids.Count; i++)
|
|
{
|
|
if (i != (suids.Count - 1))
|
|
{
|
|
strSUIDS += suids[i] + ",";
|
|
}
|
|
else
|
|
{
|
|
strSUIDS += suids[i];
|
|
}
|
|
}
|
|
Utils.ConsWrite(DebugMSG_Type.ARS, "suids string:" + strSUIDS);
|
|
|
|
char[] suidARR = strSUIDS.ToCharArray();
|
|
byte[] msg = new byte[15 + suidARR.Length * 2];
|
|
//length
|
|
msg[0] = 0x00;
|
|
msg[1] = (byte)(13 + suidARR.Length * 2);
|
|
// message ID
|
|
msg[2] = 0x03;
|
|
// Dialog ID
|
|
byte[] tempDialogID = BitConverter.GetBytes(dialogID);
|
|
msg[3] = tempDialogID[1];
|
|
msg[4] = tempDialogID[0];
|
|
|
|
//Message BODY
|
|
//The Expires TLV Field
|
|
//msg[5] = 0x01;
|
|
//msg[6] = 0x01;
|
|
//msg[7] = 0x00;//one time
|
|
//The Entities TLV Field
|
|
msg[5] = 0x0a;
|
|
msg[6] = (byte)(suidARR.Length * 2);
|
|
for (int i = 0; i < suidARR.Length; i++)
|
|
{
|
|
byte b = (byte)suidARR[i];
|
|
//Console.WriteLine(b);
|
|
msg[7 + i * 2] = b;
|
|
msg[7 + i * 2 + 1] = 0x00;
|
|
}
|
|
//The Events TLV Field
|
|
msg[7 + suidARR.Length * 2] = 0x02;
|
|
msg[7 + suidARR.Length * 2 + 1] = 0x06;
|
|
msg[7 + suidARR.Length * 2 + 2] = (byte)'1';
|
|
msg[7 + suidARR.Length * 2 + 3] = 0x00;
|
|
msg[7 + suidARR.Length * 2 + 4] = (byte)',';
|
|
msg[7 + suidARR.Length * 2 + 5] = 0x00;
|
|
msg[7 + suidARR.Length * 2 + 6] = (byte)'2';
|
|
msg[7 + suidARR.Length * 2 + 7] = 0x00;
|
|
|
|
Send(msg, msg.Length);
|
|
//Console.WriteLine("-----------Sent Subscribe ALL to the controller-----");
|
|
//Print(msg, msg.Length, false);
|
|
}
|
|
|
|
public void SubscribeALLinDB(int dialogID)
|
|
{
|
|
//start subscription thread
|
|
subscribThread.Start(dialogID);
|
|
}
|
|
|
|
private void SubscribeALLinDB_del(object dialogID)
|
|
{
|
|
|
|
//wait for su info to be retrived from DB
|
|
while(SN_Queues.ht_SUInfo.Count < 1)
|
|
{
|
|
Utils.ConsWrite(DebugMSG_Type.ARS, "SubscribeALLinDB waiting for SU info from DB sleeping 500ms "
|
|
+ "<------> or no unit present in DB for gwid:" + gwID);
|
|
Thread.Sleep(500);
|
|
}
|
|
List<string> suids = null;
|
|
if (SN_Queues.ht_SUInfo != null)
|
|
{
|
|
suids = new List<string>();
|
|
foreach (DictionaryEntry de in SN_Queues.ht_SUInfo)
|
|
{
|
|
suids.Add(((SUinfo)de.Value).suid);
|
|
}
|
|
}
|
|
if(suids != null)
|
|
SubscribeList((int)dialogID, suids);
|
|
}
|
|
//send PONG back to controller
|
|
|
|
public void PONG()
|
|
{
|
|
byte[] msg = new byte[12];
|
|
//length
|
|
msg[0] = 0x00;
|
|
msg[1] = 0x0a;
|
|
// message ID
|
|
msg[2] = 0xff;
|
|
// body length
|
|
msg[3] = 0x08;
|
|
//PONG -utf16 LE string
|
|
//P
|
|
msg[4] = 0x50;
|
|
msg[5] = 0x00;
|
|
//O
|
|
msg[6] = 0x4f;
|
|
msg[7] = 0x00;
|
|
//N
|
|
msg[8] = 0x4e;
|
|
msg[9] = 0x00;
|
|
//G
|
|
msg[10] = 0x47;
|
|
msg[11] = 0x00;
|
|
|
|
Send(msg, msg.Length);
|
|
Utils.ConsWrite(DebugMSG_Type.always,"-----------Sent PONG to the controller-----");
|
|
//Print(msg, msg.Length, false, "PONG:");
|
|
}
|
|
|
|
bool InsertARSinQueue(string p_radioID, string p_message)
|
|
{
|
|
try
|
|
{
|
|
ArsMSG ars = new ArsMSG();
|
|
ars.imei = p_radioID;
|
|
ars.msg = p_message;
|
|
SN_Queues.arsMsgQueue.PostItem(ars);
|
|
return true;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Utils.ConsWrite(DebugMSG_Type.always, "Error inserting ARS in Queue");
|
|
Utils.ConsWrite(DebugMSG_Type.always, e.Message);
|
|
return false;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region AUX methods
|
|
private void Print(byte[] data, int length, bool inOut)
|
|
{
|
|
//Console.Clear();
|
|
Console.WriteLine("--------------------------------------------------------------------------- " + length);
|
|
Console.Write("Data (" + ((inOut) ? "RECEIVED" : "SENT") + "): ");
|
|
for (int i = 0; i < length; i++)
|
|
Console.Write(" 0x" + data[i].ToString("X2"));
|
|
Console.WriteLine("");
|
|
Console.WriteLine("--------------------------------------------------------------------------- ");
|
|
}
|
|
|
|
private static byte[] convertInt2ByteLE(int id)
|
|
{
|
|
Byte[] retBytes = Encoding.Unicode.GetBytes(id.ToString());
|
|
return retBytes;
|
|
}
|
|
|
|
private int ConvertByteArr2Int(byte[] arr)
|
|
{
|
|
byte[] worker = new byte[4];
|
|
arr.CopyTo(worker, 0);
|
|
return BitConverter.ToInt32(worker, 0);
|
|
}
|
|
#endregion
|
|
|
|
}
|
|
|
|
|
|
public class NotifyRespons
|
|
{
|
|
private string suid;
|
|
public string SUID
|
|
{
|
|
get { return suid; }
|
|
set { suid = value; }
|
|
}
|
|
|
|
private bool active;
|
|
public bool Active
|
|
{
|
|
get { return active; }
|
|
set { active = value; }
|
|
}
|
|
|
|
private int dialogID;
|
|
public int DialogID
|
|
{
|
|
get { return dialogID; }
|
|
set { dialogID = value; }
|
|
}
|
|
|
|
private bool error;
|
|
public bool Error
|
|
{
|
|
get { return error; }
|
|
set { error = value; }
|
|
}
|
|
}
|
|
|
|
public enum SubscriptionState
|
|
{
|
|
Rejected = 1,
|
|
Accepted = 2,
|
|
Terminated = 3,
|
|
RefreshAccepted = 4
|
|
}
|
|
}
|