Skip to content
Snippets Groups Projects
Tracker.cs 6.03 KiB
Newer Older
philip.schell's avatar
philip.schell committed
using System;
using System.Text.RegularExpressions;
using Fraunhofer.Fit.Iot.Lora.Events;

philip.schell's avatar
philip.schell committed
namespace Fraunhofer.Fit.Iot.Lora.Trackers {
  public class Tracker {
    public delegate void UpdateDataEvent(Object sender, DataUpdateEvent e);
    public delegate void UpdateStatusEvent(Object sender, StatusUpdateEvent e);
    public event UpdateDataEvent DataUpdate;
    public event UpdateStatusEvent StatusUpdate;
philip.schell's avatar
philip.schell committed

philip.schell's avatar
philip.schell committed
    public Double BatteryLevel { get; private set; }
    public Int32 FrequencyOffset { get; private set; }
    public GpsInfo Gps { get; private set; }
    public String IpAddress { get; private set; }
    public String Name { get; private set; }
philip.schell's avatar
philip.schell committed
    public Byte PacketRssi { get; private set; }
philip.schell's avatar
philip.schell committed
    public DateTime Receivedtime { get; private set; }
philip.schell's avatar
philip.schell committed
    public Byte Rssi { get; private set; }
    public Double Snr { get; private set; }
philip.schell's avatar
philip.schell committed
    public Int32 Version { get; private set; }
    public Boolean WifiActive { get; private set; }
    public String WifiSsid { get; private set; }
philip.schell's avatar
philip.schell committed

philip.schell's avatar
philip.schell committed
    public Tracker() { }
philip.schell's avatar
philip.schell committed

philip.schell's avatar
philip.schell committed
    #region Private Parsers and Helpers
philip.schell's avatar
philip.schell committed
    private void Parse(Byte[] data) {
      if (data.Length == 28) {
        this.Name = GetName(data);
        Single lat = BitConverter.ToSingle(this.From5to4(data, 9), 0);
        Single lon = BitConverter.ToSingle(this.From5to4(data, 14), 0);
        Byte hour = data[19];
        Byte minute = data[20];
        Byte second = data[21];
        Single hdop = BitConverter.ToSingle(this.From5to4(data, 22), 0);
        this.BatteryLevel = data[27];
        Boolean fix = (lat != 0 && lon != 0);
        this.Gps = new GpsInfo(lat, lon, hour, minute, second, hdop, fix);
philip.schell's avatar
philip.schell committed
        this.DataUpdate?.Invoke(this, new DataUpdateEvent(this));
philip.schell's avatar
philip.schell committed
      }
    }

philip.schell's avatar
philip.schell committed
    private void Parse(String text) {
      String[] texts = text.Split(new String[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries);
      this.Name = GetName(text, 0);
      String[] infos = texts[1].Split(',');
      if (infos.Length >= 6 && Double.TryParse(infos[5], out Double batteryLevel)) {
        this.BatteryLevel = batteryLevel;
      }
      this.Gps = new GpsInfo(texts[1]);
      this.DataUpdate?.Invoke(this, new DataUpdateEvent(this));
    }

    private void ParseStatus(String text) {
      String[] texts = text.Split(new String[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries);
      if(texts.Length != 3) {
        return;
      }
      this.Name = GetName(text, 1);
      String[] infos = texts[2].Split(',');
      if(infos.Length != 6) {
        return;
      }
      if (Int32.TryParse(infos[0], out Int32 version)) {
        this.Version = version;
      }
      this.IpAddress = infos[1];
      this.WifiSsid = infos[2];
      this.WifiActive = infos[3] == "t";
      if (Double.TryParse(infos[4], out Double batteryLevel)) {
        this.BatteryLevel = batteryLevel;
      }
      if (Int32.TryParse(infos[5], out Int32 freqOffset)) {
        this.FrequencyOffset = freqOffset;
      }
      this.StatusUpdate?.Invoke(this, new StatusUpdateEvent(this));
    }

philip.schell's avatar
philip.schell committed
    private Byte[] From5to4(Byte[] data, Int32 start) {
philip.schell's avatar
philip.schell committed
      if (data.Length < start + 6) {
philip.schell's avatar
philip.schell committed
        return new Byte[] { 0, 0, 0, 0 };
      }
      UInt64 t = 0;
      t = data[start + 4];
      t += ((UInt64)data[start + 3] << 7);
      t += ((UInt64)data[start + 2] << 14);
      t += ((UInt64)data[start + 1] << 21);
      t += ((UInt64)data[start + 0] << 28);
      return BitConverter.GetBytes(t);
    }

    private void SetUpdate(LoraClientEvent e) {
      this.PacketRssi = e.Packetrssi;
      this.Rssi = e.Rssi;
      this.Snr = e.Snr;
      this.Receivedtime = e.UpdateTime;
    }
philip.schell's avatar
philip.schell committed
    #endregion
philip.schell's avatar
philip.schell committed

philip.schell's avatar
philip.schell committed
    #region External update Methods
philip.schell's avatar
philip.schell committed
    public void SetUpdate(LoraClientEvent e, String data) {
      this.SetUpdate(e);
      this.Parse(data);
    }

    public void SetUpdate(LoraClientEvent e, Byte[] data) {
      this.SetUpdate(e);
      this.Parse(data);
    }

philip.schell's avatar
philip.schell committed
    public void SetStatus(LoraClientEvent e, String textStatus) {
      this.SetUpdate(e);
      this.ParseStatus(textStatus);
    }
    #endregion

    #region Static Functions
    public static Boolean CheckPacket(String message) {
philip.schell's avatar
philip.schell committed
      String[] m;
      if (message.Contains("\r\n")) {
        m = message.Split(new String[] { "\r\n" }, StringSplitOptions.None);
      } else if (message.Contains("\n")) {
        m = message.Split(new String[] { "\n" }, StringSplitOptions.None);
      } else {
        return false;
      }
philip.schell's avatar
philip.schell committed
      if (m.Length == 2) { //Normal Data Packet
        if (m[0] == "") { //Name should not be empty
philip.schell's avatar
philip.schell committed
          return false;
        }
philip.schell's avatar
philip.schell committed
        if (!Regex.Match(m[1], "[0-9]+.[0-9]{5,10},[0-9]+.[0-9]{5,10},[0-9]{6},[0-9]+.[0-9]{2},[0-9]+.[0-9],[0-9].[0-9]{2}").Success) { //lon,lat,hhmmss,hdop,height,bat not match
philip.schell's avatar
philip.schell committed
          return false;
        }
        return true;
      }
philip.schell's avatar
philip.schell committed
      if (m.Length == 3) { //Debug Packet
        if (m[0] != "deb") { //first must be "deb"
          return false;
        }
        if (m[1] == "") { //Name should not be empty
philip.schell's avatar
philip.schell committed
          return false;
        }
philip.schell's avatar
philip.schell committed
        //version,ip,ssid,wififlag,battery,offset
        if (!Regex.Match(m[2], "^[0-9]+,[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3},[^,]+,[tf],[0-9].[0-9]{2},(-[0-9]+|[0-9]+)").Success) {
philip.schell's avatar
philip.schell committed
          return false;
        }
        return true;
      }
      return false;
    }

philip.schell's avatar
philip.schell committed
    public static String GetName(String message, Int32 index) {
      if (message.Contains("\r\n")) {
        return message.Split(new String[] { "\r\n" }, StringSplitOptions.None)[index].Trim();
      } else if (message.Contains("\n")) {
        return message.Split(new String[] { "\n" }, StringSplitOptions.None)[index].Trim();
      } else {
        return "";
      }
philip.schell's avatar
philip.schell committed
    }

    public static String GetName(Byte[] data) {
      if(data.Length >= 9) {
        Byte[] ret = new Byte[8];
        for (Int32 i = 0; i < 8; i++) {
          ret[i] = data[i + 1];
        }
        return System.Text.Encoding.ASCII.GetString(ret).Trim();
      }
      return "";
    }
philip.schell's avatar
philip.schell committed
    #endregion
philip.schell's avatar
philip.schell committed
  }
}