1851 lines
80 KiB
C#
1851 lines
80 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using SafeMobileLib;
|
|
using System.Threading;
|
|
using System.Net.Sockets;
|
|
using System.IO;
|
|
using System.ComponentModel;
|
|
|
|
namespace SDRgateway
|
|
{
|
|
class SDR
|
|
{
|
|
public static bool DEBUG = false;
|
|
private bool running = false;
|
|
|
|
private TcpClient tcpClient = null;
|
|
private Thread listenThread = null;
|
|
private NetworkStream stream = null;
|
|
|
|
private Int64 ISSI;
|
|
private String pass;
|
|
private string IP;
|
|
private int port;
|
|
public static int SMSprotocolID = 130;
|
|
private bool isStoreAndForward = true;
|
|
private System.Threading.Timer tCheckConnection;
|
|
private DateTime lastEntry;
|
|
|
|
public static object dictionaryLock = new object();
|
|
public static Dictionary<String, String> radioIdTolastPositionATMessageDictionary = new Dictionary<String, String>();
|
|
public static Dictionary<String, PositionData> RadioIdToLastPosDictionary = new Dictionary<string, PositionData>();
|
|
|
|
public static object calloutUUIDLock = new object();
|
|
public static Dictionary<String, uint> radioISSIWithSeverityToCalloutUUIDDictionary = new Dictionary<string, uint>();
|
|
private DBvehiclesManager dbVehManager;
|
|
|
|
public SDR_STATUS _registered = SDR_STATUS.NoConnection;
|
|
public SDR_STATUS registered
|
|
{
|
|
get { return _registered; }
|
|
set
|
|
{
|
|
_registered = value;
|
|
RegStatusChanged("RegStatusProp");
|
|
}
|
|
}
|
|
public event PropertyChangedEventHandler PropertyChanged;
|
|
|
|
protected void RegStatusChanged(string name)
|
|
{
|
|
PropertyChangedEventHandler handler = PropertyChanged;
|
|
if (handler != null)
|
|
{
|
|
PropertyChangedEventArgs e = new PropertyChangedEventArgs(name);
|
|
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
public SDR()
|
|
{
|
|
SM.Print("SDR constructor");
|
|
ISSI = Program.cfg.SDR_ISSI;
|
|
pass = Program.cfg.SDR_pass;
|
|
IP = Program.cfg.SDR_IP;
|
|
port = Program.cfg.SDR_port;
|
|
|
|
|
|
|
|
try
|
|
{
|
|
lock (dictionaryLock)
|
|
{
|
|
dbVehManager = new DBvehiclesManager(Program.cfg.DB_IP, Program.cfg.DB_schema, Program.cfg.DB_user, Program.cfg.DB_passwd, Program.cfg.DB_port);
|
|
|
|
RadioIdToLastPosDictionary = dbVehManager.getImeiLastPosDictionary(true);
|
|
Utils.WriteLine("Received " + RadioIdToLastPosDictionary.Count + " units", ConsoleColor.Green);
|
|
|
|
foreach (var item in RadioIdToLastPosDictionary)
|
|
{
|
|
Utils.Write(String.Format("{0:#############} |||| ", item.Key), ConsoleType.ALL);
|
|
}
|
|
}
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
Utils.WriteLine("Unable to get assigned units : " + ex.ToString(), ConsoleColor.Red);
|
|
}
|
|
}
|
|
|
|
public void setStoreAndForwardOption(bool isStoreAndForward)
|
|
{
|
|
this.isStoreAndForward = isStoreAndForward;
|
|
}
|
|
|
|
public void Start()
|
|
{
|
|
running = true;
|
|
if (listenThread!=null && listenThread.IsAlive)
|
|
return;
|
|
|
|
lastEntry = DateTime.Now;
|
|
tCheckConnection = new System.Threading.Timer(CheckConnection, null, new TimeSpan(0, 0, 15), new TimeSpan(0, 1, 0));
|
|
|
|
listenThread = new Thread(new ThreadStart(HandleConnection));
|
|
listenThread.IsBackground = true;
|
|
listenThread.Start();
|
|
}
|
|
public void Stop(SDR_STATUS status)
|
|
{
|
|
if(registered != status)
|
|
registered = status;
|
|
|
|
running = false;
|
|
|
|
SM.Print("Stop SDR");
|
|
try
|
|
{
|
|
if (stream != null)
|
|
{
|
|
stream.Close();
|
|
}
|
|
stream = null;
|
|
}
|
|
catch (Exception ex) { Utils.WriteLine("Dispose 1"); };
|
|
|
|
try
|
|
{
|
|
if (tcpClient != null)
|
|
{
|
|
tcpClient.EndConnect(null);
|
|
tcpClient.Close();
|
|
|
|
}
|
|
tcpClient = null;
|
|
}
|
|
catch (Exception ex) { Utils.WriteLine("Dispose 2"); };
|
|
|
|
if (tCheckConnection != null)
|
|
tCheckConnection.Dispose();
|
|
|
|
if (registered != SDR_STATUS.Disconnected)
|
|
registered = SDR_STATUS.Disconnected;
|
|
}
|
|
|
|
|
|
|
|
private void CheckConnection(Object state)
|
|
{
|
|
try
|
|
{
|
|
//SM.Print("Testing connection Current:" + DateTime.Now +" lastentry:" +lastEntry);
|
|
if ((DateTime.Now.Subtract(lastEntry)).TotalSeconds > Program.cfg.SDR_TimeOut)
|
|
{
|
|
//if we dont receive anything in the last 10mins reset connection
|
|
Console.WriteLine("step1");
|
|
Stop(SDR_STATUS.NoConnection);
|
|
Console.WriteLine("step 2");
|
|
Thread.Sleep(1000);
|
|
Console.WriteLine("step 3");
|
|
Start();
|
|
|
|
SM.Print("Expired.Restart");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
SM.Print(ex.ToString());
|
|
}
|
|
}
|
|
//write data
|
|
private bool Write(byte[] data, int len)
|
|
{
|
|
bool resp = false;
|
|
try
|
|
{
|
|
if (tcpClient != null && tcpClient.Connected && stream != null && stream.CanWrite)
|
|
{
|
|
stream.Write(data, 0, len);
|
|
resp = true;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Utils.WriteLine("Write on TCP Exception : " + ex.ToString(), ConsoleColor.Red);
|
|
//SM.Print("Write on TCP Exception : " + ex.ToString());
|
|
stream = null;
|
|
tcpClient = null;
|
|
if (registered != SDR_STATUS.Disconnected)
|
|
registered = SDR_STATUS.Disconnected;
|
|
}
|
|
return resp;
|
|
}
|
|
//deleg for reading data (threaded while true) connection and maintain inside
|
|
private void HandleConnection()
|
|
{
|
|
try
|
|
{
|
|
while (running)
|
|
{
|
|
|
|
//reconnect
|
|
if (stream == null && running)
|
|
{
|
|
ConnectAndMaintain();
|
|
}
|
|
|
|
try
|
|
{
|
|
//read available data from SDR!!!
|
|
//byte[] data = SDR_Parse(out data_len, out rec_issi);
|
|
|
|
//Process(data, data_len, rec_issi);
|
|
if (stream != null && running)
|
|
LIPreader();
|
|
}
|
|
catch (IOException ex)
|
|
{
|
|
if (running)
|
|
{
|
|
WriteLine("ERROR in SDR.cs HandleConnection" + ex.ToString(), ConsoleColor.DarkRed);
|
|
if (registered != SDR_STATUS.Disconnected)
|
|
registered = SDR_STATUS.Disconnected;
|
|
stream = null;
|
|
tcpClient = null;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
SM.Print(ex.ToString());
|
|
}
|
|
finally
|
|
{
|
|
if (stream != null)
|
|
stream.Close();
|
|
if (tcpClient != null)
|
|
if (tcpClient.Connected)
|
|
tcpClient.Close();
|
|
}
|
|
|
|
if (registered != SDR_STATUS.NoConnection)
|
|
registered = SDR.SDR_STATUS.NoConnection;
|
|
}
|
|
|
|
#region LIP
|
|
public void LIPreader()
|
|
{
|
|
try
|
|
{
|
|
byte[] data = new byte[1025];
|
|
string asciiData = "";
|
|
int iToRead = 0;
|
|
int i = 0;
|
|
|
|
//wait and read incoming data
|
|
try
|
|
{
|
|
iToRead = stream.Read(data, 0, data.Length);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine("SDR read error - " + ex.Message);
|
|
stream = null;
|
|
tcpClient = null;
|
|
if (registered != SDR_STATUS.Disconnected)
|
|
registered = SDR_STATUS.Disconnected;
|
|
}
|
|
|
|
//must cover the case where 2 Gws are active at th same time
|
|
if (iToRead == 0)
|
|
{
|
|
Console.WriteLine("#############################################");
|
|
Console.WriteLine("RX 0 lenght data. Connection droped!!!");
|
|
Console.WriteLine("#############################################");
|
|
stream = null;
|
|
tcpClient = null;
|
|
if(registered != SDR_STATUS.Disconnected)
|
|
registered = SDR_STATUS.Disconnected;
|
|
|
|
if (DEBUG)
|
|
{
|
|
Console.WriteLine("#############################################");
|
|
Console.WriteLine(DateTime.Now.ToString("hh:mm:ss"));
|
|
SDR.Print(data, iToRead, true);
|
|
Console.WriteLine("#############################################");
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//convert each byte into hex value.
|
|
while (i < iToRead)
|
|
{
|
|
if (Convert.ToString(data[i], 16).ToString().Length < 2)
|
|
{
|
|
asciiData = asciiData + "0" + Convert.ToString(data[i], 16);
|
|
}
|
|
else
|
|
{
|
|
asciiData = asciiData + Convert.ToString(data[i], 16);
|
|
}
|
|
i = i + 1;
|
|
}
|
|
//Console.WriteLine("Ascii Data: " + asciiData);
|
|
//message decoder and display section
|
|
LIPSDR lipsdr = new LIPSDR();
|
|
lipsdr.sdsDecoder(asciiData);
|
|
if (lipsdr.reply == "Address Registered")
|
|
{
|
|
if (registered != SDR_STATUS.Connected)
|
|
{
|
|
registered = SDR_STATUS.Connected;
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (registered != SDR_STATUS.Connected)
|
|
return;
|
|
|
|
//if (DEBUG)
|
|
if (true)
|
|
{
|
|
/*
|
|
Console.WriteLine("Raw Data: " + lipsdr.binarydata);
|
|
Utils.WriteLine("Source Address : " + lipsdr.sourceaddress,ConsoleColor.DarkYellow);
|
|
Console.WriteLine("Source Address : " + lipsdr.sourceaddress);
|
|
Console.WriteLine("Destination Address : " + lipsdr.destinationaddress);
|
|
Utils.WriteLine("Protocol Identifier: " + lipsdr.PIvalue, ConsoleColor.DarkYellow);
|
|
Console.WriteLine("Message Reference: " + lipsdr.messageReference);
|
|
Console.WriteLine("User_data: " + lipsdr.User_data);
|
|
Console.WriteLine("SDTS_TL_DATA_flags: " + lipsdr.SDTS_TL_DATA_flags);
|
|
Console.WriteLine("CM_reply: " + lipsdr.CM_reply);
|
|
Console.WriteLine("Reply: " + lipsdr.reply);
|
|
*/
|
|
}
|
|
|
|
|
|
string imei = lipsdr.sourceaddress ?? "";
|
|
Utils.WriteLine("SDR Received data from " + imei);
|
|
|
|
// continue only if unit is assigned to this gateway or if the size of dictionary is 0 (connection with database was not allowed)
|
|
if (RadioIdToLastPosDictionary.Count == 0 || RadioIdToLastPosDictionary.ContainsKey(imei))
|
|
{
|
|
//SMS
|
|
if (lipsdr.PIvalue == "130" || lipsdr.PIvalue == "195")
|
|
{
|
|
//Utils.WriteLine("PI VALUE ISSSS : " + lipsdr.PIvalue, ConsoleColor.Yellow);
|
|
//Utils.WriteLine("ASCII : " + asciiData, ConsoleColor.Red);
|
|
|
|
//IF SMS(not null) this must be added
|
|
if (lipsdr.User_data != null)
|
|
{
|
|
if (lipsdr.User_data != "")
|
|
{
|
|
msgCell cell = new msgCell();
|
|
cell.msg = MSG_TYPE.SMS;
|
|
cell.IMEI = lipsdr.sourceaddress;
|
|
cell.sms = lipsdr.User_data;
|
|
|
|
Utils.WriteLine("MSG RECEIVED : " + lipsdr.User_data, ConsoleColor.Yellow);
|
|
|
|
Program.smsINQueue.PostItem(cell);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//send ACK back
|
|
// sending a report back
|
|
int sourISSI = int.Parse(lipsdr.destinationaddress);
|
|
int DestISSI = int.Parse(lipsdr.sourceaddress);
|
|
byte[] REPORT_ACK = {0x00, 0x0f,
|
|
0x00,
|
|
(byte)(((UInt32)sourISSI&0xff0000)>>16), // source ISSI
|
|
(byte)(((UInt32)sourISSI&0x00ff00)>>8),
|
|
(byte)(((UInt32)sourISSI&0x0000ff)),
|
|
|
|
(byte)(((UInt32)DestISSI&0x00ff0000)>>16), // destination ISSI
|
|
(byte)(((UInt32)DestISSI&0x0000ff00)>>8),
|
|
(byte)(((UInt32)DestISSI&0x000000ff)),
|
|
(byte)(byte.Parse(lipsdr.PIvalue)),// 0xc0, // protocol
|
|
0x60, // flags
|
|
0x00, // message reference
|
|
0x00, // area slection
|
|
0x00, 0x10, // TL length (bits)
|
|
0x01, // PDU type = Report
|
|
0x00 // Delivery status = ACK
|
|
};
|
|
REPORT_ACK[11] = byte.Parse(lipsdr.messageReference); ; // msg_id
|
|
if (stream != null)
|
|
stream.Write(REPORT_ACK, 0, 0x0f + 2);
|
|
}
|
|
else if (lipsdr.PIvalue != "10")
|
|
;//Utils.WriteLine("PI VALUE IS " + lipsdr.PIvalue, ConsoleColor.Magenta);
|
|
|
|
#region PIVALUE 10
|
|
if (lipsdr.PIvalue == "10")
|
|
{
|
|
LIP lip = new LIP();
|
|
lip.decoder(lipsdr.User_data);
|
|
|
|
Utils.WriteLine("╕╕╕ LIP raw data : " + lipsdr.User_data, ConsoleColor.Cyan);
|
|
|
|
//Console.WriteLine("MESSAGE REFERENCE " + lip.locationMessageReference);
|
|
|
|
int len = (int.Parse(lipsdr.TLlength_include_SDTS_TL_PDU_field) / 4) - 1;
|
|
//Console.WriteLine("User Data len: " + len );
|
|
|
|
/*
|
|
if (DEBUG)
|
|
{
|
|
Console.WriteLine("pDUType: " + lip.pDUType);
|
|
Console.WriteLine("Time Type : " + lip.timeType);
|
|
Console.WriteLine("Time Elapsed :" + lip.timeElapsed);
|
|
Console.WriteLine("timePositionDay: " + lip.timePositionDay);
|
|
Console.WriteLine("timePositionHour: " + lip.timePositionHour);
|
|
Console.WriteLine("timePositionMinute: " + lip.timePositionMinute);
|
|
Console.WriteLine("timePositionSecond: " + lip.timePositionSecond);
|
|
|
|
Console.WriteLine("locationShape: " + lip.locationShape);
|
|
Console.WriteLine("longitude: " + lip.longitude);
|
|
Console.WriteLine("latitude: " + lip.latitude);
|
|
Console.WriteLine("horizontalVelocity: " + lip.horizontalVelocity);
|
|
}
|
|
*/
|
|
|
|
|
|
MSG_TYPE type = lipsdr.GetMSGtype(lipsdr.User_data, len);
|
|
|
|
String source = lipsdr.sourceaddress != "" ? lipsdr.sourceaddress : "";
|
|
|
|
handleDecodedLip(type, lip, source);
|
|
}
|
|
#endregion
|
|
}
|
|
|
|
else
|
|
Utils.WriteLine($"Received position from unit not assigned with imei {imei}", ConsoleColor.Magenta);
|
|
}
|
|
catch (IOException ex)
|
|
{
|
|
Utils.WriteLine("SDR IO read error" + ex.Message);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Utils.WriteLine("SDR read error" + ex.Message);
|
|
}
|
|
}
|
|
|
|
|
|
public void handleDecodedLip(MSG_TYPE type, LIP lip, String source)
|
|
{
|
|
msgCell cell = new msgCell();
|
|
//IMEI subscriber
|
|
if (source == "")
|
|
SM.Print("subscriber == null");
|
|
|
|
cell.IMEI = source;
|
|
|
|
|
|
|
|
switch (type)
|
|
{
|
|
case MSG_TYPE.ARS_ON:
|
|
{
|
|
SM.Print("Adding ARS_ON from " + cell.IMEI);
|
|
cell.msg = MSG_TYPE.ARS;
|
|
cell.ars = 1;
|
|
|
|
Program.eventQueue.PostItem(cell);
|
|
break;
|
|
}
|
|
case MSG_TYPE.ARS_OFF:
|
|
{
|
|
SM.Print("Adding ARS_OFF from " + cell.IMEI);
|
|
cell.msg = MSG_TYPE.ARS;
|
|
cell.ars = 0;
|
|
Program.eventQueue.PostItem(cell);
|
|
break;
|
|
}
|
|
case MSG_TYPE.Emergency:
|
|
{
|
|
SM.Print("Adding Emergency from " + cell.IMEI);
|
|
cell.msg = MSG_TYPE.Emergency;
|
|
Program.eventQueue.PostItem(cell);
|
|
|
|
break;
|
|
}
|
|
case MSG_TYPE.GPS:
|
|
{
|
|
//SM.Print("Adding LIP message to gps queue.");
|
|
//LAT latitude
|
|
if (lip.latitude != "")
|
|
cell.lat = lip.latitude;
|
|
else
|
|
SM.Print("latitude == null");
|
|
|
|
//LNG
|
|
if (lip.longitude != "")
|
|
cell.lng = lip.longitude;
|
|
else
|
|
SM.Print("longitude == null");
|
|
|
|
if (lip.timePositionHour == null || lip.timePositionHour == "")
|
|
{
|
|
lip.timePositionHour = DateTime.UtcNow.Hour.ToString();
|
|
}
|
|
|
|
if (lip.timePositionMinute == null || lip.timePositionMinute == "")
|
|
{
|
|
lip.timePositionMinute = DateTime.UtcNow.Minute.ToString();
|
|
}
|
|
|
|
if (lip.timePositionSecond == null || lip.timePositionSecond == "")
|
|
{
|
|
lip.timePositionSecond = DateTime.UtcNow.Second.ToString();
|
|
}
|
|
|
|
Utils.WriteLine($"{lip.timePositionHour}:{lip.timePositionMinute}:{lip.timePositionSecond}", ConsoleColor.Magenta);
|
|
|
|
//time
|
|
DateTime time = new DateTime((int)DateTime.UtcNow.Year,
|
|
(int)DateTime.UtcNow.Month,
|
|
(int)DateTime.UtcNow.Day,
|
|
(int)Convert.ToInt32(lip.timePositionHour),
|
|
(int)Convert.ToInt32(lip.timePositionMinute),
|
|
(int)Convert.ToInt32(lip.timePositionSecond));
|
|
|
|
if (time != null)
|
|
cell.time = time;
|
|
else
|
|
SM.Print("time == null");
|
|
|
|
//speed speed
|
|
double spd = 0;
|
|
|
|
Utils.WriteLine("Horizontal speed : " + lip.horizontalVelocity, ConsoleColor.DarkCyan);
|
|
|
|
if (lip.horizontalVelocity.Contains("Horizontal speed is unknown"))
|
|
{
|
|
// Console.WriteLine("Horizontal speed is unknown");
|
|
lip.horizontalVelocity = "0";
|
|
}
|
|
if (lip.horizontalVelocity.Contains("km/h"))
|
|
{
|
|
lip.horizontalVelocity = lip.horizontalVelocity.Replace("km/h", "");
|
|
//Console.WriteLine("After replace km/h: " + lip.horizontalVelocity);
|
|
}
|
|
if (!double.TryParse(lip.horizontalVelocity, out spd))
|
|
{
|
|
//Console.WriteLine("!ulong.TryParse(lip.horizontalVelocity, out spd) " + lip.horizontalVelocity);
|
|
lip.horizontalVelocity = "0";
|
|
}
|
|
//this is for knots
|
|
//ulong spd = (ulong)(ulong.Parse( lip.horizontalVelocity) * 1.85325);
|
|
|
|
spd = double.Parse(lip.horizontalVelocity);
|
|
try
|
|
{
|
|
spd = (ulong)Math.Round((double)spd);
|
|
}
|
|
catch (Exception ex) { Console.WriteLine("ERROR rounding speed:" + ex.Message); }
|
|
|
|
Utils.WriteLine("Horizontal speed : " + spd, ConsoleColor.DarkMagenta);
|
|
|
|
|
|
try
|
|
{
|
|
cell.spd = spd + "";
|
|
/*
|
|
if (cell.spd != null)
|
|
{
|
|
cell.spd = ((int)spd).ToString();
|
|
if (spd > 250)
|
|
{
|
|
cell.spd = "0";
|
|
cell.lat = "0";
|
|
cell.lng = "0";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cell.spd = ((int)spd).ToString();
|
|
if (spd > 250)
|
|
{
|
|
cell.spd = "0";
|
|
cell.lat = "0";
|
|
cell.lng = "0";
|
|
}
|
|
//SM.Print("spd == null");
|
|
}*/
|
|
}
|
|
catch (Exception ex) { Utils.WriteLine(""); };
|
|
|
|
|
|
|
|
|
|
// convert the position error to the enum value
|
|
LIP.PositionError positionError = LIP.PositionError.GetPositionError(lip.positionErrorBinaryValue);
|
|
Utils.WriteLine("Position Error is: " + positionError.ToHumanString() + "[" + lip.positionErrorBinaryValue + "]", ConsoleColor.Cyan);
|
|
Boolean isGPSErrorValid = true;
|
|
|
|
|
|
if (positionError.value <= Program.cfg.PositionErrorTolerance.value)
|
|
isGPSErrorValid = true;
|
|
else
|
|
isGPSErrorValid = false;
|
|
/*
|
|
if (positionError == LIP.PositionError.Less2M)
|
|
isGPSErrorValid = true;
|
|
else if (positionError == LIP.PositionError.Less20M)
|
|
isGPSErrorValid = true;
|
|
else if (positionError == LIP.PositionError.Less200M)
|
|
isGPSErrorValid = true;
|
|
else if (positionError == LIP.PositionError.Less2Km)
|
|
isGPSErrorValid = false;
|
|
else if (positionError == LIP.PositionError.Less20Km)
|
|
isGPSErrorValid = false;
|
|
else if (positionError == LIP.PositionError.Less200Km)
|
|
isGPSErrorValid = false;
|
|
else if (positionError == LIP.PositionError.More200Km)
|
|
isGPSErrorValid = false;
|
|
else if (positionError == LIP.PositionError.Unknown)
|
|
isGPSErrorValid = true;
|
|
*/
|
|
#region INDOOR POSITION - QUERY INFO NOT ATTAINABLE
|
|
lock (dictionaryLock)
|
|
{
|
|
// add last position to an empty message if not available
|
|
if (!radioIdTolastPositionATMessageDictionary.ContainsKey(cell.IMEI))
|
|
radioIdTolastPositionATMessageDictionary.Add(cell.IMEI, "");
|
|
|
|
// get last position message from the hashtable
|
|
String lastPositionATMessage = radioIdTolastPositionATMessageDictionary[cell.IMEI];
|
|
|
|
// last position message is equal with current one (QUERY INFO NOT ATTAINABLE)
|
|
if (lastPositionATMessage.Equals(lip.binary))
|
|
{
|
|
SafeMobileLib.Utils.WriteLine("Query info not attainable", ConsoleColor.DarkYellow);
|
|
cell.lat = "0.0";
|
|
cell.lng = "0.0";
|
|
cell.time = DateTime.UtcNow;
|
|
cell.spd = "0";
|
|
}
|
|
|
|
// update last position at message to the last received one
|
|
radioIdTolastPositionATMessageDictionary[cell.IMEI] = lip.binary;
|
|
}
|
|
#endregion
|
|
|
|
|
|
//poll response
|
|
if (Convert.ToInt32(lip.reasonForSendingBinaryValue, 2) == 32)
|
|
{
|
|
cell.msg = MSG_TYPE.GPSpoll;
|
|
cell.poll = 1;
|
|
OnEventToDisplayOnUI(String.Format("»»» Poll res [{0:0.0000},{1:0.0000}] from {2}", Math.Round(Double.Parse(cell.lat), 4),
|
|
Math.Round(Double.Parse(cell.lng), 4), cell.IMEI));
|
|
}
|
|
else
|
|
{
|
|
cell.msg = MSG_TYPE.GPS;
|
|
cell.poll = 0;
|
|
//OnEventToDisplayOnUI(String.Format("»»» Position res [{0:0.0000},{1:0.0000}] from {2}", Math.Round(Double.Parse(cell.lat), 4),
|
|
// Math.Round(Double.Parse(cell.lng), 4), cell.IMEI));
|
|
}
|
|
|
|
if (!isGPSErrorValid)
|
|
{
|
|
|
|
Utils.WriteLine(String.Format("»»» Position is not valid [{0:0.0000},{1:0.0000}] from {2} [{3} kmh]", Math.Round(Double.Parse(cell.lat), 4),
|
|
Math.Round(Double.Parse(cell.lng), 4), cell.IMEI, cell.spd), ConsoleColor.Red);
|
|
//cell.lat = "0";
|
|
//cell.lng = "0";
|
|
}
|
|
else
|
|
Utils.WriteLine(String.Format("»»» Position is [{0:0.0000},{1:0.0000}] from {2} [{3} kmh]", Math.Round(Double.Parse(cell.lat), 4),
|
|
Math.Round(Double.Parse(cell.lng), 4), cell.IMEI, cell.spd), ConsoleColor.Green);
|
|
|
|
Program.gpsQueue.PostItem(cell);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//mark message time
|
|
lastEntry = DateTime.Now;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region lrrp
|
|
public void Process(byte[] data, uint data_len, long rec_issi)
|
|
{
|
|
if (data == null)
|
|
{
|
|
Utils.WriteLine("SDR data == null");
|
|
return;
|
|
}
|
|
//switch GPS_type
|
|
if (Program.cfg.GPS_type == "LIP")
|
|
{
|
|
Parser p = new Parser();
|
|
string out_str = p.ProcessCommand(data, data_len);
|
|
|
|
string xml = "";
|
|
System.Xml.XmlDocument doc = null;
|
|
System.Xml.XmlNode element = null;
|
|
if (out_str != "")
|
|
{
|
|
xml = "<xml " + out_str + " />";
|
|
doc = new System.Xml.XmlDocument();
|
|
doc.LoadXml(xml);
|
|
|
|
element = doc.SelectSingleNode("xml");
|
|
|
|
string value = element.Attributes["id"].Value;
|
|
}
|
|
|
|
if (doc != null)
|
|
{
|
|
Utils.WriteLine("Adding LIP message to gps queue.");
|
|
msgCell cell = new msgCell();
|
|
|
|
//IMEI subscriber
|
|
if (element.Attributes["subscriber"].Value != null)
|
|
cell.IMEI = element.Attributes["subscriber"].Value;
|
|
else
|
|
Utils.WriteLine("subscriber == null");
|
|
|
|
//LAT latitude
|
|
if (element.Attributes["latitude"].Value != null)
|
|
cell.lat = element.Attributes["latitude"].Value;
|
|
else
|
|
Utils.WriteLine("latitude == null");
|
|
|
|
//LNG
|
|
if (element.Attributes["longitude"].Value != null)
|
|
cell.lng = element.Attributes["longitude"].Value;
|
|
else
|
|
Utils.WriteLine("longitude == null");
|
|
|
|
//time
|
|
if (element.Attributes["time"].Value != null)
|
|
cell.time70 = uint.Parse(element.Attributes["time"].Value);
|
|
else
|
|
Utils.WriteLine("time == null");
|
|
|
|
//speed speed
|
|
if (element.Attributes["speed"].Value != null)
|
|
{
|
|
cell.spd = element.Attributes["speed"].Value;
|
|
Double speed = 0;
|
|
|
|
if ((Double.TryParse(cell.spd,out speed))&&(speed>250))
|
|
{
|
|
cell.spd = "0";
|
|
cell.lat = "0";
|
|
cell.lng = "0";
|
|
}
|
|
}
|
|
else
|
|
SM.Print("time == null");
|
|
|
|
//poll response
|
|
cell.poll = 0;
|
|
|
|
OnEventToDisplayOnUI(String.Format("»»» Position [{0:0.0000},{1:0.0000}] from {2}", Math.Round(Double.Parse(cell.lat), 4),
|
|
Math.Round(Double.Parse(cell.lng), 4), cell.IMEI));
|
|
|
|
Program.gpsQueue.PostItem(cell);
|
|
}
|
|
else
|
|
{
|
|
Utils.WriteLine("LIP message = null!");
|
|
}
|
|
|
|
Thread.Sleep(100);
|
|
}// else LRRP
|
|
else
|
|
{
|
|
Parse_LRRP p_lrrp = new Parse_LRRP();
|
|
MOTO.GPS_POS gps_pos = p_lrrp.ProcessCommand(data, data_len);
|
|
if (gps_pos != null)
|
|
{
|
|
Utils.WriteLine("Adding LRRP message to gps queue.");
|
|
msgCell cell = new msgCell();
|
|
//IMEI
|
|
cell.IMEI = rec_issi.ToString();
|
|
//LAT
|
|
cell.lat = ((gps_pos.pos.direction_lat == 'N') ? "" : "-")
|
|
+ gps_pos.pos.degrees_lat.ToString()
|
|
+ "."
|
|
+ (gps_pos.pos.minutes_lat + gps_pos.pos.fraction_lat).ToString();
|
|
//LNG
|
|
cell.lng = ((gps_pos.pos.direction_lng == 'E') ? "" : "-")
|
|
+ gps_pos.pos.degrees_lng.ToString()
|
|
+ "."
|
|
+ (gps_pos.pos.minutes_lng + gps_pos.pos.fraction_lng).ToString();
|
|
//time
|
|
cell.time = new DateTime();
|
|
cell.time = new DateTime(gps_pos.time.year, gps_pos.time.month, gps_pos.time.day, gps_pos.time.hour, gps_pos.time.minute, gps_pos.time.second);
|
|
//speed
|
|
cell.spd = "0";
|
|
//poll response
|
|
cell.poll = 0;
|
|
|
|
OnEventToDisplayOnUI(String.Format("»»» Position [{0:0.0000},{1:0.0000}] from {2}", Math.Round(Double.Parse(cell.lat), 4),
|
|
Math.Round(Double.Parse(cell.lng), 4), cell.IMEI));
|
|
|
|
Program.gpsQueue.PostItem(cell);
|
|
}
|
|
else
|
|
{
|
|
Utils.WriteLine("LRRP message = null!");
|
|
}
|
|
|
|
}
|
|
}
|
|
public byte[] SDR_Parse(out uint data_len, out long issi)
|
|
{
|
|
int cm_len = 0;
|
|
int cm_type = -1;
|
|
int i, val;
|
|
byte[] data =null;
|
|
byte[] buf = new byte[1024];
|
|
int len;
|
|
issi = 0;
|
|
data_len = 0;
|
|
|
|
len = stream.Read(buf, 0, 2);
|
|
if (len == 0)
|
|
{
|
|
Utils.WriteLine(String.Format("error: broken pipe {0}\n", len));
|
|
return null;
|
|
}
|
|
if (len != 2)
|
|
{
|
|
Utils.WriteLine(String.Format("error: reading len {0}\n", len));
|
|
return null;
|
|
}
|
|
|
|
cm_len = (byte)buf[0];
|
|
cm_len <<= 8;
|
|
cm_len |= (byte)buf[1];
|
|
|
|
Utils.WriteLine(String.Format("CM Length={0}\n", cm_len));
|
|
|
|
//!! implement the interrupted TCP/IP message
|
|
int bread = stream.Read(buf, 0, cm_len);
|
|
if(DEBUG)
|
|
{
|
|
Utils.WriteLine("#############################################");
|
|
Utils.WriteLine("RX: cm_len: " + cm_len + " bread:" + bread);
|
|
SDR.Print(buf, bread, true);
|
|
Utils.WriteLine("#############################################");
|
|
}
|
|
|
|
if (bread != cm_len)
|
|
{
|
|
Utils.WriteLine("ERROR: cm_len:" + cm_len + " != bread:" + bread);
|
|
|
|
return null;
|
|
}
|
|
|
|
cm_type = buf[0];
|
|
|
|
Utils.WriteLine(String.Format("CM Type[{0}]: ", cm_type));
|
|
|
|
switch (cm_type)
|
|
{
|
|
case 0x00: // ----------------------------------------------------------------------- CM DATA
|
|
|
|
Utils.WriteLine(String.Format("(CM_DATA)\n"));
|
|
Utils.WriteLine(String.Format("Source Addr={0} {1} {2}\n", buf[1], buf[2], buf[3]));
|
|
Utils.WriteLine(String.Format("Destin Addr={0} {1} {2}\n", buf[4], buf[5], buf[6]));
|
|
Utils.WriteLine(String.Format("Protocol ID=0x{0}\n", buf[7] & 0x00ff));
|
|
Utils.WriteLine(String.Format("CM flags={0}\n", buf[8]));
|
|
Utils.WriteLine(String.Format("Msg reference={0}\n", buf[9]));
|
|
Utils.WriteLine(String.Format("Area={0}\n", buf[10]));
|
|
|
|
// compute decimal issi
|
|
long c1 = (byte)buf[1];
|
|
long c2 = (byte)buf[2];
|
|
long c3 = (byte)buf[3];
|
|
//Console.Write("c1=%ld c2=%ld c3=%ld\r\n", c1, c2, c3);
|
|
c3 += c1 << 16;
|
|
//Console.Write("c1=%ld c2=%ld c3=%ld\r\n", c1, c2, c3);
|
|
c3 += c2 << 8;
|
|
//Console.Write("c1=%ld c2=%ld c3=%ld\r\n", c1, c2, c3);
|
|
issi = c3;
|
|
//*issi = buf[1]<<16 + buf[2]<<7 + buf[3];
|
|
|
|
uint tl_len; // = buf[11];
|
|
tl_len = (((uint)buf[11] & 0x00FF) << 8);
|
|
//tl_len <<= 8;
|
|
tl_len += ((uint)buf[12] & 0x00FF);
|
|
|
|
|
|
Utils.WriteLine(String.Format("TL Length (bits)=0x{0:X}\n", tl_len));
|
|
|
|
int tl_type = buf[13];
|
|
|
|
Utils.WriteLine(String.Format("TL Type[0x{0:X}]: ", tl_type));
|
|
|
|
switch (tl_type)
|
|
{
|
|
|
|
case 0x00: // DATA
|
|
|
|
Utils.WriteLine("TL-Data:");
|
|
Utils.WriteLine(String.Format("Headers: {0:X} {1:X} {2:X} {3:X} {4:X}\n", buf[14], buf[15], buf[16], buf[17], buf[18]));
|
|
Console.Write("Data: \n");
|
|
|
|
i = 0;
|
|
data_len = tl_len / 8 - 6;
|
|
data = new byte[data_len];
|
|
while (i < tl_len / 8 - 6) // get rid of the len+headers (1+5B)
|
|
{
|
|
|
|
Console.Write("{0:X}({1},{2}) ", buf[19 + i], i, tl_len);
|
|
|
|
// return payload
|
|
data[i] = buf[19 + i];
|
|
i++;
|
|
}
|
|
|
|
Console.Write("\n");
|
|
|
|
// print text message
|
|
Console.Write("Text Message:\n");
|
|
i=0;
|
|
while (i<tl_len/8-6) // get rid of the len+headers (1+5B)
|
|
{
|
|
Console.Write("%c", buf[19+i]);
|
|
i++;
|
|
}
|
|
Console.Write("\n");
|
|
|
|
// sending a report back
|
|
|
|
byte[] REPORT_ACK = {0x00, 0x0f,
|
|
0x00,
|
|
buf[4], buf[5], buf[6], // source ISSI
|
|
buf[1], buf[2], buf[3], // dest ISSI
|
|
0xc0, // protocol
|
|
0x60, // flags
|
|
0x00, // message reference
|
|
0x00, // area slection
|
|
0x00, 0x10, // TL length (bits)
|
|
0x01, // PDU type = Report
|
|
0x00 // Delivery status = ACK
|
|
};
|
|
REPORT_ACK[11] = buf[9]; // msg_id
|
|
/*
|
|
Console.Write("\r\n send conf !!! \r\n");fflush(stdout);
|
|
for (i=0;i<0x0f+2;i++)
|
|
{
|
|
Console.Write(" %x ",REPORT_ACK[i]);fflush(stdout);
|
|
}
|
|
*/
|
|
stream.Write(REPORT_ACK, 0, 0x0f + 2);
|
|
//Console.Write("\r\n send ok !!! \r\n");fflush(stdout);
|
|
|
|
break;
|
|
|
|
case 0x03: // SHORT_REPORT
|
|
|
|
Console.Write("Short");
|
|
break;
|
|
case 0x01: // REPORT
|
|
Console.Write("Report: \n");
|
|
|
|
val = buf[14]; // this contains the report value
|
|
|
|
i = 0;
|
|
while (i < tl_len / 8 - 1) // get rid of the len (1B)
|
|
{
|
|
Console.Write("{0:X} ", buf[i + 14]);
|
|
i++;
|
|
}
|
|
Console.Write("\n");
|
|
break;
|
|
}
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x04: // ----------------------------------------------------------------------- CM BROADCAST
|
|
|
|
Console.Write("(CM_BROADCAST)\n");
|
|
for (i = 0; i < cm_len - 1; i++)
|
|
Console.Write(buf[i + 1] + " ");
|
|
Console.Write("\n");
|
|
|
|
break;
|
|
|
|
|
|
case 0x02: // ----------------------------------------------------------------------- CM REGISTER request
|
|
|
|
Console.Write("(CM_REGISTER_REQ)\n");
|
|
Console.Write("Error: CM REGISTER REQUEST \n");
|
|
|
|
break;
|
|
|
|
case 0x01: // ----------------------------------------------------------------------- CM REPORT response
|
|
|
|
Console.Write("(CM_REPORT_RESP)\n");
|
|
Console.Write("Source Addr={0:X} {1:X} {2:X}\n", buf[1], buf[2], buf[3]);
|
|
Console.Write("Destin Addr={0:X} {1:X} {2:X}\n", buf[4], buf[5], buf[6]);
|
|
Console.Write("Protocol ID={0:X}\n", buf[7]);
|
|
Console.Write("Msg reference={0:X}\n", buf[8]);
|
|
|
|
val = buf[9];
|
|
|
|
Console.Write("Delivery status[0x{0:X}]:\n", val);
|
|
|
|
switch (val)
|
|
{
|
|
case 0x40: { Console.Write(" DELIVERY_OVERLOAD\n"); } break;
|
|
case 0x41: { Console.Write(" DELIVERY_SERVICE_DISABLED\n"); } break;
|
|
case 0x42: { Console.Write(" DELIVERY_SERV_TEMP_NOT_AVAIL\n"); } break;
|
|
case 0x44: { Console.Write(" DELIVERY_DEST_NOT_AUTH_FOR_SDS\n"); } break;
|
|
case 0x45: { Console.Write(" DELIVERY_UNKNOWN_DEST\n"); } break;
|
|
case 0x47: { Console.Write(" DELIVERY_GROUP_ADDR\n"); } break;
|
|
case 0x4a: { Console.Write(" DELIVERY_NOT_REACHABLE\n"); } break;
|
|
case 0x4b: { Console.Write(" DELIVERY_NOT_REGISTERED\n"); } break;
|
|
case 0x4c: { Console.Write(" DELIVERT_DEST_QUEUE_FULL\n"); } break;
|
|
case 0x4d: { Console.Write(" DELIVERY_MSG_TOO_LONG\n"); } break;
|
|
case 0x4e: { Console.Write(" DELIVERY_DEST_NOT_SUPPORT_PDU\n"); } break;
|
|
case 0x4f: { Console.Write(" DELIVERY_DEST_NOT_CONNECTED\n"); } break;
|
|
case 0x50: { Console.Write(" DELIVERY_PROT_NOT_SUPP\n"); } break;
|
|
case 0x53: { Console.Write(" DELIVERY_DEST_NOT_ACC_SDS\n"); } break;
|
|
case 0x56: { Console.Write(" DELIVERY_DEST_PROHIBITED\n"); } break;
|
|
case 0x58: { Console.Write(" DELIVERY_UNKOWN_SUBSCRIBER\n"); } break;
|
|
case 0x5a: { Console.Write(" DELIVERY_DEST_NOT_REACHABLE\n"); } break;
|
|
case 0x8d: { Console.Write(" DELIVERY_TEXT_ERROR\n"); } break;
|
|
case 0x8e: { Console.Write(" DELIVERY_CORRUPT_INFO\n"); } break;
|
|
}
|
|
break;
|
|
|
|
case 0x03: // ----------------------------------------------------------------------- CM REGISTER response
|
|
|
|
Console.Write("(CM_REGISTER)\n");
|
|
Console.Write("Pass No={0:X} {1:X} {2:X} {3:X}\n", buf[1], buf[2], buf[3], buf[4]);
|
|
Console.Write("ISSI={0:X} {1:X} {2:X}\n", buf[5], buf[6], buf[7]);
|
|
Console.Write("Registration type={0:X}\n", buf[8]);
|
|
|
|
val = buf[9];
|
|
Console.Write("Registration status[0x{0:X}]: ", val);
|
|
|
|
Console.ForegroundColor = ConsoleColor.Green;
|
|
switch (val)
|
|
{
|
|
case 0x00: SM.Print("Address Registered");
|
|
{
|
|
if(registered != SDR_STATUS.Connected)
|
|
registered = SDR_STATUS.Connected;
|
|
|
|
break;
|
|
}
|
|
case 0x01: SM.Print("Duplicate Address"); break;
|
|
case 0x02: SM.Print("Invalid Address"); break;
|
|
case 0x03: SM.Print("Registration Not Available"); break;
|
|
case 0x04: SM.Print("Invalid Pass Number"); break;
|
|
default: SM.Print(" Registration: Unknown Code"); break;
|
|
}
|
|
Console.ResetColor();
|
|
break;
|
|
} // end switch
|
|
|
|
return data;
|
|
}
|
|
#endregion
|
|
|
|
#region Connect and send msg
|
|
private string displayedMessage = "Connecting to SDR";
|
|
public void ConnectAndMaintain()
|
|
{
|
|
try
|
|
{
|
|
if (tcpClient == null)
|
|
{
|
|
OnEventToDisplayOnUI(displayedMessage);
|
|
displayedMessage = "Reconnecting to SDR";
|
|
try
|
|
{
|
|
tcpClient = new TcpClient(IP, port);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if (!ex.ToString().Contains("failed because the connected party did not properly respond"))
|
|
WriteLine("Exception " + ex.ToString(), ConsoleColor.DarkRed);
|
|
else
|
|
{
|
|
//OnEventToDisplayOnUI("Unable to connect to SDR");
|
|
}
|
|
}
|
|
//Thread.Sleep(1000);
|
|
}
|
|
|
|
if (stream == null && tcpClient != null)
|
|
{
|
|
stream = tcpClient.GetStream();
|
|
}
|
|
Thread.Sleep(500);
|
|
//send connect message
|
|
if (registered != SDR_STATUS.Connected)
|
|
{
|
|
if (stream != null)
|
|
{
|
|
//tcpClient.Write(new byte[11] { 0x00, 0x09 , 0x02, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,0x05,0x00}, 11);
|
|
OnEventToDisplayOnUI("Starting SDR Connection");
|
|
WriteLine("Starting SDR Connection");
|
|
byte[] data = SDR.GenConnectMSG_ISSI(ISSI, pass);
|
|
Console.Write("TX:");
|
|
SDR.Print(data, data.Length, false);
|
|
//send data
|
|
bool resp = Write(data, data.Length);
|
|
if (resp)
|
|
Console.WriteLine("Connection data sent to SDR!!! waiting for response!!! ");
|
|
else
|
|
Console.WriteLine("ERROR sending data to SDR!!!! ");
|
|
}
|
|
}
|
|
else
|
|
Console.WriteLine("Connected and waiting for data... ");
|
|
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
//Console.WriteLine("ERROR in ConnectAndMaintain");
|
|
if(!ex.ToString().Contains("failed because the connected party did not properly respond"))
|
|
WriteLine("Exception " + ex.ToString(), ConsoleColor.DarkRed);
|
|
|
|
if (registered != SDR_STATUS.Disconnected)
|
|
{
|
|
registered = SDR_STATUS.Disconnected;
|
|
}
|
|
stream = null;
|
|
tcpClient = null;
|
|
}
|
|
finally
|
|
{
|
|
Thread.Sleep(100);
|
|
}
|
|
}
|
|
|
|
public static byte[] GenConnectMSG_ISSI(Int64 ISSI, String pass)// in case of LRRP pass=IP
|
|
{
|
|
byte[] ret = new byte[9];
|
|
|
|
String[] split = pass.Split(new char[] {'.'}, StringSplitOptions.RemoveEmptyEntries);
|
|
|
|
ret[0] = (byte)CM_MSG_TYPE.CM_REGISTER_REQ; //msg type
|
|
/*
|
|
ret[1] = (byte)(((UInt32)split[0] & 0xff000000) >> 24); //pass
|
|
ret[2] = (byte)(((UInt32)pass & 0x00ff0000) >> 16); //pass
|
|
ret[3] = (byte)(((UInt32)pass & 0x0000ff00) >> 8); //pass
|
|
ret[4] = (byte)(((UInt32)pass & 0x000000ff)); //pass
|
|
*/
|
|
ret[1] = (byte)(Int32.Parse(split[0])); //pass
|
|
ret[2] = (byte)(Int32.Parse(split[1])); //pass
|
|
ret[3] = (byte)(Int32.Parse(split[2])); //pass
|
|
ret[4] = (byte)(Int32.Parse(split[3]) ); //pass
|
|
|
|
ret[5] = (byte)(((UInt32)ISSI & 0x00ff0000) >> 16); //ISSI
|
|
ret[6] = (byte)(((UInt32)ISSI & 0x0000ff00) >> 8); //ISSI
|
|
ret[7] = (byte)(((UInt32)ISSI & 0x000000ff)); //ISSI
|
|
|
|
ret[8] = 0x00; //reserved
|
|
return addMsgLength(ret);
|
|
}
|
|
public static byte cm_msg_id=0;
|
|
public static byte[] SDR_CMD_SendMsg(UInt32 sourISSI, UInt32 DestISSI, byte[] buf, int buflen)
|
|
{
|
|
if (cm_msg_id > 0xfe) cm_msg_id = 0;
|
|
cm_msg_id += 1;
|
|
byte[] MSG = {0x00, 0x00, // CM length = to be computed
|
|
0x00, //CM_DATA
|
|
(byte)(((UInt32)sourISSI&0xff0000)>>16), // source ISSI
|
|
(byte)(((UInt32)sourISSI&0x00ff00)>>8),
|
|
(byte)(((UInt32)sourISSI&0x0000ff)),
|
|
|
|
(byte)(((UInt32)DestISSI&0x00ff0000)>>16), // destination ISSI
|
|
(byte)(((UInt32)DestISSI&0x0000ff00)>>8),
|
|
(byte)(((UInt32)DestISSI&0x000000ff)),
|
|
|
|
0x82,//0xC0, //CM_PROTOCOL, // protocol
|
|
0x60, // flags
|
|
cm_msg_id, // message reference
|
|
0x00, // area selection
|
|
|
|
0x00, 0x00, // TL length (bits) = to be completed
|
|
0x00, // PDU type = TL-DATA
|
|
0x80, // TL flags
|
|
0x00, // validity period
|
|
0x00, 0x00, 0x00, // forward address
|
|
// TL data = to be sent separately
|
|
};
|
|
|
|
|
|
// compute the CM length in bytes
|
|
MSG[0] = (byte)(((0x13 + buflen) & 0xff00) >> 8);
|
|
MSG[1] = (byte)((0x13 + buflen) & 0x00ff);
|
|
|
|
// complete the TL length in bits
|
|
MSG[13] = (byte)((((buflen + 6) * 8) & 0xff00) >> 8);
|
|
MSG[14] = (byte)(((buflen + 6) * 8) & 0x00ff);
|
|
|
|
|
|
byte[] temp = new byte[0x13 + 2 + buflen];
|
|
int i;
|
|
Console.WriteLine("SDR-CM-DATA:\nHeaders:");
|
|
for (i = 0; i < 0x13 + 2; i++)
|
|
{
|
|
Console.Write("0x{0:X} ", MSG[i]);
|
|
temp[i] = MSG[i];
|
|
}
|
|
Console.Write("\nTL-Data:");
|
|
for (i = 0; i < buflen; i++)
|
|
{
|
|
Console.Write("0x{0:X} ", buf[i]);
|
|
temp[0x13 + 2 + i] = buf[i];
|
|
}
|
|
Console.Write("\n");
|
|
|
|
return temp;
|
|
}
|
|
|
|
public void SendCallOutMessage(Int32 DestISSI, byte[] msg)
|
|
{
|
|
Console.Write("TX:");
|
|
SDR.Print(msg, msg.Length, false);
|
|
//send data
|
|
bool resp = Write(msg, msg.Length);
|
|
if (resp)
|
|
{
|
|
SDR.WriteLine(String.Format("»»» Call OUT to {0} [{1}]", DestISSI, BitConverter.ToString(msg)));
|
|
OnEventToDisplayOnUI(String.Format("»»» Call OUT to {0} [{1}]", DestISSI, BitConverter.ToString(msg)));
|
|
}
|
|
else
|
|
SDR.WriteLine(String.Format("φφφ Call OUT not sent to {0} [{1}]", DestISSI, BitConverter.ToString(msg)));
|
|
}
|
|
/*
|
|
public void SEND_CALL_OUT_MESSAGE_TEST_623(int type)
|
|
{
|
|
Utils.WriteLine("SEND_CALL_OUT_MESSAGE_TEST_623 : " ,ConsoleColor.Cyan);
|
|
|
|
|
|
if (cm_msg_id > 0xfe) cm_msg_id = 0;
|
|
cm_msg_id += 1;
|
|
|
|
LIPSDR.CallOutFunction function = (LIPSDR.CallOutFunction) (type%4 + 1);
|
|
|
|
|
|
|
|
//Stds_CallOutAlertPDU_sdsEncoder(uint callOutNumber, uint callOutSeverity, uint tgNumber, string calloutText, TGctrl tgCtrl)
|
|
//Stds_CallOut_Message_header_sdsEncoder(uint Source_ISSI, uint Destination_ISSI, int PIvalue, int msgReferenceCounter, Byte [] bytemsg)
|
|
//LIPSDR.Stds_CallOutAlertPDU_sdsEncoder(LIPSDR.callOutNumber++, 3, 00, "this is a test", LIPSDR.TGctrl.TGChangeOnAlert)
|
|
|
|
byte[] data = LIPSDR.Stds_CallOut_Message_header_sdsEncoder(ISSI, 623, 195, cm_msg_id,
|
|
LIPSDR.Stds_CallOutAlertPDU_sdsEncoder(LIPSDR.callOutNumber++, function, 1, 0, "1", LIPSDR.TGctrl.TGControlNotUsed));
|
|
LIPSDR.printBytesArray(data);
|
|
Utils.WriteLine("Encrypted SMS length: " + data.Length, ConsoleColor.Cyan);
|
|
|
|
|
|
//send data
|
|
bool resp = Write(data, data.Length);
|
|
if (resp)
|
|
{
|
|
SDR.WriteLine(String.Format("»»» Call out to {0} [{1}]", 623,'1'), ConsoleColor.Yellow);
|
|
OnEventToDisplayOnUI(String.Format("»»» TM to {0} [{1}]", 623, '1'));
|
|
}
|
|
else
|
|
SDR.WriteLine(String.Format("φφφ TM not sent to {0} [{1}]", 623, '1'), ConsoleColor.Red);
|
|
|
|
Console.Write("TX:");
|
|
SDR.Print(data, data.Length, false);
|
|
}*/
|
|
|
|
public void SendCallOut(UInt32 destISSI, UInt16 callOutSeverity, string geoName)
|
|
{
|
|
|
|
UInt32 sourceISSI = (UInt32)Program.cfg.SDR_ISSI;
|
|
UInt32 tgNumber = 10010001; //need to get the Radio TalkGroup
|
|
uint tgCtrl = (uint)TGctrl.TGChangeUserInter;
|
|
if (cm_msg_id > 0xfe) cm_msg_id = 0;
|
|
cm_msg_id += 1;
|
|
|
|
uint calloutUUID = ++LIPSDR.callOutNumber;
|
|
//if (ddlTgCtrl.SelectedText == TGctrl.TGChangeOnAlert.ToString())
|
|
// tgCtrl = (uint)TGctrl.TGChangeOnAlert;
|
|
|
|
string calloutKey = getCalloutKey(destISSI, callOutSeverity);
|
|
|
|
lock (calloutUUIDLock)
|
|
{
|
|
// remove previous callout with the same severity to the same radio issi
|
|
if (radioISSIWithSeverityToCalloutUUIDDictionary.ContainsKey(calloutKey))
|
|
{
|
|
uint previousCalloutUUID = radioISSIWithSeverityToCalloutUUIDDictionary[calloutKey];
|
|
// send callout clear for previous callout
|
|
// to decide
|
|
|
|
radioISSIWithSeverityToCalloutUUIDDictionary.Remove(calloutKey);
|
|
}
|
|
|
|
// store the callout uuid for this radio issi with this severity
|
|
radioISSIWithSeverityToCalloutUUIDDictionary.Add(calloutKey, calloutUUID);
|
|
}
|
|
|
|
|
|
byte[] result = CallOutClass.SendCallOut(true, (uint)CallOutFunction.Alert, calloutUUID, callOutSeverity, tgCtrl, tgNumber, ref cm_msg_id, sourceISSI, destISSI, geoName);
|
|
//LIPSDR.printBytesArray(result);
|
|
Utils.WriteLine("Encrypted CallOut length: " + result.Length, ConsoleColor.Cyan);
|
|
//send data
|
|
bool resp = Write((byte[])result, (int)result.Length);
|
|
if (resp)
|
|
{
|
|
SDR.WriteLine(String.Format("»»» Call out to {0} [{1}]", destISSI, callOutSeverity), ConsoleColor.Yellow);
|
|
OnEventToDisplayOnUI(String.Format("»»» TM to {0} [{1}]", destISSI, callOutSeverity));
|
|
}
|
|
else
|
|
SDR.WriteLine(String.Format("φφφ TM not sent to {0} [{1}]", destISSI, callOutSeverity), ConsoleColor.Red);
|
|
|
|
Console.Write("TX:");
|
|
SDR.Print(result, result.Length, false);
|
|
|
|
Console.WriteLine(LIPSDR.callOutNumber);
|
|
|
|
}
|
|
|
|
public void SendCallOutStop(UInt32 destISSI, UInt16 callOutSeverity)
|
|
{
|
|
|
|
UInt32 sourceISSI = (UInt32)Program.cfg.SDR_ISSI;
|
|
string geoName = "";
|
|
|
|
|
|
//if (ddlTgCtrl.SelectedText == TGctrl.TGChangeOnAlert.ToString())
|
|
// tgCtrl = (uint)TGctrl.TGChangeOnAlert;
|
|
|
|
uint? calloutUUID = GetCalloutUUIDForISSI(destISSI, callOutSeverity);
|
|
|
|
if(calloutUUID == null)
|
|
{
|
|
Utils.WriteLine($"No callout to clear for issi {destISSI} with severity {callOutSeverity}", ConsoleColor.Yellow);
|
|
return;
|
|
}
|
|
|
|
byte[] result = CallOutClass.SendCallOut(true, (uint)CallOutFunction.Clear, (uint)calloutUUID , 0, (uint)TGctrl.TGControlNotUsed, 0, ref cm_msg_id, sourceISSI, destISSI, geoName);
|
|
//LIPSDR.printBytesArray(result);
|
|
Utils.WriteLine("Encrypted CallOut length: " + result.Length, ConsoleColor.Cyan);
|
|
//send data
|
|
bool resp = Write((byte[])result, (int)result.Length);
|
|
|
|
Console.Write("TX:");
|
|
SDR.Print(result, result.Length, false);
|
|
Console.WriteLine(LIPSDR.callOutNumber);
|
|
|
|
}
|
|
|
|
|
|
private uint? GetCalloutUUIDForISSI(UInt32 destISSI, UInt16 callOutSeverity)
|
|
{
|
|
uint? result = null;
|
|
string calloutKey = getCalloutKey(destISSI, callOutSeverity);
|
|
|
|
lock (calloutUUIDLock)
|
|
{
|
|
// remove previous callout with the same severity to the same radio issi
|
|
if (radioISSIWithSeverityToCalloutUUIDDictionary.ContainsKey(calloutKey))
|
|
result = radioISSIWithSeverityToCalloutUUIDDictionary[calloutKey];
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
private string getCalloutKey(UInt32 destISSI, UInt16 callOutSeverity)
|
|
{
|
|
return destISSI + "_" + callOutSeverity;
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SEND_SMS(UInt32 DestISSI, string msg)
|
|
{
|
|
Utils.WriteLine("SEND SMS : " + msg, ConsoleColor.Cyan);
|
|
string tmp_str = msg + " ";
|
|
if (cm_msg_id > 0xfe) cm_msg_id = 0;
|
|
cm_msg_id += 1;
|
|
|
|
//byte[] data = SDR.SDR_CMD_SendMsg(ISSI, DestISSI, Encoding.UTF8.GetBytes(msg), Encoding.UTF8.GetBytes(msg).Length);
|
|
byte[] data = LIPSDR.Stds_Cm_Message_header_sdsEncoder(ISSI, DestISSI, SMSprotocolID, cm_msg_id, tmp_str);
|
|
Utils.WriteLine("Encrypted SMS length: " + data.Length, ConsoleColor.Cyan);
|
|
|
|
|
|
//send data
|
|
bool resp = Write(data, data.Length);
|
|
if (resp)
|
|
{
|
|
SDR.WriteLine(String.Format("»»» TM to {0} [{1}]", DestISSI, msg), ConsoleColor.Yellow);
|
|
OnEventToDisplayOnUI(String.Format("»»» TM to {0} [{1}]", DestISSI, msg));
|
|
}
|
|
else
|
|
SDR.WriteLine(String.Format("φφφ TM not sent to {0} [{1}]", DestISSI, msg), ConsoleColor.Red);
|
|
|
|
Console.Write("TX:");
|
|
SDR.Print(data, data.Length, false);
|
|
}
|
|
|
|
|
|
public void SendSMS_4_Test(Int64 radioID, Int64 gatewayID, Int64 gatewayRadioID, string message, int type)
|
|
{
|
|
byte[] data = new byte[] { };
|
|
|
|
if (type == 20)
|
|
data = LIPSDR.Stds_Cm_Message_header_sdsEncoder((uint)ISSI, (uint)radioID, SMSprotocolID, cm_msg_id++ % 0xFE, message);
|
|
else if (type == 00)
|
|
data = LIPSDR.Stds_Cm_Message_header_sdsEncoder_SF((uint)ISSI, (uint)radioID, 0xC0, cm_msg_id++ % 0xFE, message, false, false);
|
|
else if (type == 10)
|
|
data = LIPSDR.Stds_Cm_Message_header_sdsEncoder_SF((uint)ISSI, (uint)radioID, 0xC0, cm_msg_id++ % 0xFE, message, true, false);
|
|
else if (type == 11)
|
|
data = LIPSDR.Stds_Cm_Message_header_sdsEncoder_SF((uint)ISSI, (uint)radioID, 0xC0, cm_msg_id++ % 0xFE, message, true, true);
|
|
else if (type == 01)
|
|
data = LIPSDR.Stds_Cm_Message_header_sdsEncoder_SF((uint)ISSI, (uint)radioID, 0xC0, cm_msg_id++ % 0xFE, message, false, true);
|
|
|
|
bool resp = Write(data, data.Length);
|
|
if (resp)
|
|
SDR.WriteLine(String.Format("»»» TM to {0} [{1}]", radioID, message));
|
|
else
|
|
SDR.WriteLine(String.Format("φφφ TM not sent to {0} [{1}]", radioID, message));
|
|
|
|
Console.Write("TX:");
|
|
SDR.Print(data, data.Length, false);
|
|
}
|
|
|
|
public void Send_Imed_Loc_req(UInt32 DestISSI, bool isLong, string seqNumber)
|
|
{
|
|
byte[] data;
|
|
|
|
data = LIPSDR.Stds_POLL_header_sdsEncoder(ISSI, DestISSI, 10, cm_msg_id++ % 0xFE);
|
|
|
|
//send data
|
|
bool resp = Write(data, data.Length);
|
|
if (resp)
|
|
{
|
|
SDR.WriteLine(String.Format("»»» Poll req to {0}", DestISSI));
|
|
OnEventToDisplayOnUI(String.Format("»»» Poll req to {0}", DestISSI));
|
|
}
|
|
//Console.WriteLine("»»» Poll request to " + DestISSI);
|
|
else
|
|
SDR.WriteLine(String.Format("φφφ Poll req to {0}", DestISSI));
|
|
|
|
Console.Write("TX:");
|
|
SDR.Print(data, data.Length, false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sends the received message through TCP witout any formatting
|
|
/// </summary>
|
|
/// <param name="rawData">String containing raw Data which needs to be sent</param>
|
|
public void Send_RAW_Data(UInt32 DestISSI, String rawData)
|
|
{
|
|
Console.WriteLine("TO SEND RAW DATA : " + rawData);
|
|
byte[] data = new byte[rawData.Length / 2];
|
|
for (int i = 0; i < rawData.Length/2; i++)
|
|
{
|
|
data[i] = Convert.ToByte(rawData.Substring(i*2, 2), 16);
|
|
}
|
|
|
|
//byte[] data = System.Text.Encoding.UTF8.GetBytes(rawData);
|
|
|
|
bool resp = Write(data, data.Length);
|
|
if (resp)
|
|
{
|
|
OnEventToDisplayOnUI(String.Format("»»» Raw Data to {0}", DestISSI));
|
|
Console.ForegroundColor = ConsoleColor.Magenta;
|
|
Console.Write("TX:");
|
|
SDR.Print(data, data.Length, false);
|
|
Console.ForegroundColor = ConsoleColor.Gray;
|
|
|
|
}
|
|
else
|
|
SDR.WriteLine(String.Format("φφφ Raw req to {0}", DestISSI), ConsoleColor.Red);
|
|
}
|
|
|
|
#endregion
|
|
|
|
//aux
|
|
#region AUX
|
|
public static byte[] addMsgLength(byte[] data)
|
|
{
|
|
byte[] retData = new byte[data.Length + 2];
|
|
byte[] len = BitConverter.GetBytes(data.Length);
|
|
retData[0] = len[1];
|
|
retData[1] = len[0];
|
|
for (int i = 0; i < data.Length; i++)
|
|
{
|
|
retData[2 + i] = data[i];
|
|
}
|
|
return retData;
|
|
}
|
|
|
|
public static void Print(byte[] data, int length, bool inOut)
|
|
{
|
|
//Console.Clear();
|
|
//Console.WriteLine("--------------------------------------------------------------------------- " + length);
|
|
Console.Write("Data (" + ((inOut) ? "RECEIVED" : "SENT") + "): ");
|
|
Console.WriteLine();
|
|
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
if ((i % 8) == 0) Console.WriteLine();
|
|
Console.Write(" 0x" + data[i].ToString("X2"));
|
|
}
|
|
Console.WriteLine("");
|
|
//Console.WriteLine("--------------------------------------------------------------------------- ");
|
|
}
|
|
|
|
#endregion
|
|
|
|
public enum SDR_STATUS
|
|
{
|
|
Connected = 0x00,
|
|
Disconnected = 0x01,
|
|
Connecting = 0x02,
|
|
NoConnection = 0x03,
|
|
Disconnecting = 0x04
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Write a specific message into console
|
|
/// </summary>
|
|
/// <param name="str">Message which needs to be written into console</param>
|
|
public static void WriteLine(string str)
|
|
{
|
|
WriteLine(str, ConsoleColor.Gray);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Write a specific message into console using the desired color
|
|
/// </summary>
|
|
/// <param name="str">Message which will be written into console</param>
|
|
/// <param name="color">Color with which the message will be written</param>
|
|
public static void WriteLine(string str, ConsoleColor color)
|
|
{
|
|
Console.ForegroundColor = ConsoleColor.DarkGray;
|
|
Console.Write(String.Format("[### {0:H:mm:ss} ###] ", DateTime.Now));
|
|
Console.ForegroundColor = color;
|
|
Console.Write(String.Format("{0}\n", str));
|
|
Console.ForegroundColor = ConsoleColor.Gray;
|
|
}
|
|
|
|
|
|
// EVENTS
|
|
public delegate void EventToDisplayOnUIDEl(string msg);
|
|
public event EventToDisplayOnUIDEl OnEventToDisplayOnUI;
|
|
public delegate void OnSDRStoppedDEl();
|
|
public event OnSDRStoppedDEl OnSDRStopped;
|
|
|
|
|
|
|
|
#region TEST CallOut obsolete
|
|
/*
|
|
public byte[] SendCallOut(uint callOutFunction, uint callOutNumber, uint callOutSeverity, uint tgCtrl, uint tgNumber,
|
|
ref byte cm_msg_id, UInt32 sourceISSI, UInt32 destISSI, string data)
|
|
{
|
|
// Call Out Function [15-12] + CallOutNumber [11-4] + CallOutSeverity [3-0]
|
|
//uint bytes23 = (uint)CallOutFunction.Alert * 4096 + callOutNumber * 16 + callOutSeverity;
|
|
UInt16 callOut = (UInt16)(callOutFunction * 0x1000 + callOutNumber * 0x10 + callOutSeverity);
|
|
|
|
// TGctrl [31-30] + TGnumber [29-6] + Reserved [5-0]
|
|
UInt32 talkGroup = (uint)tgCtrl * 0x40000000 + tgNumber * 0x40 + 0x00;
|
|
|
|
|
|
byte[] result = SDR_CallOut(ref cm_msg_id, sourceISSI, destISSI, callOut, talkGroup, data);
|
|
|
|
bool resp = Write(result, result.Length);
|
|
|
|
return result;
|
|
}
|
|
|
|
private byte[] SDR_CallOut(ref byte cm_msg_id, UInt32 sourceISSI, UInt32 destISSI, UInt16 callOut, UInt32 talkGroup, string data)
|
|
{
|
|
int buflen = 0;
|
|
if (data != null) buflen = data.Length;
|
|
|
|
byte[] cmBytes = SDR_CM_CallOut(ref cm_msg_id, sourceISSI, destISSI);
|
|
|
|
byte[] tlBytes = SDR_TP_CallOut(callOut, talkGroup);
|
|
|
|
LIPSDR.CallOutFunction callOutFunction = (LIPSDR.CallOutFunction)((callOut >> 12) & 0x0000f);
|
|
if (callOutFunction == LIPSDR.CallOutFunction.Test ||
|
|
callOutFunction == LIPSDR.CallOutFunction.Info ||
|
|
callOutFunction == LIPSDR.CallOutFunction.Clear)
|
|
Array.Resize(ref tlBytes, 5);
|
|
else if (callOutFunction == LIPSDR.CallOutFunction.Availability ||
|
|
callOutFunction == LIPSDR.CallOutFunction.AvailabilityRequest)
|
|
Array.Resize(ref tlBytes, 4);
|
|
|
|
// compute the CM length in bytes (count starting with 'CM PDU Type')
|
|
if (cmBytes != null)
|
|
{
|
|
int cmLength = (cmBytes.Length - 2) + tlBytes.Length;
|
|
|
|
cmBytes[0] = (byte)(((buflen + cmLength) & 0xff00) >> 8);
|
|
cmBytes[1] = (byte)((buflen + cmLength) & 0x00ff);
|
|
}
|
|
|
|
// compute the TL length in bits
|
|
// the TL fields are taken into consideration (count starting with 'TL encoding scheme' and transform in bits (*8) ) ==> 9 fields
|
|
if (tlBytes != null)
|
|
{
|
|
int tlLength = tlBytes.Length - 2;
|
|
|
|
tlBytes[0] = (byte)((((buflen + tlLength) * 8) & 0xff00) >> 8);
|
|
tlBytes[1] = (byte)(((buflen + tlLength) * 8) & 0x00ff);
|
|
}
|
|
|
|
if (buflen > 0)
|
|
return Combine(cmBytes, tlBytes, Encoding.UTF8.GetBytes(data));
|
|
|
|
return Combine(cmBytes, tlBytes);
|
|
|
|
}
|
|
|
|
|
|
private byte[] SDR_CM_CallOut(ref byte cm_msg_id, UInt32 sourceISSI, UInt32 destISSI)
|
|
{
|
|
if (cm_msg_id > 0xfe) cm_msg_id = 0;
|
|
cm_msg_id += 1;
|
|
|
|
byte[] msg = { 0x00,
|
|
0x00, //1 CM length = to be computed
|
|
0x00, //2 CM PDU Type
|
|
(byte)(((UInt32)sourceISSI & 0xff0000)>>16), //3 source ISSI
|
|
(byte)(((UInt32)sourceISSI & 0x00ff00)>>8), //4 source ISSI
|
|
(byte)(((UInt32)sourceISSI & 0x0000ff)), //5 source ISSI
|
|
|
|
(byte)(((UInt32)destISSI & 0x00ff0000)>>16), //6 destination ISSI
|
|
(byte)(((UInt32)destISSI & 0x0000ff00)>>8), //7 destination ISSI
|
|
(byte)(((UInt32)destISSI & 0x000000ff)), //8 destination ISSI
|
|
|
|
0xC3, //9 CM_PROTOCOL ( CallOut),
|
|
0x60, //10 flags (SDS type=0112, SS=02, Reserved=00002)
|
|
cm_msg_id, //11 message reference
|
|
0x00 //12 area selection
|
|
};
|
|
return msg;
|
|
|
|
}
|
|
|
|
private byte[] SDR_TP_CallOut(UInt16 callOut, UInt32 talkGroup)
|
|
{
|
|
byte[] callOutBytes = BitConverter.GetBytes(callOut);
|
|
byte[] talkGroupBytes = BitConverter.GetBytes(talkGroup);
|
|
|
|
byte[] msg = { 0x00, //13 TL length (bits) = to be completed
|
|
0x00, //14 TL length (bits) = to be completed
|
|
(byte)LIPSDR.TextEncoding.ISO8859Latin1, //15 TL encoding scheme
|
|
callOutBytes[1], //16 TL call out number + call out severity
|
|
callOutBytes[0], //17 TL call out number + call out severity
|
|
talkGroupBytes[3], //18 TL TG ( ctrl + number )
|
|
talkGroupBytes[2], //18 TL TG ( ctrl + number )
|
|
talkGroupBytes[1], //19 TL TG ( ctrl + number )
|
|
talkGroupBytes[0], //20 TL TG ( ctrl + number )
|
|
0x00, //21 forward address
|
|
0x00, //22 forward address
|
|
0x00 //23 forward address
|
|
};
|
|
|
|
return msg;
|
|
|
|
}
|
|
|
|
*/
|
|
#endregion
|
|
|
|
|
|
#region TEST CallOut
|
|
/*
|
|
public byte[] SendCallOut(bool prefixWithSize, uint callOutFunction, uint callOutNumber, uint callOutSeverity, uint tgCtrl, uint tgNumber,
|
|
ref byte cm_msg_id, UInt32 sourceISSI, UInt32 destISSI, string data)
|
|
{
|
|
// Call Out Function [15-12] + CallOutNumber [11-4] + CallOutSeverity [3-0]
|
|
//uint bytes23 = (uint)CallOutFunction.Alert * 4096 + callOutNumber * 16 + callOutSeverity;
|
|
UInt16 callOut = (UInt16)(callOutFunction * 0x1000 + callOutNumber * 0x10 + callOutSeverity);
|
|
|
|
// TGctrl [31-30] + TGnumber [29-6] + Reserved [5-0]
|
|
UInt32 talkGroup = (uint)tgCtrl * 0x40000000 + tgNumber * 0x40 + 0x00;
|
|
|
|
|
|
byte[] result = SDTS_CallOut(prefixWithSize, ref cm_msg_id, sourceISSI, destISSI, callOut, talkGroup, data);
|
|
|
|
bool resp = Write(result, result.Length);
|
|
|
|
return result;
|
|
}
|
|
|
|
public byte[] SDTS_CallOut(bool prefixWithSize, ref byte cm_msg_id, UInt32 sourceISSI, UInt32 destISSI, UInt16 callOut, UInt32 talkGroup, string data)
|
|
{
|
|
int buflen = 0;
|
|
if (data != null) buflen = data.Length;
|
|
|
|
byte[] cmBytes = SDR_CM_COM_CallOut(ref cm_msg_id, sourceISSI, destISSI);
|
|
|
|
byte[] tlBytes = SDTS_TLX_CallOut(callOut, talkGroup);
|
|
|
|
LIPSDR.CallOutFunction callOutFunction = (LIPSDR.CallOutFunction)((callOut >> 12) & 0x0000f);
|
|
if (callOutFunction == LIPSDR.CallOutFunction.Test ||
|
|
callOutFunction == LIPSDR.CallOutFunction.Info ||
|
|
callOutFunction == LIPSDR.CallOutFunction.Clear)
|
|
Array.Resize(ref tlBytes, tlBytes.Length - 7);
|
|
else if (callOutFunction == LIPSDR.CallOutFunction.Availability ||
|
|
callOutFunction == LIPSDR.CallOutFunction.AvailabilityRequest)
|
|
Array.Resize(ref tlBytes, tlBytes.Length - 8);
|
|
|
|
|
|
// compute the TL length in bits
|
|
// the TL fields are taken into consideration (count starting with 'TL encoding scheme' and transform in bits (*8) ) ==> 9 fields
|
|
if (tlBytes != null)
|
|
{
|
|
int tlLength = tlBytes.Length - 2;
|
|
|
|
tlBytes[3] = (byte)((((buflen + tlLength) * 8) & 0xff00) >> 8);
|
|
tlBytes[4] = (byte)(((buflen + tlLength) * 8) & 0x00ff);
|
|
}
|
|
|
|
// compute the CM length in bytes
|
|
byte[] cmSize = new byte[2];
|
|
if (cmBytes != null)
|
|
{
|
|
int cmLength = cmBytes.Length + tlBytes.Length;
|
|
|
|
cmSize[0] = (byte)(((buflen + cmLength) & 0xff00) >> 8);
|
|
cmSize[1] = (byte)((buflen + cmLength) & 0x00ff);
|
|
}
|
|
|
|
byte[] cmResult = cmBytes;
|
|
if (prefixWithSize)
|
|
cmResult = Combine(cmSize, cmBytes);
|
|
|
|
if (buflen > 0)
|
|
return Combine(cmResult, tlBytes, Encoding.UTF8.GetBytes(data));
|
|
|
|
return Combine(cmResult, tlBytes);
|
|
}
|
|
|
|
|
|
|
|
|
|
public byte[] SDR_CM_COM_CallOut(ref byte cm_msg_id, UInt32 sourceISSI, UInt32 destISSI)
|
|
{
|
|
if (cm_msg_id > 0xfe) cm_msg_id = 0;
|
|
cm_msg_id += 1;
|
|
|
|
byte[] msg = { 0x17, //1 PDU Type
|
|
0x01, //2 Protocol version
|
|
0x00, //3 header length
|
|
0x34, //4 header length ( 52 bytes )
|
|
0x40, //5 Next PDU Type ( SDTS_CM_TLX)
|
|
0x00,0x00,0x00,0x00,0x00, //6-10 Reserved
|
|
0x01, //11 Calling party type identifier
|
|
(byte)(((UInt32)sourceISSI & 0xff0000)>>16), //12 source ISSI
|
|
(byte)(((UInt32)sourceISSI & 0x00ff00)>>8), //13 source ISSI
|
|
(byte)(((UInt32)sourceISSI & 0x0000ff)), //14 source ISSI
|
|
0x00,0x00,0x00, //15-17 Calling party extension
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //18-26 Reserved
|
|
0x01, //27 Calling party type identifier
|
|
(byte)(((UInt32)destISSI & 0x00ff0000)>>16), //28 destination ISSI
|
|
(byte)(((UInt32)destISSI & 0x0000ff00)>>8), //29 destination ISSI
|
|
(byte)(((UInt32)destISSI & 0x000000ff)), //30 destination ISSI
|
|
0x00,0x00,0x00, //31-33 Calling party extension
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //34-42 Reserved
|
|
0xC3, //43 CM_PROTOCOL (CallOut),
|
|
0x60, //44 flags (SDS type=011 (7-5) | SS (4)| RV (3) | Reserved ( 2-1 )| CSV ( 0 )
|
|
cm_msg_id, //45 message reference
|
|
0x00, //46 Reserved
|
|
0x00, //47 Reserved (7-3)| GS (2)| PDCH (1) | MCCH (0)
|
|
0x00, //48 Reserved (7-1)| RR (0)
|
|
0x00,0x00, //49-50 Region selection
|
|
0x00,0x00 //51-52 Reserved
|
|
};
|
|
return msg;
|
|
}
|
|
|
|
public byte[] SDTS_TLX_CallOut(UInt16 callOut, UInt32 talkGroup)
|
|
{
|
|
byte[] callOutBytes = BitConverter.GetBytes(callOut);
|
|
byte[] talkGroupBytes = BitConverter.GetBytes(talkGroup);
|
|
|
|
byte[] msg = { 0x00, //01 Header length
|
|
0x11, //02 Header length
|
|
0xFF, //03 Next extension PDU type
|
|
0x00, //04 TL user data length
|
|
0x00, //05 TL user data length
|
|
0x04, //06 PDU type
|
|
0x00, //07 REC | CON | STO | TL forward adress type
|
|
0x00, //08 Validity period
|
|
0x00,0x00,0x00, //09-11 Forward address
|
|
0x00,0x00,0x00,0x00,0x00, //12-17 Reserved
|
|
(byte)LIPSDR.TextEncoding.ISO8859Latin1, //18 TL encoding scheme
|
|
callOutBytes[1], //19 TL call out number + call out severity
|
|
callOutBytes[0], //20 TL call out number + call out severity
|
|
talkGroupBytes[3], //21 TL TG ( ctrl + number )
|
|
talkGroupBytes[2], //22 TL TG ( ctrl + number )
|
|
talkGroupBytes[1], //23 TL TG ( ctrl + number )
|
|
talkGroupBytes[0], //24 TL TG ( ctrl + number )
|
|
0x00, //25 forward address
|
|
0x00, //26 forward address
|
|
0x00 //27 forward address
|
|
};
|
|
|
|
return msg;
|
|
|
|
}
|
|
|
|
|
|
|
|
private byte[] Combine(byte[] a, byte[] b)
|
|
{
|
|
byte[] result = new byte[a.Length + b.Length];
|
|
Buffer.BlockCopy(a, 0, result, 0, a.Length);
|
|
Buffer.BlockCopy(b, 0, result, a.Length, b.Length);
|
|
return result;
|
|
}
|
|
|
|
|
|
private byte[] Combine(byte[] a, byte[] b, byte[] c)
|
|
{
|
|
byte[] result = new byte[a.Length + b.Length + c.Length];
|
|
Buffer.BlockCopy(a, 0, result, 0, a.Length);
|
|
Buffer.BlockCopy(b, 0, result, a.Length, b.Length);
|
|
Buffer.BlockCopy(c, 0, result, a.Length + b.Length, c.Length);
|
|
return result;
|
|
}*/
|
|
#endregion
|
|
}
|
|
}
|