123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293 |
- using System;
- using System.Collections.Generic;
- using System.Globalization;
- using InABox.Core;
- namespace Comal.Classes
- {
- public enum SigfoxType
- {
- Location = 0,
- DeviceStats = 1,
- DownloadAcknowledgement = 2
- }
- public abstract class SigfoxBase
- {
- public SigfoxBase(byte[] buffer)
- {
- if (buffer == null)
- throw new Exception("Invalid Payload");
- var recordType = buffer[0] & 0x0f;
- if (recordType != (int)ValidType())
- throw new Exception(string.Format("Invalid Record Type: {0}", recordType));
- Parse(buffer);
- }
- private SigfoxBase()
- {
- }
- public static byte[] hex2Bytes(string val)
- {
- if (string.IsNullOrWhiteSpace(val)) return null; //return new byte[] { };
- val = val.Trim();
- if (val.StartsWith("0x")) val = val.Substring(2); //get rid of starting '0x'
- var numBytes = val.Length / 2;
- //byte[] bytes = new byte[] { };
- var byteList = new List<byte>();
- for (var i = 0; i < numBytes; i++)
- {
- var sSub = val.Substring(i * 2, 2);
- var bSub = byte.Parse(sSub, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
- byteList.Add(bSub); //, 16));
- }
- return byteList.ToArray();
- }
- protected int ParseLittleEndianInt32(byte[] buffer, int offset)
- {
- return (buffer[offset + 3] << 24) +
- (buffer[offset + 2] << 16) +
- (buffer[offset + 1] << 8) +
- buffer[offset];
- }
- protected int ParseLittleEndianInt16(byte[] buffer, int offset)
- {
- var arg1 = buffer[offset + 1] << 8;
- var arg2 = buffer[offset];
- return arg1 + arg2;
- }
- protected int ParseLittleEndianInt16Bits(byte[] buffer, int offset, int bitOffset, int bitLength)
- {
- var temp = ParseLittleEndianInt16(buffer, offset);
- temp = temp >> bitOffset;
- var mask = 0xffff >> (16 - bitLength);
- return temp & mask;
- }
- protected abstract SigfoxType ValidType();
- protected abstract void Parse(byte[] buffer);
- }
- public class SigfoxLocation : SigfoxBase
- {
- public SigfoxLocation(byte[] buffer) : base(buffer)
- {
- }
- public double Latitude { get; private set; }
- public double Longitude { get; private set; }
- public bool InTrip { get; private set; }
- public bool LastFixFailed { get; private set; }
- public int Heading { get; private set; }
- public int Speed { get; private set; }
- public double BatteryLevel { get; private set; }
- protected override SigfoxType ValidType()
- {
- return SigfoxType.Location;
- }
- protected override void Parse(byte[] buffer)
- {
- var flags = buffer[0] & 0xF0;
- InTrip = (flags & 0x10) > 0;
- LastFixFailed = (flags & 0x20) > 0;
- Latitude = ParseLittleEndianInt32(buffer, 1) * 1e-7;
- Longitude = ParseLittleEndianInt32(buffer, 5) * 1e-7;
- Heading = buffer[9] * 2;
- Speed = buffer[10];
- BatteryLevel = buffer[11] * 25 / 1000.0f;
- }
- }
- public class SigfoxDeviceStatistics : SigfoxBase
- {
- public SigfoxDeviceStatistics(byte[] buffer) : base(buffer)
- {
- }
- public int UptimeWeeks { get; private set; }
- public int TxCountRaw { get; private set; }
- public byte RxCountRaw { get; private set; }
- public int TripCountRaw { get; private set; }
- public int GpsSuccessRaw { get; private set; }
- public int GpsFailuresRaw { get; private set; }
- public int AverageFixTime { get; private set; }
- public int AverageFailTime { get; private set; }
- public int AverageFreshenTime { get; private set; }
- public int WakeupsPerTrip { get; private set; }
- protected override void Parse(byte[] buffer)
- {
- if (buffer == null)
- return;
- var recordType = buffer[0] & 0x0f;
- if (recordType == 2)
- {
- UptimeWeeks = ParseLittleEndianInt16Bits(buffer, 0, 4, 9 /*bits*/);
- TxCountRaw = ParseLittleEndianInt16Bits(buffer, 1, 5, 11 /*bits*/);
- RxCountRaw = buffer[3];
- TripCountRaw = ParseLittleEndianInt16Bits(buffer, 4, 0, 13 /*bits*/);
- GpsSuccessRaw = ParseLittleEndianInt16Bits(buffer, 5, 5, 10 /*bits*/);
- GpsFailuresRaw = ParseLittleEndianInt16Bits(buffer, 6, 7, 8 /*bits*/);
- AverageFixTime = ParseLittleEndianInt16Bits(buffer, 7, 7, 9 /*bits*/);
- AverageFailTime = ParseLittleEndianInt16Bits(buffer, 9, 0, 9 /*bits*/);
- AverageFreshenTime = ParseLittleEndianInt16Bits(buffer, 10, 1, 8 /*bits*/);
- WakeupsPerTrip = buffer[11] >> 1;
- }
- }
- protected override SigfoxType ValidType()
- {
- return SigfoxType.DeviceStats;
- }
- }
- public class SigfoxDownlinkAcknowledgement : SigfoxBase
- {
- public SigfoxDownlinkAcknowledgement(byte[] buffer) : base(buffer)
- {
- }
- public bool DownlinkAccepted { get; private set; }
- public byte FirmwareMajor { get; private set; }
- public byte FirmwareMinor { get; private set; }
- public int[] DownlinkData { get; private set; }
- protected override SigfoxType ValidType()
- {
- return SigfoxType.DownloadAcknowledgement;
- }
- protected override void Parse(byte[] buffer)
- {
- var flags = buffer[0] & 0xF0;
- DownlinkAccepted = (flags & 0x10) > 0;
- FirmwareMajor = buffer[2];
- FirmwareMinor = buffer[3];
- var data = new List<int>();
- for (var i = 0; i < 8; i++) data.Add(i + 4);
- DownlinkData = data.ToArray();
- }
- }
- public static class SigfoxFactory
- {
- public static SigfoxBase Parse(string data)
- {
- var bytes = SigfoxBase.hex2Bytes(data);
- var type = bytes[0] & 0x0f;
- if (type == (int)SigfoxType.Location)
- return new SigfoxLocation(bytes);
- if (type == (int)SigfoxType.DeviceStats)
- return new SigfoxDeviceStatistics(bytes);
- if (type == (int)SigfoxType.DownloadAcknowledgement)
- return new SigfoxDownlinkAcknowledgement(bytes);
- throw new Exception(string.Format("Invalid Record Type: {0}", type));
- }
- }
- [Caption("Locations")]
- [UserTracking(typeof(GPSTracker))]
- public class GPSTrackerLocation : Entity, IPersistent, IRemotable, ILicense<GPSTrackerLicense>, IOneToMany<GPSTracker>
- {
- [EditorSequence(1)]
- [DateTimeEditor(Visible = Visible.Default, Editable = Editable.Disabled)]
- public override DateTime Created
- {
- get => base.Created;
- set => base.Created = value;
- }
- [EditorSequence(2)]
- public GPSTrackerLink Tracker { get; set; }
- [EditorSequence(3)]
- public Location Location { get; set; }
- [Obsolete("Replaced with Location.Address")]
- [TextBoxEditor]
- [EditorSequence(4)]
- public string Address { get; set; }
- [DoubleEditor]
- [EditorSequence(5)]
- public double BatteryLevel { get; set; }
- [DoubleEditor]
- [EditorSequence(6)]
- public double Hours { get; set; }
- [DoubleEditor]
- [EditorSequence(7)]
- public double Distance { get; set; }
- [DoubleEditor]
- [EditorSequence(8)]
- public double Counter1 { get; set; }
- [DoubleEditor]
- [EditorSequence(9)]
- public double Counter2 { get; set; }
- [DoubleEditor]
- [EditorSequence(10)]
- public double Counter3 { get; set; }
- [DoubleEditor]
- [EditorSequence(11)]
- public double Counter4 { get; set; }
- [DoubleEditor]
- [EditorSequence(12)]
- public double Counter5 { get; set; }
- [NullEditor]
- public string DeviceID { get; set; }
- [NullEditor]
- public string MessageID { get; set; }
- [NullEditor]
- public string Payload { get; set; }
- [NullEditor]
- public long TimeStamp { get; set; }
- [NullEditor]
- public bool InTrip { get; set; }
- [NullEditor]
- public bool LastFixFailed { get; set; }
- [NullEditor]
- public int Heading { get; set; }
- [NullEditor]
- public int Speed { get; set; }
- public override string ToString()
- {
- if (!string.IsNullOrWhiteSpace(Payload))
- return string.Format("ID {0} TimeStamp {1} Payload {2}", DeviceID, TimeStamp, Payload);
- return string.Format(
- "ID {0} Lat: {1:F4} Lng: {2:F4} Batt: {3:F2} Hrs: {4:F2} Dist: {5:F2} C1: {6:F2} C2: {7:F2} C3: {8:F2} C4: {9:F2} C5: {10:F2}",
- DeviceID, Location.Latitude, Location.Longitude, BatteryLevel, Hours, Distance, Counter1, Counter2, Counter3, Counter4, Counter5);
- }
- }
- }
|