Not able to Parsed the data properly

I have TCP Listener in C# and its read the and store the data properly in Codec8 but in codec8E its give error

  1. Error
    Error: Not enough data for 8B I/O element.
    ArgumentOutOfRangeException: Value to add was out of range.
    Parameter name: value
  2. Code
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using GPSParser.DBLogic;

namespace GPSParser.Teltonika
{
public class FMXXXX_Parser_8E : ParserBase
{
public FMXXXX_Parser_8E(bool showDiagnosticInfo)
{
_showDiagnosticInfo = showDiagnosticInfo;
}

    public override int DecodeAVL(List<byte> receiveBytes, string IMEI)
    {
        try
        {
            // Log the raw data received
            Console.WriteLine("Received Data: " + BitConverter.ToString(receiveBytes.ToArray()).Replace("-", ""));

            // Parse AVL Data Length
            if (receiveBytes.Count < 8)
            {
                Console.WriteLine("Error: Not enough data for AVL Data Length.");
                return 0;
            }

            string hexDataLength = string.Empty;
            receiveBytes.Skip(4).Take(4).ToList().ForEach(delegate (byte b) { hexDataLength += String.Format("{0:X2}", b); });
            int dataLength = Convert.ToInt32(hexDataLength, 16);
            Console.WriteLine("Data Length: " + dataLength);

            // Validate data length
            if (receiveBytes.Count < dataLength + 12) // 12 bytes: 8 header + 4 CRC
            {
                Console.WriteLine("Error: Received data length does not match expected length.");
                return 0;
            }

            // Parse Codec ID
            if (receiveBytes.Count < 9)
            {
                Console.WriteLine("Error: Not enough data for Codec ID.");
                return 0;
            }

            int codecId = Convert.ToInt32(receiveBytes.Skip(8).Take(1).ToList()[0]);
            Console.WriteLine("Codec ID: " + codecId);

            // Parse Number of Data
            if (receiveBytes.Count < 10)
            {
                Console.WriteLine("Error: Not enough data for Number of Data.");
                return 0;
            }

            int numberOfData = Convert.ToInt32(receiveBytes.Skip(9).Take(1).ToList()[0]);
            Console.WriteLine("Number of Data: " + numberOfData);

            int tokenAddress = 10;

            for (int n = 0; n < numberOfData; n++)
            {
                GPSdata gpsData = new GPSdata();

                // Parse Timestamp
                if (tokenAddress + 8 > receiveBytes.Count)
                {
                    Console.WriteLine("Error: Not enough data for timestamp.");
                    break;
                }

                string hexTimeStamp = string.Empty;
                receiveBytes.Skip(tokenAddress).Take(8).ToList().ForEach(delegate (byte b) { hexTimeStamp += String.Format("{0:X2}", b); });
                long timeSt = Convert.ToInt64(hexTimeStamp, 16);
                DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0);
                DateTime timestamp = origin.AddMilliseconds(Convert.ToDouble(timeSt));
                gpsData.Timestamp = timestamp;
                Console.WriteLine("Timestamp: " + timestamp);

                tokenAddress += 8;

                // Parse Priority
                if (tokenAddress + 1 > receiveBytes.Count)
                {
                    Console.WriteLine("Error: Not enough data for priority.");
                    break;
                }

                int priority = Convert.ToInt32(receiveBytes.Skip(tokenAddress).Take(1).ToList()[0]);
                gpsData.Priority = (byte)priority;
                Console.WriteLine("Priority: " + priority);

                tokenAddress += 1;

                // Parse Longitude
                if (tokenAddress + 4 > receiveBytes.Count)
                {
                    Console.WriteLine("Error: Not enough data for longitude.");
                    break;
                }

                string longt = string.Empty;
                receiveBytes.Skip(tokenAddress).Take(4).ToList().ForEach(delegate (byte b) { longt += String.Format("{0:X2}", b); });
                double longitude = ((double)Convert.ToInt32(longt, 16)) / 10000000;
                gpsData.Long = longitude;
                Console.WriteLine("Longitude: " + longitude);

                tokenAddress += 4;

                // Parse Latitude
                if (tokenAddress + 4 > receiveBytes.Count)
                {
                    Console.WriteLine("Error: Not enough data for latitude.");
                    break;
                }

                string lat = string.Empty;
                receiveBytes.Skip(tokenAddress).Take(4).ToList().ForEach(delegate (byte b) { lat += String.Format("{0:X2}", b); });
                double latitude = ((double)Convert.ToInt32(lat, 16)) / 10000000;
                gpsData.Lat = latitude;
                Console.WriteLine("Latitude: " + latitude);

                tokenAddress += 4;

                // Parse Altitude
                if (tokenAddress + 2 > receiveBytes.Count)
                {
                    Console.WriteLine("Error: Not enough data for altitude.");
                    break;
                }

                string alt = string.Empty;
                receiveBytes.Skip(tokenAddress).Take(2).ToList().ForEach(delegate (byte b) { alt += String.Format("{0:X2}", b); });
                int altitude = Convert.ToInt32(alt, 16);
                gpsData.Altitude = (short)altitude;
                Console.WriteLine("Altitude: " + altitude);

                tokenAddress += 2;

                // Parse Angle
                if (tokenAddress + 2 > receiveBytes.Count)
                {
                    Console.WriteLine("Error: Not enough data for angle.");
                    break;
                }

                string ang = string.Empty;
                receiveBytes.Skip(tokenAddress).Take(2).ToList().ForEach(delegate (byte b) { ang += String.Format("{0:X2}", b); });
                int angle = Convert.ToInt32(ang, 16);
                gpsData.Direction = (short)angle;
                Console.WriteLine("Angle: " + angle);

                tokenAddress += 2;

                // Parse Satellites
                if (tokenAddress + 1 > receiveBytes.Count)
                {
                    Console.WriteLine("Error: Not enough data for satellites.");
                    break;
                }

                int satellites = Convert.ToInt32(receiveBytes.Skip(tokenAddress).Take(1).ToList()[0]);
                gpsData.Satellite = (byte)satellites;
                Console.WriteLine("Satellites: " + satellites);

                tokenAddress += 1;

                // Parse Speed
                if (tokenAddress + 2 > receiveBytes.Count)
                {
                    Console.WriteLine("Error: Not enough data for speed.");
                    break;
                }

                string sp = string.Empty;
                receiveBytes.Skip(tokenAddress).Take(2).ToList().ForEach(delegate (byte b) { sp += String.Format("{0:X2}", b); });
                int speed = Convert.ToInt32(sp, 16);
                gpsData.Speed = (short)speed;
                Console.WriteLine("Speed: " + speed);

                tokenAddress += 2;

                // Parse Event IO Element ID
                if (tokenAddress + 1 > receiveBytes.Count)
                {
                    Console.WriteLine("Error: Not enough data for event IO element ID.");
                    break;
                }

                byte event_IO_element_ID = (byte)Convert.ToInt32(receiveBytes.Skip(tokenAddress).Take(1).ToList()[0]);
                gpsData.Event_IO_element_ID = event_IO_element_ID;
                Console.WriteLine("Event IO Element ID: " + event_IO_element_ID);

                tokenAddress += 1;

                // Parse IO Elements in Record
                if (tokenAddress + 1 > receiveBytes.Count)
                {
                    Console.WriteLine("Error: Not enough data for IO elements in record.");
                    break;
                }

                int IO_element_in_record = Convert.ToInt32(receiveBytes.Skip(tokenAddress).Take(1).ToList()[0]);
                Console.WriteLine("IO Element in Record: " + IO_element_in_record);

                tokenAddress += 1;

                int currentCursor = tokenAddress;

                // Handle 1B I/O elements
                if (currentCursor < receiveBytes.Count)
                {
                    int IO_Elements_1B_Quantity = Convert.ToInt32(receiveBytes.Skip(currentCursor).Take(1).ToList()[0]);
                    currentCursor++;
                    Console.WriteLine($"1B I/O Elements Quantity: {IO_Elements_1B_Quantity}");
                    for (int IO_1 = 0; IO_1 < IO_Elements_1B_Quantity; IO_1++)
                    {
                        if (currentCursor + 1 >= receiveBytes.Count)
                        {
                            Console.WriteLine("Error: Not enough data for 1B I/O element.");
                            break;
                        }

                        var parameterID = (byte)Convert.ToInt32(receiveBytes.Skip(currentCursor).Take(1).ToList()[0]);
                        var IO_Element_1B = (byte)Convert.ToInt32(receiveBytes.Skip(currentCursor + 1).ToList()[0]);
                        if (!gpsData.IO_Elements_1B.ContainsKey(parameterID))
                        {
                            gpsData.IO_Elements_1B.Add(parameterID, IO_Element_1B);
                        }

                        Console.WriteLine($"1B Element ID: {parameterID}, Value: {IO_Element_1B}");
                        currentCursor += 2;
                    }
                }

                // Handle 2B I/O elements
                if (currentCursor < receiveBytes.Count)
                {
                    int IO_Elements_2B_Quantity = Convert.ToInt32(receiveBytes.Skip(currentCursor).Take(1).ToList()[0]);
                    currentCursor++;
                    Console.WriteLine($"2B I/O Elements Quantity: {IO_Elements_2B_Quantity}");
                    for (int IO_2 = 0; IO_2 < IO_Elements_2B_Quantity; IO_2++)
                    {
                        if (currentCursor + 3 > receiveBytes.Count)
                        {
                            Console.WriteLine("Error: Not enough data for 2B I/O element.");
                            break;
                        }

                        var parameterID = (byte)Convert.ToInt32(receiveBytes.Skip(currentCursor).Take(1).ToList()[0]);
                        string value = string.Empty;
                        receiveBytes.Skip(currentCursor + 1).Take(2).ToList().ForEach(delegate (byte b) { value += String.Format("{0:X2}", b); });

                        var IO_Element_2B = Convert.ToInt16(value, 16);
                        if (!gpsData.IO_Elements_2B.ContainsKey(parameterID))
                        {
                            gpsData.IO_Elements_2B.Add(parameterID, IO_Element_2B);
                        }

                        Console.WriteLine($"2B Element ID: {parameterID}, Value: {IO_Element_2B}");
                        currentCursor += 3;
                    }
                }

                // Handle 4B I/O elements
                if (currentCursor < receiveBytes.Count)
                {
                    int IO_Elements_4B_Quantity = Convert.ToInt32(receiveBytes.Skip(currentCursor).Take(1).ToList()[0]);
                    currentCursor++;
                    Console.WriteLine($"4B I/O Elements Quantity: {IO_Elements_4B_Quantity}");
                    for (int IO_4 = 0; IO_4 < IO_Elements_4B_Quantity; IO_4++)
                    {
                        if (currentCursor + 5 > receiveBytes.Count)
                        {
                            Console.WriteLine("Error: Not enough data for 4B I/O element.");
                            break;
                        }

                        var parameterID = (byte)Convert.ToInt32(receiveBytes.Skip(currentCursor).Take(1).ToList()[0]);
                        string value = string.Empty;
                        receiveBytes.Skip(currentCursor + 1).Take(4).ToList().ForEach(delegate (byte b) { value += String.Format("{0:X2}", b); });

                        var IO_Element_4B = Convert.ToInt32(value, 16);
                        if (!gpsData.IO_Elements_4B.ContainsKey(parameterID))
                        {
                            gpsData.IO_Elements_4B.Add(parameterID, IO_Element_4B);
                        }

                        Console.WriteLine($"4B Element ID: {parameterID}, Value: {IO_Element_4B}");
                        currentCursor += 5;
                    }
                }

                // Handle 8B I/O elements
                if (currentCursor < receiveBytes.Count)
                {
                    int IO_Elements_8B_Quantity = Convert.ToInt32(receiveBytes.Skip(currentCursor).Take(1).ToList()[0]);
                    currentCursor++;
                    Console.WriteLine($"8B I/O Elements Quantity: {IO_Elements_8B_Quantity}");
                    for (int IO_8 = 0; IO_8 < IO_Elements_8B_Quantity; IO_8++)
                    {
                        if (currentCursor + 9 > receiveBytes.Count)
                        {
                            Console.WriteLine("Error: Not enough data for 8B I/O element.");
                            break;
                        }

                        var parameterID = (byte)Convert.ToInt32(receiveBytes.Skip(currentCursor).Take(1).ToList()[0]);
                        string value = string.Empty;
                        receiveBytes.Skip(currentCursor + 1).Take(8).ToList().ForEach(delegate (byte b) { value += String.Format("{0:X2}", b); });

                        var IO_Element_8B = Convert.ToInt64(value, 16);
                        if (!gpsData.IO_Elements_8B.ContainsKey(parameterID))
                        {
                            gpsData.IO_Elements_8B.Add(parameterID, IO_Element_8B);
                        }

                        Console.WriteLine($"8B Element ID: {parameterID}, Value: {IO_Element_8B}");
                        currentCursor += 9;
                    }
                }

                tokenAddress = currentCursor;

                // Ensure IMEI is set before saving to database
                if (string.IsNullOrEmpty(IMEI) || IMEI.Length < 15)
                {
                    Console.WriteLine("Error: IMEI is not valid.");
                    continue;
                }

                gpsData.IMEI = IMEI.Substring(0, 15);

                Data dt = new Data();
                dt.SaveGPSPositionFMXXXX(gpsData);

                FMXXXXIOB _fmElement = new FMXXXXIOB();
                _fmElement._gpsData = gpsData;
                _fmElement.Store1B();
                _fmElement.Store2B();
                _fmElement.Store4B();
                _fmElement.Store8B();

                dt.SaveGPSElementsFMXXXX(gpsData.IMEI, _fmElement._gpsElement);
            }

            // Calculate and verify CRC
            string crcString = string.Empty;
            receiveBytes.Skip(dataLength + 8).Take(4).ToList().ForEach(delegate (byte b) { crcString += String.Format("{0:X2}", b); });
            int CRC = Convert.ToInt32(crcString, 16);
            int calculatedCRC = GetCRC16(receiveBytes.Skip(8).Take(dataLength).ToArray());
            Console.WriteLine("CRC: " + CRC);
            Console.WriteLine("Calculated CRC: " + calculatedCRC);

            return calculatedCRC == CRC ? numberOfData : 0;
        }
        catch (ArgumentOutOfRangeException ex)
        {
            Console.WriteLine("ArgumentOutOfRangeException: " + ex.Message);
            return 0;
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception: " + ex.Message);
            return 0;
        }
    }

    private int GetCRC16(byte[] buffer)
    {
        return GetCRC16(buffer, buffer.Length, 0xA001);
    }

    private int GetCRC16(byte[] buffer, int bufLen, int polynom)
    {
        polynom &= 0xFFFF;
        int crc = 0;
        for (int i = 0; i < bufLen; i++)
        {
            int data = buffer[i] & 0xFF;
            crc ^= data;
            for (int j = 0; j < 8; j++)
            {
                if ((crc & 0x0001) != 0)
                {
                    crc = (crc >> 1) ^ polynom;
                }
                else
                {
                    crc = crc >> 1;
                }
            }
        }
        return crc & 0xFFFF;
    }
}

}

please help me whether I have written parsing logic properly if not please help

Hello,

The error message indicates that parser is trying to process data that does not match the expected format, This is because the Codec 8 Extended AVL Data IO element Length is different then Codec 8 , please check the data structure and length difference from link : Codec - Wiki Knowledge Base | Teltonika GPS

I will suggest you to use the Teltonika source code and parser for the devices .
You can download the necessary files from this link: Universal Device Test Guide - Wiki Knowledge Base | Teltonika GPS

Check the FAQ page from more information Help with Server FAQ - Wiki Knowledge Base | Teltonika GPS

Regards
Maryam

2 Likes

@Maryam Thank You My Problem Resolved