/// <summary>
        /// Remove zero bits stuffed in for transparency of the protocol
        /// </summary>
        /// <param name="data">Bool stands for already decoded bits, not just transitions</param>
        /// <returns>Array of bits</returns>
        public static SortedList <int, bool> DestuffZeroes(SortedList <int, bool> data)
        {
            int ones = 0;

            data = new SortedList <int, bool>(data);
            for (int i = 0; i < data.Count; i++)
            {
                if (data.Values[i])
                {
                    ones++;
                }
                else
                {
                    ones = 0;
                }
                try
                {
                    if ((ones == 5) && !data.Values[i + 1])
                    {
                        data.RemoveAt(i + 1);
                        ones = 0;
                    }
                }
                catch (ArgumentOutOfRangeException)
                {
                    ErrorListener.Add(new ArgumentException("Warning: incomplete bit sequence detected!"));
                    break;
                }
            }
            return(data);
        }
Exemplo n.º 2
0
        public virtual string GetReport(params byte[] bytes)
        {
            //Get only the bytes that belong to the field
            bytes = bytes.Where((byte i, int j) => { return(Bytes.Contains(j + 2)); }).ToArray();
            if (LittleEndian)
            {
                bytes = bytes.Reverse().ToArray();
            }
            StringBuilder res = new StringBuilder(string.Format(@"----------------- Field: {0} ----------------
", Name));

            res.Append(string.Join(" ", bytes.Select(x => x.ToString("X2"))));
            res.Append(" = "); //Add binary representation
            res.AppendLine(string.Join(" ", bytes.Select(x => Convert.ToString(x, 2).PadLeft(8, '0'))));
            if (CustomParser != null)
            {
                try
                {
                    res.AppendLine(CustomParser(bytes));
                }
                catch (Exception e)
                {
                    ErrorListener.Add(new Exception(
                                          string.Format("Error in a custom parser for field {0}", Name), e));
                }
            }
            //res.AppendLine("------------------");
            return(res.ToString());
        }
        public static LogicAnalyzerData CreateFromKingst(string filePath, int columnIndex, int limit = int.MaxValue)
        {
            if (limit < int.MaxValue)
            {
                limit++;                       //Take header into account
            }
            string[] fileContents;
            SortedList <int, bool> result;
            int lineLimit = LoadDataHelper(filePath, limit, out fileContents, out result);

            for (int i = 1; i < lineLimit; i++)
            {
                string[] split = fileContents[i].Split(',');
                split[0] = split[0].Replace(".", ""); //Switch to fixed-point arithmetic
                split[1] = split[columnIndex].TrimStart();
                try
                {
                    int temp = int.Parse(split[0]);
                    if (UseTimeLimit)
                    {
                        if (temp > limit)
                        {
                            break;
                        }
                    }
                    result.Add(int.Parse(split[0]), int.Parse(split[1]) > 0);
                }
                catch (FormatException e)
                {
                    ErrorListener.Add(new Exception("Can't parse Kingst data line: " + fileContents[i], e));
                }
            }
            return(new LogicAnalyzerData(result));
        }
        public static LogicAnalyzerData CreateFromLogicSnifferSTM(string filePath, int limit = int.MaxValue)
        {
            string[] fileContents;
            SortedList <int, bool> result;
            int lineLimit = LoadDataHelper(filePath, limit, out fileContents, out result);

            for (int i = fileContents[0].Contains(':') ? 0 : 1; i < lineLimit; i++)
            {
                string[] split = fileContents[i].Split(':');
                try
                {
                    int temp = int.Parse(split[0]);
                    if (UseTimeLimit)
                    {
                        if (temp > limit)
                        {
                            break;
                        }
                    }
                    result.Add(int.Parse(split[0]), int.Parse(split[1]) > 0);
                }
                catch (FormatException e)
                {
                    ErrorListener.Add(new Exception("Can't parse LogicSnifferSTM data line: " + fileContents[i], e));
                }
            }
            return(new LogicAnalyzerData(result));
        }
        /// <summary>
        /// Sorts packet's bytes into easily accessible structures. Manipulates endianess.
        /// </summary>
        /// <param name="data">Expects bytes, composed of fully decoded bits (Decode, then SeparatePackets, then DestuffZeros, then PackIntoBytes).</param>
        /// <param name="time">x10nS</param>
        /// <param name="littleEndian">See Communications.Parse</param>
        /// <returns></returns>
        public static EncoderPacket Parse(byte[] data, int time, bool littleEndian = false)
        {
            //bool containsSub = data.Length > OrdinaryPacketLength;
            byte[][]    result  = new byte[FieldLength.Count][];
            int         dataLen = data.Length - FieldLength[Fields.FCS];
            List <byte> fcs     = new List <byte>(dataLen > -1 ? dataLen : 0);
            int         current = 0;

            try
            {
                for (int i = 0; i < FieldLength.Count; i++)
                {
                    if (OrdinaryPacketFieldsToExclude.Any(x => x == (Fields)i))
                    {
                        continue;
                    }
                    int l = FieldLength[(Fields)i];
                    if (l == -1)
                    {
                        l = data.Length - FieldLength.Sum(x => x.Value) - 1;          //-1 stands for "variable length"
                    }
                    result[i] = new byte[l];
                    //Multibyte fields may be little-endian at physical layer (in fact they should be, but it turns out they're not...)
                    //All in all, we'd better implement a switch
                    for (int j = 0; j < l; j++)
                    {
                        result[i][j] = data[current + (littleEndian ? (l - j - 1) : (j))];
                        if ((Fields)i != Fields.FCS)
                        {
                            fcs.Add(result[i][j]);
                        }
                    }
                    current += l;
                }
            }
            catch (OverflowException)
            {
                ErrorListener.Add(new Exception(string.Format("Packet at {0} is incomplete!", time)));
            }
            var toParse = result[(int)Fields.Unknown];
            //if (containsSub) toParse = toParse.Concat(result[(int)Fields.SubcommandData]).ToArray();
            var packet = new EncoderPacket(result, EncoderCommand.Parse(toParse), time);

            packet.ComputedFCS = HDLCManchesterDecoder.ComputeFCS(fcs.ToArray());
            try
            {
                packet.FCSError = !packet.ComputedFCS.SequenceEqual(packet.ParsedData[(int)Fields.FCS]);
            }
            catch (ArgumentNullException)
            {
                packet.FCSError = true;
            }
            packet.DatabaseReport = EncoderCommandDatabase.GetReport(packet);
            return(packet);
        }
 public static string GetReport(EncoderPacket packet)
 {
     try
     {
         /*if (packet.ParsedData[(int)MechatrolinkPacket.Fields.Address][0] == SyncFrameAddress) return SyncFrameReport;
          * var info = Database[packet.Command.ParsedFields[(int)MechatrolinkCommand.Fields.Code][0]];
          * return info.GetReport(packet.Command.ParsedFields[(int)MechatrolinkCommand.Fields.Data],
          *  packet.ParsedData[(int)MechatrolinkPacket.Fields.Control][0] == ResponseControlCode);*/
     }
     catch (KeyNotFoundException) { }
     catch (Exception e)
     {
         ErrorListener.Add(new Exception("Error during database search. Operation aborted.", e));
     }
     return("");
 }
        /// <summary>
        /// Packs arrays of bool-s into an array of bytes.
        /// Mechatrolink-II packet structure is based on bytes, therefore this is convenient.
        /// </summary>
        /// <param name="bits">Bool stand for already decoded bits, not just transitions</param>
        /// <returns></returns>
        public static SortedList <int, byte> PackIntoBytes(SortedList <int, bool> bits)
        {
            int len = bits.Count;

            if (len % 8 != 0)
            {
                ErrorListener.Add(new ArgumentException(string.Format(
                                                            "Warning: bit count at {0} is not a multiple 8. It will be truncated.", bits.Keys[0])));
                len -= len % 8;
            }
            int byteLen = len / 8;
            SortedList <int, byte> result = new SortedList <int, byte>(byteLen);

            for (int i = 0; i < byteLen; i++)
            {
                byte temp = new byte();
                for (int j = 0; j < 8; j++)
                {
                    temp |= (byte)((bits.Values[i * 8 + j] ? 1 : 0) << j);
                }
                result.Add(bits.Keys[i * 8], temp);
            }
            return(result);
        }
        /// <summary>
        /// Decodes Manchester-encoded data (edges).
        /// </summary>
        /// <param name="data">Array of edges</param>
        /// <param name="freq">Communication frequency (equal to speed, 4Mbps = 4MHz for Mechatrolink-I and 10MHz for M-II)</param>
        /// <param name="error">Allowed tolerance for edge position (fraction of a period, usually 0.25 = 25%)</param>
        /// <returns>Array of bits</returns>
        public static SortedList <int, bool> Decode(SortedList <int, bool> data, int freq, double error)
        {
            bool req = false; //For interpacket search and then preamble length matching, first look for request preamble (i.e. set req true after interpacket search!)

            data = new SortedList <int, bool>(data);
            int p  = (int)Math.Round(1E8 / freq);
            int ph = (int)Math.Round(p * (1 + error));
            int pl = (int)Math.Round(p * (1 - error));
            SortedList <int, int> pulses = new SortedList <int, int>(data.Count - 1);

            for (int i = 0; i < data.Count - 1; i++) //Transform edges into pulses
            {
                //Skip until first long pulse (interpacket)
                if (!req && ((data.Keys[i + 1] - data.Keys[i]) < MaxRequestResponseDelay))
                {
                    continue;
                }
                pulses.Add(data.Keys[i], data.Keys[i + 1] - data.Keys[i]);
                req = true;
            }
            //Look for the preambles: starts with low-to-high, ends with high-to-low (?)
            SortedList <int, int> preambles = new SortedList <int, int>(pulses.Count / 32); //Assuming the contents are at least as long as the preamble (16*2)
            int current = 0;                                                                //Suitable edges found during preamble search

            try
            {
                int state = 0;
                for (int i = 0; i < pulses.Count; i++)
                {
                    switch (state)
                    {
                    case 0:     //Look for request preamble
                        if (PreambleHelper(data, pulses, preambles, pl, ph, RequestPreambleLength, ref current, i))
                        {
                            state++;
                        }
                        break;

                    case 1:     //Look for request-response delay
                        if (pulses.Values[i] > MinRequestResponseDelay)
                        {
                            if (pulses.Values[i] < MaxRequestResponseDelay)
                            {
                                state++;
                            }
                            else
                            {
                                state = 0;
                            }
                        }
                        break;

                    case 2:     //Look for response preamble
                        if (PreambleHelper(data, pulses, preambles, pl, ph, ResponsePreambleLength, ref current, i))
                        {
                            state++;
                        }
                        break;

                    case 3:     //Look for response-request delay
                        if (pulses.Values[i] > MaxRequestResponseDelay)
                        {
                            state = 0;
                        }
                        break;

                    default:
                        ErrorListener.Add(new Exception("Illegal state value for preamble detection state machine."));
                        break;
                    }
                }
            }
            catch (ArgumentOutOfRangeException)
            {
                ErrorListener.Add(new ArgumentException(
                                      "Warning: the bitstream contains an incomplete packet. The latter will be discarded."));
            }
            //DataReporter.ReportProgress("Preambles parsed...");
            SortedList <int, bool> bits = new SortedList <int, bool>(data.Capacity);
            int lastPreamble            = preambles.Count - 1;

            //Btw, int current is now repurposed
            current = 0;
            for (int i = 0; i < lastPreamble; i++)
            {
                current = PartDecodeManchester(i, current, pl, ph, preambles, data, bits);
            }
            //To avoid processing overhead in previous cycle, process the last packet separately
            if (!IgnoreLastPreamble)
            {
                PartDecodeManchester(lastPreamble, current, pl, ph, preambles, data, bits);
            }
            bits.TrimExcess();
            return(bits);
        }