221 lines
8.9 KiB
C#
221 lines
8.9 KiB
C#
using System.Globalization;
|
|
|
|
namespace InnovEnergy.Lib.Devices.BatteryDeligreen;
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
|
|
public class TelecommandFrameParser
|
|
{
|
|
private static Int32 _currentIndex;
|
|
private const Int32 FrameLength = 232;
|
|
|
|
private static readonly Dictionary<String, String> ByteAlarmCodes = new()
|
|
{
|
|
{ "00", "Normal, no alarm" },
|
|
{ "01", "Alarm that analog quantity reaches the lower limit" },
|
|
{ "02", "Alarm that analog quantity reaches the upper limit" },
|
|
{ "F0", "Other alarms" }
|
|
};
|
|
|
|
public BatteryDeligreenAlarmRecord? ParsingTelecommandFrame(String response)
|
|
{
|
|
_currentIndex = 0; // Reset currentIndex to the start
|
|
|
|
if (string.IsNullOrEmpty(response) || response.Length < FrameLength)
|
|
{
|
|
Console.WriteLine("Response is too short to contain valid data.");
|
|
Console.WriteLine(" Fixed Length" + FrameLength);
|
|
Console.WriteLine(" response Length" + response.Length);
|
|
return null;
|
|
}
|
|
|
|
// 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 null;
|
|
}
|
|
|
|
_currentIndex += 2;
|
|
|
|
// Extract firmware version
|
|
var versionBytes = response.Substring(_currentIndex, 4);
|
|
try
|
|
{
|
|
var versionAscii = HexToAscii(versionBytes);
|
|
// Console.WriteLine($"Firmware version: {versionBytes} (Hex), ASCII: {versionAscii}");
|
|
}
|
|
catch (Exception)
|
|
{
|
|
Console.WriteLine($"Failed to decode firmware version from bytes: {versionBytes}");
|
|
return null;
|
|
}
|
|
|
|
_currentIndex += 4;
|
|
|
|
// Extract and parse other fields
|
|
ParseAndPrintHexField(response, "Device Address", 4); // this is not added to the Alarm record
|
|
ParseAndPrintHexField(response, "Device Code (CID1)", 4); // this is not added to the Alarm record
|
|
ParseAndPrintHexField(response, "Function Code", 4); // this is not added to the Alarm record
|
|
ParseAndPrintHexField(response, "Length Code", 8); // this is not added to the Alarm record
|
|
ParseAndPrintHexField(response, "Data Flag", 4); // this is not added to the Alarm record
|
|
ParseAndPrintHexField(response, "Command Group", 4); // this is not added to the Alarm record
|
|
ParseAndPrintHexField(response, "Number of Cells", 4); // this is not added to the Alarm record
|
|
|
|
// Parse Cell Temperature Alarm fields
|
|
var cellAlarmList = ExtractCellAlarm(response);
|
|
|
|
// Parse Number of Temperature Alarm
|
|
ParseAndPrintHexField(response, "Number of Temperature ", 4); // this is not added to the Alarm record
|
|
|
|
// Parse Cell Temperature Alarm fields
|
|
var cellTemperatureAlarm = ExtractCellTempAlarm(response);
|
|
var enviTempAlarm = ParseAndPrintField(response, "Environment Temperature Alarm" );
|
|
var powerTempAlarm = ParseAndPrintField(response, "Power Temperature Alarm" );
|
|
var currentAlarm = ParseAndPrintField(response, "Charge/Discharge Current Alarm" );
|
|
var totalVoltageAlarm = ParseAndPrintField(response, "Total Battery Voltage Alarm" );
|
|
var numberOfCustom = ParseAndPrintField(response, "Number of Custom Alarm");
|
|
var alarmEvent1 = ParseByteAlarm(response, "Alarm Event 1");
|
|
var alarmEvent2 = ParseByteAlarm(response, "Alarm Event 2");
|
|
var alarmEvent3 = ParseByteAlarm(response, "Alarm Event 3");
|
|
var alarmEvent4 = ParseByteAlarm(response, "Alarm Event 4");
|
|
var alarmEvent5 = ParseByteAlarm(response, "Alarm Event 5");
|
|
var alarmEvent6 = ParseByteAlarm(response, "Alarm Event 6");
|
|
var onOffState = ParseByteAlarm(response, "onOffState");
|
|
var equilibriumState1 = ParseByteAlarm(response, "equilibriumState1");
|
|
var equilibriumState2 = ParseByteAlarm(response, "equilibriumState2");
|
|
var systemState = ParseByteAlarm(response, "systemState");
|
|
var disconnectionState1 = ParseByteAlarm(response, "DisconnectionState1");
|
|
var disconnectionState2 = ParseByteAlarm(response, "DisconnectionState2");
|
|
var alarmEvent7 = ParseByteAlarm(response, "Alarm Event 7");
|
|
var alarmEvent8 = ParseByteAlarm(response, "Alarm Event 8");
|
|
|
|
var batteryAlarmRecord = new BatteryDeligreenAlarmRecord(cellAlarmList, cellTemperatureAlarm, enviTempAlarm, powerTempAlarm,currentAlarm, totalVoltageAlarm,
|
|
alarmEvent1,alarmEvent2, alarmEvent3,alarmEvent4, alarmEvent5, alarmEvent6, onOffState, equilibriumState1, equilibriumState2, systemState,disconnectionState1, disconnectionState2, alarmEvent7, alarmEvent8);
|
|
|
|
return batteryAlarmRecord;
|
|
}
|
|
|
|
private static List<String> ExtractCellTempAlarm(String response)
|
|
{
|
|
var cellTempAlarmList = new List<String>();
|
|
|
|
var tempCellAlarm = response.Substring(_currentIndex, 4);
|
|
for (var i = 0; i < 4; i++)
|
|
{
|
|
try
|
|
{
|
|
var tempAscii = HexToAscii(tempCellAlarm);
|
|
var alarmMessage = ByteAlarmCodes.ContainsKey(tempAscii) ? ByteAlarmCodes[tempAscii] : "Unknown alarm code";
|
|
cellTempAlarmList.Add(alarmMessage);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
Console.WriteLine($"Failed to decode Cell Temp Alarm {i + 1} from bytes: {tempCellAlarm}");
|
|
}
|
|
_currentIndex += 4;
|
|
}
|
|
|
|
return cellTempAlarmList;
|
|
}
|
|
|
|
|
|
private static List<String> ExtractCellAlarm(String response)
|
|
{
|
|
var cellAlarmList = new List<String>();
|
|
|
|
// Process Alarms for all 16 cells
|
|
for (var i = 0; i < 16; i++)
|
|
{
|
|
var cellAlarm = response.Substring(_currentIndex, 4);
|
|
try
|
|
{
|
|
var alarmAscii = HexToAscii(cellAlarm);
|
|
var alarmMessage = ByteAlarmCodes.ContainsKey(alarmAscii) ? ByteAlarmCodes[alarmAscii] : "Unknown alarm code";
|
|
cellAlarmList.Add(alarmMessage);
|
|
|
|
// Console.WriteLine($"Cell {i + 1}: Alarm Code {cellAlarm}, Status: {alarmMessage}");
|
|
}
|
|
catch (Exception)
|
|
{
|
|
Console.WriteLine($"Failed to decode Cell Alarm {i + 1} from bytes: {cellAlarm}");
|
|
}
|
|
_currentIndex += 4;
|
|
}
|
|
return cellAlarmList;
|
|
}
|
|
|
|
private static void ParseAndPrintHexField(String response, String fieldName, Int32 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 Byte ParseByteAlarm(String response, String fieldName)
|
|
{
|
|
var fieldBytes = response.Substring(_currentIndex, 4);
|
|
Byte byteValue = 0;
|
|
try
|
|
{
|
|
var tempAscii = HexToAscii(fieldBytes);
|
|
byteValue = byte.Parse(tempAscii, NumberStyles.HexNumber);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
Console.WriteLine($"Failed to decode : {fieldName}" + " Alarm");
|
|
}
|
|
_currentIndex += 4;
|
|
return byteValue;
|
|
}
|
|
|
|
private static String ParseAndPrintField(String response, String fieldName)
|
|
{
|
|
var fieldBytes = response.Substring(_currentIndex, 4);
|
|
var alarmMessage = "Failed to read alarm";
|
|
|
|
try
|
|
{
|
|
var tempAscii = HexToAscii(fieldBytes);
|
|
alarmMessage = ByteAlarmCodes.ContainsKey(tempAscii) ? ByteAlarmCodes[tempAscii] : "Unknown alarm code";
|
|
}
|
|
catch (Exception)
|
|
{
|
|
Console.WriteLine($"Failed to decode : {fieldName}" + " Alarm");
|
|
}
|
|
_currentIndex += 4;
|
|
|
|
return alarmMessage;
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|