using System.Globalization; namespace InnovEnergy.Lib.Devices.BatteryDeligreen; public class TelemetryFrameParser { private static Int32 _currentIndex; private const Int32 FrameLenght = 286; public void ParsingTelemetryFrame(String response) { _currentIndex = 0; // Reset currentIndex to the start if (string.IsNullOrEmpty(response) || response.Length < FrameLenght) { Console.WriteLine("Response is too short to contain valid data."); return; } // Check starting byte string startingByte = response.Substring(_currentIndex, 2).ToUpper(); if (startingByte == "7E") { Console.WriteLine($"Starting byte: {startingByte} (Hex)"); } else { Console.WriteLine($"Incorrect starting byte: {startingByte}"); return; } _currentIndex += 2; // Extract firmware version var versionBytes = response.Substring(_currentIndex, 4); try { String versionAscii = HexToAscii(versionBytes); Console.WriteLine($"Firmware version: {versionBytes} (Hex), ASCII: {versionAscii}"); } catch (Exception) { Console.WriteLine($"Failed to decode firmware version from bytes: {versionBytes}"); return; } _currentIndex += 4; // Extract and parse other fields ParseAndPrintHexField(response, "Device Address", 4); ParseAndPrintHexField(response, "Device Code (CID1)", 4); ParseAndPrintHexField(response, "Function Code", 4); ParseAndPrintHexField(response, "Length Code", 8); ParseAndPrintHexField(response, "Data Flag", 4); ParseAndPrintHexField(response, "Command Group", 4); ParseAndPrintHexField(response, "Number of Cells", 4); // Process voltages for all 16 cells for (var i = 0; i < 16; i++) { String cellVoltageBytes = response.Substring(_currentIndex, 8); try { var cellVoltageAscii = HexToAscii(cellVoltageBytes); var cellVoltageDecimal = HexToDecimal(cellVoltageAscii) / 1000.0; // cell voltage are divided 1000 Console.WriteLine($"Voltage of Cell {i + 1}: {cellVoltageBytes} (Hex), ASCII: {cellVoltageAscii}, Voltage: {cellVoltageDecimal:F3} V"); } catch (Exception) { Console.WriteLine($"Failed to decode Voltage of Cell {i + 1} from bytes: {cellVoltageBytes}"); } _currentIndex += 8; } // Parse other fields ParseAndPrintHexField(response, "Number of Temperature Sensors", 4); // Parse cell temperatures for (var i = 1; i <= 4; i++) { ParseAndPrintTemperatureField(response, $"Cell Temperature {i}"); } // Parse other temperature and battery information ParseAndPrintTemperatureField(response, "Environment Temperature"); ParseAndPrintTemperatureField(response, "Power Temperature"); ParseAndPrintField(response, "Charge/Discharge Current", 8, value => value / 100.0, "A"); ParseAndPrintField(response, "Total Battery Voltage", 8, value => value / 100.0, "V"); ParseAndPrintField(response, "Residual Capacity", 8, value => value / 100.0, "Ah"); ParseAndPrintHexField(response, "Custom Number", 4); ParseAndPrintField(response, "Battery Capacity", 8, value => value / 100.0, "Ah"); ParseAndPrintField(response, "SOC", 8, value => value / 10.0, "%"); ParseAndPrintField(response, "Rated Capacity", 8, value => value / 100.0, "Ah"); ParseAndPrintHexField(response, "Number of Cycles", 8); ParseAndPrintField(response, "SOH", 8, value => value / 10.0, "%"); ParseAndPrintField(response, "Bus Voltage", 8, value => value / 100.0, "V"); } private static void ParseAndPrintHexField(String response, String fieldName, int length) { var hexBytes = response.Substring(_currentIndex, length); try { var asciiValue = HexToAscii(hexBytes); var decimalValue = int.Parse(asciiValue, NumberStyles.HexNumber); Console.WriteLine($"{fieldName}: {hexBytes} (Hex), ASCII: {asciiValue}, Decimal: {decimalValue}"); } catch (Exception) { Console.WriteLine($"Failed to decode {fieldName} from bytes: {hexBytes}"); } _currentIndex += length; } private static void ParseAndPrintTemperatureField(String response, String fieldName) { var tempBytes = response.Substring(_currentIndex, 8); try { var tempAscii = HexToAscii(tempBytes); var tempDecimal = (HexToDecimal(tempAscii) - 2731) / 10.0; Console.WriteLine($"{fieldName}: {tempBytes} (Hex), ASCII: {tempAscii}, Temperature: {tempDecimal:F2} °C"); } catch (Exception) { Console.WriteLine($"Failed to decode {fieldName} from bytes: {tempBytes}"); } _currentIndex += 8; } private static void ParseAndPrintField(String response, String fieldName, Int32 length, Func conversion, String unit) { var fieldBytes = response.Substring(_currentIndex, length); try { var fieldAscii = HexToAscii(fieldBytes); var fieldDecimal = conversion(HexToDecimal(fieldAscii)); Console.WriteLine($"{fieldName}: {fieldBytes} (Hex), ASCII: {fieldAscii}, {fieldName}: {fieldDecimal:F3} {unit}"); } catch (Exception) { Console.WriteLine($"Failed to decode {fieldName} from bytes: {fieldBytes}"); } _currentIndex += length; } private static String HexToAscii(String hex) { var bytes = new Byte[hex.Length / 2]; for (var i = 0; i < hex.Length; i += 2) { bytes[i / 2] = byte.Parse(hex.Substring(i, 2), NumberStyles.HexNumber); } return System.Text.Encoding.ASCII.GetString(bytes); } private static double HexToDecimal(String hex) { return int.Parse(hex, NumberStyles.HexNumber); } }