688 lines
33 KiB
C#
688 lines
33 KiB
C#
|
using System;
|
|||
|
using System.Net;
|
|||
|
using System.Net.Sockets;
|
|||
|
using SafeMobileLib;
|
|||
|
using System.Threading;
|
|||
|
|
|||
|
namespace MotoTrbo_GW
|
|||
|
{
|
|||
|
class TallysmanReceiveThread
|
|||
|
{
|
|||
|
private static UdpClient udpClient;
|
|||
|
private static UdpMulticast udpMulticast;
|
|||
|
private Int32 Port = 0;
|
|||
|
private String mIP;
|
|||
|
private Int32 mPort;
|
|||
|
private static GeneralLocationManager locManager;
|
|||
|
|
|||
|
public TallysmanReceiveThread(Int32 port, String multicastID, String multicastPort)
|
|||
|
{
|
|||
|
Port = port;
|
|||
|
mIP = multicastID;
|
|||
|
mPort = Int32.Parse(multicastPort);
|
|||
|
locManager = new GeneralLocationManager(mIP, mPort);
|
|||
|
}
|
|||
|
|
|||
|
public void handleConnection()
|
|||
|
{
|
|||
|
SafeMobileLib.Utils.WriteLine("TallysmanReceiveThread initialized on port " + Port, ConsoleColor.Yellow);
|
|||
|
|
|||
|
udpClient = null;
|
|||
|
try
|
|||
|
{
|
|||
|
udpClient = new UdpClient();
|
|||
|
udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
|
|||
|
udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, Port));
|
|||
|
}
|
|||
|
catch (Exception ex)
|
|||
|
{
|
|||
|
SafeMobileLib.Utils.WriteLine("TallysmanReceiveThread handleConnection exception: " + ex.ToString());
|
|||
|
}
|
|||
|
|
|||
|
try
|
|||
|
{
|
|||
|
udpMulticast = new UdpMulticast(mIP, mPort);
|
|||
|
//SafeMobileLib.Utils.WriteLine("TallysmanReceiveThread successfully registered to multicast group");
|
|||
|
}
|
|||
|
catch (Exception ex)
|
|||
|
{
|
|||
|
SafeMobileLib.Utils.WriteLine("TallysmanReceiveThread exception while joining the multicast group: " + ex.ToString());
|
|||
|
}
|
|||
|
|
|||
|
IPEndPoint remoteIpEndPoint = new IPEndPoint(IPAddress.Any, Port);
|
|||
|
|
|||
|
while (true)
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
// Blocks until a message returns on this socket from a remote host.
|
|||
|
Byte[] receivedBytes = udpClient.Receive(ref remoteIpEndPoint);
|
|||
|
|
|||
|
char[] separator = { '.' };
|
|||
|
string[] su = remoteIpEndPoint.Address.ToString().Split(separator);
|
|||
|
uint radioID = (Convert.ToUInt32(su[1])) * 256 * 256 + (Convert.ToUInt32(su[2])) * 256 + Convert.ToUInt32(su[3]);
|
|||
|
string suid = radioID.ToString();
|
|||
|
int seqNo = receivedBytes[0] * 256 + receivedBytes[1];
|
|||
|
String seqID = TallysmanConfirm.getFromConfirmationQueue(seqNo);
|
|||
|
|
|||
|
SafeMobileLib.Utils.WriteLine(DateTime.Now.ToString() + " TallysmanReceiveThread received data from radio " + radioID + ", with seq ID " + seqID);
|
|||
|
//Utils.printBytesArray(receivedBytes);
|
|||
|
// process the message
|
|||
|
Byte toreturn = ProcessPacket2(receivedBytes, receivedBytes.Length, radioID.ToString().Trim());
|
|||
|
//put information on message bus
|
|||
|
//string sequenceID = "";
|
|||
|
//Byte[] toSendMulticast = Utils.createMulticastMessage(233, suid, receivedBytes, out sequenceID);
|
|||
|
//udpMulticast.Send(toSendMulticast, toSendMulticast.Length);
|
|||
|
SafeMobileLib.Utils.WriteLine("TallysmanReceiveThread successfully sent data to message bus");
|
|||
|
|
|||
|
Thread.Sleep(100);
|
|||
|
}
|
|||
|
catch (Exception e)
|
|||
|
{
|
|||
|
SafeMobileLib.Utils.WriteLine("##### TallysmanReceiveThread Exception #########\n" + e.ToString());
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public static Byte ProcessPacket2(byte[] data, int len, String imei)
|
|||
|
{
|
|||
|
|
|||
|
#region variable declaration
|
|||
|
Byte numberofMessByte =0;
|
|||
|
String pLat = "0.0", pLong = "0.0";
|
|||
|
Int64 itime70 = 0;
|
|||
|
double iSpeed = 0;
|
|||
|
int altitude = 0;
|
|||
|
#region fields for safenet db
|
|||
|
int bearing = -1;
|
|||
|
int levelOfConfidence = -1;
|
|||
|
int accuracy_horizontal = -1;
|
|||
|
int accuracy_vertical = -1;
|
|||
|
int odometer = -1;
|
|||
|
int vio_status = -1;
|
|||
|
int vio_changed = -1;
|
|||
|
float rssi = -1;
|
|||
|
int vital_id = -1;
|
|||
|
int runtime, idletime = -1;
|
|||
|
int eventTime = -1;
|
|||
|
long eventField = -1;
|
|||
|
string firmware_version = string.Empty;
|
|||
|
double average_speed = 0;
|
|||
|
#endregion
|
|||
|
|
|||
|
#region correction length variables
|
|||
|
int start_parse = 0;
|
|||
|
int delta = 0;
|
|||
|
int sum = 0;
|
|||
|
#endregion
|
|||
|
|
|||
|
int[] v = new int[19];
|
|||
|
|
|||
|
int protocol, version, messageLength, messageType,
|
|||
|
TransactionId, UnackedCount, LocationReportLength,
|
|||
|
LogId, EventId, EventIndex;
|
|||
|
|
|||
|
Int32 step = 0;
|
|||
|
#endregion
|
|||
|
|
|||
|
//first 2 bytes are Protocol and Version 0xFA 0x08
|
|||
|
protocol = data[step++];
|
|||
|
version = data[step++];
|
|||
|
#region Message Length
|
|||
|
string sByteMessLength = string.Empty;
|
|||
|
do
|
|||
|
{
|
|||
|
for (int j = 6; j >= 0; j--)
|
|||
|
{
|
|||
|
sByteMessLength += ((int)GetBitsAsByte(data[step], j, 1)).ToString();
|
|||
|
}
|
|||
|
}
|
|||
|
while (GetBitsAsByte(data[step++], 7, 1) == 1);
|
|||
|
messageLength = (int)(Convert.ToInt32(sByteMessLength, 2));
|
|||
|
#endregion
|
|||
|
#region Message Type
|
|||
|
messageType = data[step++];
|
|||
|
#endregion
|
|||
|
#region Transaction ID
|
|||
|
string sBytetrid = string.Empty;
|
|||
|
do
|
|||
|
{
|
|||
|
for (int j = 6; j >= 0; j--)
|
|||
|
{
|
|||
|
sBytetrid += ((int)GetBitsAsByte(data[step], j, 1)).ToString();
|
|||
|
}
|
|||
|
}
|
|||
|
while (GetBitsAsByte(data[step++], 7, 1) == 1);
|
|||
|
TransactionId = (int)(Convert.ToInt32(sBytetrid, 2));
|
|||
|
#endregion
|
|||
|
#region NOTE: Tallysman Reporting Types
|
|||
|
// There are 3 types of reports: Autonomus report 0x03, Immediate response 0x02, Log retrieval report 0x05
|
|||
|
//Between Transaction ID and Location report length foreach report type there are the following fields:
|
|||
|
//A. Autonomus report 0x03 - Unacked cound
|
|||
|
//B. Immediate response 0x02 - none
|
|||
|
//C. Log retrieval report 0x05 - Retrieval Flags (1 byte), Returned count, Unreturned count, NextID all uintvar
|
|||
|
|
|||
|
|
|||
|
#region Autonomus report 0x03 - Unacked cound
|
|||
|
if (messageType == 3)
|
|||
|
{
|
|||
|
string sByteUnkCount = string.Empty;
|
|||
|
do
|
|||
|
{
|
|||
|
for (int j = 6; j >= 0; j--)
|
|||
|
{
|
|||
|
sByteUnkCount += ((int)GetBitsAsByte(data[step], j, 1)).ToString();
|
|||
|
}
|
|||
|
}
|
|||
|
while (GetBitsAsByte(data[step++], 7, 1) == 1);
|
|||
|
UnackedCount = (int)(Convert.ToInt32(sByteUnkCount, 2));
|
|||
|
}
|
|||
|
#endregion
|
|||
|
#region Immediate response 0x02 - none
|
|||
|
if (messageType == 2)
|
|||
|
{
|
|||
|
// do nothing
|
|||
|
}
|
|||
|
#endregion
|
|||
|
#region Log retrieval report 0x05 - Retrieval Flags (1 byte), Returned count, Unreturned count, NextID all uintvar
|
|||
|
if (messageType == 5)
|
|||
|
{
|
|||
|
//Retrieval Flags
|
|||
|
step++;
|
|||
|
//Returned count
|
|||
|
do {/*nothing*/} while (GetBitsAsByte(data[step++], 7, 1) == 1);
|
|||
|
//Unreturned count
|
|||
|
do {/*nothing*/} while (GetBitsAsByte(data[step++], 7, 1) == 1);
|
|||
|
//NextID
|
|||
|
do {/*nothing*/} while (GetBitsAsByte(data[step++], 7, 1) == 1);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
#endregion
|
|||
|
#region BUNDLE/NORMAL PARSER
|
|||
|
do
|
|||
|
{
|
|||
|
#region Reset Variables
|
|||
|
pLat = pLong = "0.0";
|
|||
|
itime70 = 0;
|
|||
|
iSpeed = 0;
|
|||
|
altitude = 0;
|
|||
|
//fields for safenet db
|
|||
|
bearing = -1;
|
|||
|
levelOfConfidence = -1;
|
|||
|
accuracy_horizontal = -1;
|
|||
|
accuracy_vertical = -1;
|
|||
|
odometer = -1;
|
|||
|
vio_status = -1;
|
|||
|
vio_changed = -1;
|
|||
|
rssi = -1;
|
|||
|
vital_id = -1;
|
|||
|
runtime = idletime = -1;
|
|||
|
eventTime = -1;
|
|||
|
eventField = -1;
|
|||
|
firmware_version = string.Empty;
|
|||
|
average_speed = 0;
|
|||
|
#endregion
|
|||
|
|
|||
|
#region Location Report Length
|
|||
|
string sByteLocRepLength = string.Empty;
|
|||
|
do
|
|||
|
{
|
|||
|
for (int j = 6; j >= 0; j--)
|
|||
|
{
|
|||
|
sByteLocRepLength += ((int)GetBitsAsByte(data[step], j, 1)).ToString();
|
|||
|
}
|
|||
|
}
|
|||
|
while (GetBitsAsByte(data[step++], 7, 1) == 1);
|
|||
|
LocationReportLength = (int)(Convert.ToInt32(sByteLocRepLength, 2));
|
|||
|
start_parse = step;
|
|||
|
#endregion
|
|||
|
|
|||
|
#region Log ID
|
|||
|
string sByteLogId = string.Empty;
|
|||
|
do
|
|||
|
{
|
|||
|
for (int j = 6; j >= 0; j--)
|
|||
|
{
|
|||
|
sByteLogId += ((int)GetBitsAsByte(data[step], j, 1)).ToString();
|
|||
|
}
|
|||
|
}
|
|||
|
while (GetBitsAsByte(data[step++], 7, 1) == 1);
|
|||
|
LogId = (int)(Convert.ToInt32(sByteLogId, 2));
|
|||
|
#endregion
|
|||
|
#region Event ID
|
|||
|
string sByteEventID = string.Empty;
|
|||
|
do
|
|||
|
{
|
|||
|
for (int j = 6; j >= 0; j--)
|
|||
|
{
|
|||
|
sByteEventID += ((int)GetBitsAsByte(data[step], j, 1)).ToString();
|
|||
|
}
|
|||
|
}
|
|||
|
while (GetBitsAsByte(data[step++], 7, 1) == 1);
|
|||
|
// The value of the Event ID is (Event Type ID + Event Index * 128) and is encoded as a uintvar
|
|||
|
EventId = (int)(Convert.ToInt32(sByteEventID, 2))% 128;
|
|||
|
EventIndex = (int)(Convert.ToInt32(sByteEventID, 2)) / 128;
|
|||
|
//Check if eventId is periodic event Distance = 12, VIO = 14, Periodic = 15
|
|||
|
int[] array = new int[] { 12, 14, 15 };
|
|||
|
EventIndex += (Array.Exists(array, element => element == EventId)) ? 1 : 0;
|
|||
|
#endregion
|
|||
|
#region Report Form parser
|
|||
|
int count = 0;
|
|||
|
v = new int[19];
|
|||
|
do
|
|||
|
{
|
|||
|
for (int i = 0; i < 7; i++)
|
|||
|
{
|
|||
|
v[count++] = (int)GetBitsAsByte(data[step], i, 1);
|
|||
|
if (count == 19) break;
|
|||
|
}
|
|||
|
}
|
|||
|
while (GetBitsAsByte(data[step++], 7, 1) == 1);
|
|||
|
#endregion
|
|||
|
#region Parse data based on report form's bits
|
|||
|
for ( int i = 0; i <= 18; i++)
|
|||
|
{
|
|||
|
if (v[i] == 1)
|
|||
|
{
|
|||
|
switch (i)
|
|||
|
{
|
|||
|
//Property: Type, Form Flag + Name, Fixed/Variable Length, Length(bytes)
|
|||
|
#region Type: Latitude and Longitude, F0 - latitude and longitude, Fixed Length 8 bytes total
|
|||
|
case (int)FS.F0:
|
|||
|
{
|
|||
|
//process LAT
|
|||
|
bool sign = false;
|
|||
|
string hexLatitude = string.Empty;
|
|||
|
if ((data[step] & 0x80) != 0)
|
|||
|
{
|
|||
|
hexLatitude = (data[step++] - 128).ToString("X2");
|
|||
|
sign = true;
|
|||
|
}
|
|||
|
else hexLatitude += data[step++].ToString("X2");
|
|||
|
|
|||
|
for (int j = 0; j < 3; j++)
|
|||
|
{
|
|||
|
hexLatitude += data[step++].ToString("X2");
|
|||
|
}
|
|||
|
long decAgainLatiude = int.Parse(hexLatitude, System.Globalization.NumberStyles.HexNumber);
|
|||
|
double dlat = decAgainLatiude * 90 / (double)Math.Pow(2, 31);
|
|||
|
if (sign) dlat *= -1;
|
|||
|
pLat = Convert.ToString(dlat);
|
|||
|
|
|||
|
//process LONG
|
|||
|
string hexLongitude = string.Empty;
|
|||
|
if ((data[step] & 0x80) != 0)
|
|||
|
{
|
|||
|
hexLongitude = "FFFFFFFF" + (data[step++]).ToString("X2");
|
|||
|
}
|
|||
|
else hexLongitude += data[step++].ToString("X2");
|
|||
|
|
|||
|
for (int j = 0; j < 3; j++)
|
|||
|
{
|
|||
|
hexLongitude += data[step++].ToString("X2");
|
|||
|
}
|
|||
|
long decAgainLongitude = Int64.Parse(hexLongitude, System.Globalization.NumberStyles.HexNumber);
|
|||
|
double dlong = decAgainLongitude * 360 / (double)Math.Pow(2, 32);
|
|||
|
pLong = Convert.ToString(dlong);
|
|||
|
}
|
|||
|
break;
|
|||
|
#endregion
|
|||
|
#region Type: Timestamp, F1 - gps fix time, Fixed Length 5 bytes
|
|||
|
case (int)FS.F1:
|
|||
|
{
|
|||
|
string hexGPS = string.Empty;
|
|||
|
for (int j = 0; j < 5; j++)
|
|||
|
{
|
|||
|
hexGPS += data[step++].ToString("X2");
|
|||
|
}
|
|||
|
decimal decAgainGPS = Int64.Parse(hexGPS, System.Globalization.NumberStyles.HexNumber);
|
|||
|
int year = (int)Decimal.Truncate(decAgainGPS / (decimal)Math.Pow(2, 26));
|
|||
|
decimal modYear = decAgainGPS % (decimal)Math.Pow(2, 26);
|
|||
|
int month = (int)Decimal.Truncate(modYear / (decimal)Math.Pow(2, 22));
|
|||
|
decimal modMonth = modYear % (decimal)Math.Pow(2, 22);
|
|||
|
int day = (int)Decimal.Truncate(modMonth / (decimal)Math.Pow(2, 17));
|
|||
|
decimal modDay = modMonth % (decimal)Math.Pow(2, 17);
|
|||
|
int hour = (int)Decimal.Truncate(modDay / (decimal)Math.Pow(2, 12));
|
|||
|
decimal modHour = modDay % (decimal)Math.Pow(2, 12);
|
|||
|
int minute = (int)Decimal.Truncate(modHour / (decimal)Math.Pow(2, 6));
|
|||
|
int second = (int)(modHour % (decimal)Math.Pow(2, 6));
|
|||
|
System.DateTime dateTime = new DateTime(year, month, day, hour, minute, second, DateTimeKind.Utc);
|
|||
|
|
|||
|
TimeSpan diff = new DateTime(year, month, day, hour, minute, second, DateTimeKind.Utc) -
|
|||
|
new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
|||
|
|
|||
|
DateTime d = new DateTime();
|
|||
|
if (d.IsDaylightSavingTime())
|
|||
|
{
|
|||
|
SafeMobileLib.Utils.WriteLine("Time: Is daylight");
|
|||
|
itime70 = Convert.ToInt32(diff.TotalSeconds) + 3600;
|
|||
|
}
|
|||
|
else
|
|||
|
itime70 = Convert.ToInt32(diff.TotalSeconds);
|
|||
|
}
|
|||
|
break;
|
|||
|
#endregion
|
|||
|
#region Type: Speed, F2 - horizontal speed, F8 - vertical speed, F14 - average speed, Variable Length 1->3 bytes
|
|||
|
case (int)FS.F2:
|
|||
|
case (int)FS.F8:
|
|||
|
case (int)FS.F14:
|
|||
|
{
|
|||
|
double speed = 0;
|
|||
|
string sByte = string.Empty;
|
|||
|
do
|
|||
|
{
|
|||
|
for (int j = 6; j >= 0; j--)
|
|||
|
{
|
|||
|
sByte += ((int)GetBitsAsByte(data[step], j, 1)).ToString();
|
|||
|
}
|
|||
|
}
|
|||
|
while (GetBitsAsByte(data[step++], 7, 1) == 1);
|
|||
|
if (i == (int)FS.F2)
|
|||
|
{
|
|||
|
//meteres per second
|
|||
|
speed = (double)(Convert.ToInt32(sByte, 2)) / 10;
|
|||
|
//transform to km per hour
|
|||
|
speed *= (double)3.6;
|
|||
|
speed = (int)Math.Round(speed);
|
|||
|
}
|
|||
|
switch (i)
|
|||
|
{
|
|||
|
case (int)FS.F2:
|
|||
|
iSpeed = speed;
|
|||
|
break;
|
|||
|
case (int)FS.F8:
|
|||
|
break;
|
|||
|
case (int)FS.F14:
|
|||
|
average_speed = speed;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
break;
|
|||
|
#endregion
|
|||
|
#region Type: Sintvar, F4 - altitude, Variable Length 1->3 bytes
|
|||
|
case (int)FS.F4:
|
|||
|
{
|
|||
|
string sByte = string.Empty;
|
|||
|
bool sign = false;
|
|||
|
do
|
|||
|
{
|
|||
|
for (int j = 6; j >= 0; j--)
|
|||
|
{
|
|||
|
if (GetBitsAsByte(data[step], 7, 1) == 1 && GetBitsAsByte(data[step], j, 1) == 1 && j == 6)
|
|||
|
sign = true;
|
|||
|
else
|
|||
|
sByte += ((int)GetBitsAsByte(data[step], j, 1)).ToString();
|
|||
|
}
|
|||
|
}
|
|||
|
while (GetBitsAsByte(data[step++], 7, 1) == 1);
|
|||
|
altitude = (int)(Convert.ToInt32(sByte, 2));
|
|||
|
if (sign) altitude *= -1;
|
|||
|
}
|
|||
|
break;
|
|||
|
#endregion
|
|||
|
#region Type: Uint8, F5 - confidence level, Fixed Length 1 byte
|
|||
|
case (int)FS.F5:
|
|||
|
levelOfConfidence = data[step++];
|
|||
|
break;
|
|||
|
#endregion
|
|||
|
#region Type: Uint16, F10 - odometer, F17 - RSSI radio signal strength in dBm
|
|||
|
case (int)FS.F10:
|
|||
|
// Odometer on 2 bytes - ignoring
|
|||
|
step += 2;
|
|||
|
break;
|
|||
|
case (int)FS.F17:
|
|||
|
// msb - most significant bit, lsb - least significant bit
|
|||
|
int msb = data[step++];
|
|||
|
int lsb = data[step++];
|
|||
|
rssi = (msb + (lsb * 1000 + 128) / 256000);
|
|||
|
break;
|
|||
|
#endregion
|
|||
|
#region Type: Uint16 F12 - VIO current / VIO changed 4 bytes 2 for current, 2 for changed
|
|||
|
case (int)FS.F12:
|
|||
|
//step += 4;
|
|||
|
{
|
|||
|
//2 bytes for current VIO
|
|||
|
//Hardware VIO 1 Sprite Protocol page 67/68
|
|||
|
int currentVIO = data[step++];
|
|||
|
vio_status = currentVIO;
|
|||
|
//Hardware VIO 2
|
|||
|
step++;
|
|||
|
//2 bytes for changed VIO
|
|||
|
vio_changed = data[step++];
|
|||
|
step++;
|
|||
|
//send telemetry to message bus only if event type <> 1
|
|||
|
|
|||
|
string test = "#233#" + imei.ToString() + "#" + Convert.ToInt16(currentVIO) + "#hyt#";
|
|||
|
locManager.SendOnMsgBuss("0.0", test);
|
|||
|
}
|
|||
|
break;
|
|||
|
#endregion
|
|||
|
#region Type: RTM + ITM
|
|||
|
// F11 - Run time/idle time
|
|||
|
case (int)FS.F11:
|
|||
|
{
|
|||
|
string sByte = string.Empty;
|
|||
|
#region runtime
|
|||
|
//Indicates the run time in minutes. The run time is the current value of a timer that
|
|||
|
//continuously increments whenever a specified input is detected (e.g. ignition-on). The
|
|||
|
//ignition line from the vehicle must be wired to the Sprite.
|
|||
|
do
|
|||
|
{
|
|||
|
for (int j = 6; j >= 0; j--)
|
|||
|
{
|
|||
|
sByte += ((int)GetBitsAsByte(data[step], j, 1)).ToString();
|
|||
|
}
|
|||
|
}
|
|||
|
while (GetBitsAsByte(data[step++], 7, 1) == 1);
|
|||
|
runtime = (int)(Convert.ToInt32(sByte, 2));
|
|||
|
#endregion
|
|||
|
#region idletime
|
|||
|
//Indicates the idle time in minutes. The idle time is the current value of a timer that
|
|||
|
//continuously increments whenever a specified input is detected (e.g. ignition-on) and
|
|||
|
//the unit is not moving (i.e. stopped). The ignition line from the vehicle must be wired to
|
|||
|
//the Sprite.
|
|||
|
sByte = string.Empty;
|
|||
|
do
|
|||
|
{
|
|||
|
for (int j = 6; j >= 0; j--)
|
|||
|
{
|
|||
|
sByte += ((int)GetBitsAsByte(data[step], j, 1)).ToString();
|
|||
|
}
|
|||
|
}
|
|||
|
while (GetBitsAsByte(data[step++], 7, 1) == 1);
|
|||
|
idletime = (int)(Convert.ToInt32(sByte, 2));
|
|||
|
#endregion
|
|||
|
}
|
|||
|
break;
|
|||
|
#endregion
|
|||
|
#region Type: Uintvar, F3, F6, F7, F9, F13, F18
|
|||
|
// F3 - bearing, F6 - horizontal accuracy, F7 - vertical accuracy, F9 - odometer,
|
|||
|
// F13 - event time, F18 - vital ID
|
|||
|
case (int)FS.F3:
|
|||
|
case (int)FS.F6:
|
|||
|
case (int)FS.F7:
|
|||
|
case (int)FS.F9:
|
|||
|
case (int)FS.F13:
|
|||
|
case (int)FS.F18:
|
|||
|
{
|
|||
|
string sByte = string.Empty;
|
|||
|
do
|
|||
|
{
|
|||
|
for (int j = 6; j >= 0; j--)
|
|||
|
{
|
|||
|
sByte += ((int)GetBitsAsByte(data[step], j, 1)).ToString();
|
|||
|
}
|
|||
|
}
|
|||
|
while (GetBitsAsByte(data[step++], 7, 1) == 1);
|
|||
|
switch (i)
|
|||
|
{
|
|||
|
case (int)FS.F3:
|
|||
|
bearing = (int)(Convert.ToInt32(sByte, 2));
|
|||
|
break;
|
|||
|
case (int)FS.F6:
|
|||
|
accuracy_horizontal = (int)(Convert.ToInt32(sByte, 2));
|
|||
|
break;
|
|||
|
case (int)FS.F7:
|
|||
|
accuracy_vertical = (int)(Convert.ToInt32(sByte, 2));
|
|||
|
break;
|
|||
|
case (int)FS.F9:
|
|||
|
odometer = (int)(Convert.ToInt32(sByte, 2));
|
|||
|
break;
|
|||
|
case (int)FS.F13:
|
|||
|
// The number of seconds that have passed since the GPS fix time for the report.
|
|||
|
// If the GPS fix is old, then the GPS fix time will not be the time that the report was generated.
|
|||
|
// This field, in combination with the GPS fix time field, allows the time of the event to be calculated.
|
|||
|
// The GPS fix time should always be requested if the Event time is requested.
|
|||
|
eventTime = (int)(Convert.ToInt32(sByte, 2));
|
|||
|
break;
|
|||
|
case (int)FS.F18:
|
|||
|
vital_id = (int)(Convert.ToInt32(sByte, 2));
|
|||
|
break;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
break;
|
|||
|
#endregion
|
|||
|
#region 4 bytes FS: F15 - event field
|
|||
|
//for (int j = 0; j < 4; j++)
|
|||
|
//{
|
|||
|
// eventField <<= 8;
|
|||
|
// eventField |= (Int64)data[step];
|
|||
|
// //Console.Write(" 0x" + data[step].ToString("X2"));
|
|||
|
// step++;
|
|||
|
//}
|
|||
|
#endregion
|
|||
|
#region 6 bytes FS: F16-firmware version, configuration version, configuration update count
|
|||
|
case (int)FS.F16:
|
|||
|
int major_version = data[step++];
|
|||
|
int minor_version = data[step++];
|
|||
|
int micro_version = data[step++];
|
|||
|
firmware_version = string.Format("{0}.{1}.{2}", major_version, minor_version, micro_version);
|
|||
|
step += 3;
|
|||
|
break;
|
|||
|
#endregion
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
#endregion
|
|||
|
//send location to message bus
|
|||
|
if (itime70 == 0 && EventId == (int)TallysmanEvents.ImmediateRequest) //immediate response
|
|||
|
itime70 = DateTime.UtcNow.GetSecondsFromDT();
|
|||
|
locManager.SendLoc2messagebusTallysman(imei, (UInt32)(itime70), iSpeed.ToString(), pLat, pLong, altitude.ToString(), LogId.ToString(), 0);
|
|||
|
#region generate fake ars message if event is IgnitionOff, RadioOff, IgnitionOn, RadioOn
|
|||
|
//2.4 ARS REPLACEMENT FOR TW200, TW250 ............................................... 10
|
|||
|
string sequenceID = "";
|
|||
|
if (EventId == (int)TallysmanEvents.IgnitionOff || EventId == (int)TallysmanEvents.RadioOff)
|
|||
|
{
|
|||
|
byte[] arsStatus = new byte[] { (byte)'O', (byte)'F', (byte)'F' };
|
|||
|
Byte[] toSendMulticast = Utils.createMulticastMessage(130, imei, arsStatus, out sequenceID);
|
|||
|
udpMulticast.Send(toSendMulticast, toSendMulticast.Length);
|
|||
|
}
|
|||
|
if (EventId == (int)TallysmanEvents.IgnitionOn || EventId == (int)TallysmanEvents.RadioOn)
|
|||
|
{
|
|||
|
byte[] arsStatus = new byte[] { (byte)'O', (byte)'N' };
|
|||
|
Byte[] toSendMulticast = Utils.createMulticastMessage(130, imei, arsStatus, out sequenceID);
|
|||
|
udpMulticast.Send(toSendMulticast, toSendMulticast.Length);
|
|||
|
}
|
|||
|
#endregion
|
|||
|
#region generate fake emergency
|
|||
|
if (EventId == (int)TallysmanEvents.Emergency)
|
|||
|
{
|
|||
|
SafeMobileLib.Utils.WriteLine("Received emergency from radio id: " + imei);
|
|||
|
string seqID = "0.0";
|
|||
|
string toSend = "#138#" + imei + "#";
|
|||
|
String cmdok = "#" + seqID + toSend;
|
|||
|
Int32 tmp = cmdok.Length + 1;
|
|||
|
tmp += tmp.ToString().Length;
|
|||
|
cmdok = "#" + tmp.ToString() + cmdok;
|
|||
|
System.Text.Encoding enc = System.Text.Encoding.ASCII;
|
|||
|
byte[] buf = enc.GetBytes(cmdok);
|
|||
|
//put on multicast bus
|
|||
|
SafeMobileLib.Utils.WriteLine("Emergency alarm sent on multicast bus: " + cmdok);
|
|||
|
udpMulticast.Send(buf, buf.Length);
|
|||
|
}
|
|||
|
#endregion
|
|||
|
sum = LocationReportLength + start_parse;
|
|||
|
delta = sum - step;
|
|||
|
step += delta;
|
|||
|
}
|
|||
|
while (len > step + 1);
|
|||
|
#endregion
|
|||
|
return numberofMessByte;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets a specific group of bits as a byte values. This process is created appling a
|
|||
|
/// custom mask and then shifting the remaining bits to right
|
|||
|
/// </summary>
|
|||
|
/// <param name="b">The byte from which the bits will be extracted</param>
|
|||
|
/// <param name="offset">The number of bits which will be skipped from right[LST]. O for no offset</param>
|
|||
|
/// <param name="count">Number of bits which are required</param>
|
|||
|
/// <returns>The byte value of the required bits. This values is generated shifting the bits towards LST</returns>
|
|||
|
public static byte GetBitsAsByte(byte b, int offset, int count)
|
|||
|
{
|
|||
|
return (byte)((b >> offset) & ((1 << count) - 1));
|
|||
|
}
|
|||
|
|
|||
|
public enum FS
|
|||
|
{
|
|||
|
F0 = 0, // LAT + LON "Latitude Longitude"
|
|||
|
F1, // FTM "Time Timestamp"
|
|||
|
F2, // HSP "Speed*"
|
|||
|
F3, // BEA "uintvar"
|
|||
|
F4, // ALT "sintvar"
|
|||
|
F5, // CNF "uint8"
|
|||
|
F6, // HAC "uintvar"
|
|||
|
F7, // VAC "uintvar"
|
|||
|
F8, // VSP "Speed*"
|
|||
|
F9, // ODU "uintvar"
|
|||
|
F10, // OD2 "unsigned 16 bit integer, scaled by 10"
|
|||
|
F11, // RTM + ITM "uintvar"
|
|||
|
F12, // VCU + VCH "Bitmask (2 bytes)"
|
|||
|
F13, // ETM "uintvar"
|
|||
|
F14, // ASP "Speed*"
|
|||
|
F15, // EVF "uint32 A four byte length unsigned integer."
|
|||
|
F16, // FWV + CFV + CFU 3 concatenated uintvars + uintvar + uintvar
|
|||
|
F17, // RSS "2 bytes"
|
|||
|
F18 // VID "uintvar"
|
|||
|
|
|||
|
// *Speed is represented in meters per second and is encoded with one decimal point precision
|
|||
|
// *by scaling the speed by 10 and encoding it as a uintvar.
|
|||
|
}
|
|||
|
|
|||
|
public enum TallysmanEvents
|
|||
|
{
|
|||
|
ImmediateRequest = 1,
|
|||
|
PTT = 2,
|
|||
|
Turn = 3,
|
|||
|
Speeding = 4,
|
|||
|
IgnitionOn = 5,
|
|||
|
IgnitionOff = 6,
|
|||
|
RadioOn = 7,
|
|||
|
RadioOff = 8,
|
|||
|
Stopped = 9,
|
|||
|
Moving = 10,
|
|||
|
GPSFix = 11,
|
|||
|
GPSNoFix = 12,
|
|||
|
Distance = 13,
|
|||
|
VIO = 14,
|
|||
|
Periodic = 15,
|
|||
|
CircleWaypoint = 16,
|
|||
|
Emergency = 17,
|
|||
|
ChannelChange = 18,
|
|||
|
Tracking = 19,
|
|||
|
SafeArea = 20,
|
|||
|
RSSICapture = 21,
|
|||
|
UserInput = 22,
|
|||
|
PolygonWaypointInEvent = 23,
|
|||
|
PolygonWaypointOutEvent = 24,
|
|||
|
CircleWaypointOutEvent = 25,
|
|||
|
BusStopEvent = 26
|
|||
|
}
|
|||
|
}
|
|||
|
}
|