261 lines
9.0 KiB
C#
261 lines
9.0 KiB
C#
using System.IO.Ports;
|
|
using InnovEnergy.Lib.Utils;
|
|
|
|
namespace InnovEnergy.Lib.Devices.BatteryDeligreen;
|
|
|
|
public class BatteryDeligreenDevice
|
|
{
|
|
private const Parity Parity = System.IO.Ports.Parity.None;
|
|
private const StopBits StopBits = System.IO.Ports.StopBits.One;
|
|
private const Int32 BaudRate = 19200;
|
|
private const Int32 DataBits = 8;
|
|
|
|
private readonly SerialPort _serialPort;
|
|
|
|
public UInt16 SlaveId { get; }
|
|
|
|
// Dynamically construct the frame to send
|
|
private const String FrameStart = "7E"; // Starting of the frame
|
|
private const String Version = "3230"; // Protocol version
|
|
private const String DeviceCode = "3436"; // Device Code
|
|
private const String TelemetryFunctionCode = "3432";
|
|
private const String TelcommandFunctionCode = "3434";
|
|
|
|
private static SerialPort _sharedSerialPort;
|
|
|
|
private static SerialPort GetSharedPort(string tty)
|
|
{
|
|
if (_sharedSerialPort == null)
|
|
{
|
|
_sharedSerialPort = new SerialPort(tty, BaudRate, Parity, DataBits, StopBits)
|
|
{
|
|
ReadTimeout = 1000, // 1 second timeout for reads
|
|
WriteTimeout = 1000 // 1 second timeout for writes
|
|
};
|
|
try
|
|
{
|
|
// Open the shared serial port
|
|
_sharedSerialPort.Open();
|
|
Console.WriteLine("Shared Serial Port opened successfully.");
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Console.WriteLine(e);
|
|
}
|
|
}
|
|
|
|
return _sharedSerialPort;
|
|
}
|
|
|
|
public static void CloseSharedPort()
|
|
{
|
|
_sharedSerialPort?.Close();
|
|
Console.WriteLine("Shared Serial Port closed.");
|
|
}
|
|
|
|
// Constructor for local serial port connection
|
|
public BatteryDeligreenDevice(String tty, UInt16 slaveId)
|
|
{
|
|
SlaveId = slaveId;
|
|
_serialPort = GetSharedPort(tty);
|
|
}
|
|
|
|
// Method to send data to the device
|
|
private void Write(String hexCommand)
|
|
{
|
|
try
|
|
{
|
|
// Convert hex string to byte array
|
|
byte[] commandBytes = HexStringToByteArray(hexCommand);
|
|
|
|
// Send the command
|
|
_serialPort.Write(commandBytes, 0, commandBytes.Length);
|
|
//Console.WriteLine("Write Command sent successfully.");
|
|
}
|
|
catch (TimeoutException)
|
|
{
|
|
Console.WriteLine("Write operation timed out.");
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Console.WriteLine($"Error during write operation: {e.Message}");
|
|
throw;
|
|
}
|
|
}
|
|
|
|
// Method to read data from the device
|
|
private Byte[] Read(Int32 bufferSize)
|
|
{
|
|
try
|
|
{
|
|
// Read data from the serial port
|
|
var buffer = new Byte[bufferSize];
|
|
var bytesRead = _serialPort.Read(buffer, 0, bufferSize);
|
|
|
|
//Console.WriteLine($"Read {bytesRead} bytes from the device.");
|
|
|
|
// Return only the received bytes
|
|
var responseData = new Byte[bytesRead];
|
|
Array.Copy(buffer, responseData, bytesRead);
|
|
return responseData;
|
|
}
|
|
catch (TimeoutException)
|
|
{
|
|
Console.WriteLine("Read operation timed out.");
|
|
return Array.Empty<Byte>(); // Return empty array on timeout
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Console.WriteLine($"Error during read operation: {e.Message}");
|
|
throw;
|
|
}
|
|
}
|
|
|
|
private static String BytesToHexString(byte[] byteArray)
|
|
{
|
|
return BitConverter.ToString(byteArray).Replace("-", "").ToUpper();
|
|
}
|
|
|
|
// Helper method to convert a hex string to a byte array
|
|
private static Byte[] HexStringToByteArray(string hex)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(hex) || hex.Length % 2 != 0)
|
|
throw new ArgumentException("Invalid hex string.");
|
|
|
|
byte[] bytes = new byte[hex.Length / 2];
|
|
for (var i = 0; i < hex.Length; i += 2)
|
|
{
|
|
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
|
|
}
|
|
|
|
return bytes;
|
|
}
|
|
|
|
// Dispose method to release the serial port
|
|
public void Dispose()
|
|
{
|
|
if (_serialPort.IsOpen)
|
|
{
|
|
_serialPort.Close();
|
|
Console.WriteLine("Serial port closed.");
|
|
}
|
|
}
|
|
|
|
// Read telemetry data from the connected device
|
|
private async Task<BatteryDeligreenDataRecord?> ReadTelemetryData(UInt16 batteryId)
|
|
{
|
|
String frameToSend = batteryId switch
|
|
{
|
|
0 => "7E3230303034363432453030323030464433370D",
|
|
1 => "7E3230303134363432453030323031464433350D",
|
|
2 => "7E3230303234363432453030323032464433330D",
|
|
3 => "7E3230303334363432453030323033464433310D",
|
|
4 => "7E3230303434363432453030323034464432460D",
|
|
5 => "7E3230303534363432453030323035464432440D",
|
|
6 => "7E3230303634363432453030323036464432420D",
|
|
7 => "7E3230303734363432453030323037464432390D",
|
|
8 => "7E3230303834363432453030323038464432370D",
|
|
9 => "7E3230303934363432453030323039464432350D",
|
|
_ => "0"
|
|
};
|
|
// var frameToSend = ConstructFrameToSend(batteryId,TelemetryFunctionCode);
|
|
|
|
try
|
|
{
|
|
// Write the frame to the channel (send it to the device)
|
|
Write(frameToSend);
|
|
// Read the response from the channel (assuming max response size)
|
|
var responseBytes = await ReadFullResponse(168, 64);
|
|
|
|
// Convert the byte array to a hexadecimal string
|
|
var responseHex = BytesToHexString(responseBytes);
|
|
|
|
return new TelemetryFrameParser().ParsingTelemetryFrame(responseHex);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"Error during telemetry data retrieval: {ex.Message}");
|
|
throw;
|
|
}
|
|
}
|
|
|
|
private Task<Byte[]> ReadFullResponse(Int32 totalBytes, Int32 chunkSize)
|
|
{
|
|
var responseBuffer = new List<Byte>();
|
|
while (responseBuffer.Count < totalBytes)
|
|
{
|
|
// Calculate how many more bytes need to be read
|
|
var bytesToRead = Math.Min(chunkSize, totalBytes - responseBuffer.Count);
|
|
var chunk = Read(bytesToRead);
|
|
|
|
if (chunk.Length == 0)
|
|
{
|
|
throw new TimeoutException("Failed to read the expected number of bytes from the device.");
|
|
}
|
|
|
|
responseBuffer.AddRange(chunk);
|
|
}
|
|
|
|
return Task.FromResult(responseBuffer.ToArray());
|
|
}
|
|
|
|
private async Task<BatteryDeligreenAlarmRecord> ReadTelecomandData(UInt16 batteryId)
|
|
{
|
|
var frameToSend = batteryId switch
|
|
{
|
|
0 => "7E3230303034363434453030323030464433350D",
|
|
1 => "7E3230303134363434453030323031464433330D",
|
|
2 => "7E3230303234363434453030323032464433310D",
|
|
3 => "7E3230303334363434453030323033464432460D",
|
|
4 => "7E3230303434363434453030323034464432440D",
|
|
5 => "7E3230303534363434453030323035464432420D",
|
|
6 => "7E3230303634363434453030323036464432390D",
|
|
7 => "7E3230303734363434453030323037464432370D",
|
|
8 => "7E3230303834363434453030323038464432350D",
|
|
9 => "7E3230303934363434453030323039464432330D",
|
|
_ => "0"
|
|
};
|
|
try
|
|
{
|
|
// Write the frame to the channel (send it to the device)
|
|
Write(frameToSend);
|
|
// await Task.Delay(delayFrame2);
|
|
// Read the response from the channel (assuming max response size)
|
|
var responseBytes = await ReadFullResponse(116, 64); // Assuming Read can be executed asynchronously
|
|
// Convert the byte array to a hexadecimal string
|
|
var responseHex = BytesToHexString(responseBytes);
|
|
|
|
var response = new TelecommandFrameParser().ParsingTelecommandFrame(responseHex);
|
|
|
|
return new BatteryDeligreenAlarmRecord();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"Error during Telecomnd data retrieval: {ex.Message}");
|
|
throw;
|
|
}
|
|
}
|
|
|
|
public async Task<BatteryDeligreenRecord?> Reads()
|
|
{
|
|
var dataRecord = ReadTelemetryData(SlaveId).Result;
|
|
var alarmRecord = ReadTelecomandData(SlaveId).Result;
|
|
await Task.Delay(5); // looks like this is need. A time delay needed between each frame to send to each battery
|
|
|
|
return dataRecord != null ? new BatteryDeligreenRecord(dataRecord, alarmRecord) : null;
|
|
}
|
|
|
|
private static String ConstructFrameToSend(UInt16 batteryId, String functionCode)
|
|
{
|
|
// Convert batteryId to a 2-character ASCII string
|
|
var batteryIdAscii = $"{(Char)(batteryId / 10 + '0')}{(char)(batteryId % 10 + '0')}";
|
|
var batteryIdHex = string.Concat(batteryIdAscii.Select(c => ((Int32)c).ToString("X2")));
|
|
Console.WriteLine("Battery ID " + batteryIdHex);
|
|
|
|
var frameToSend =
|
|
FrameStart + Version + batteryIdHex + DeviceCode + functionCode +
|
|
"453030323030464433370D"; // Example custom frame with dynamic batteryId
|
|
Console.WriteLine(frameToSend);
|
|
return frameToSend;
|
|
}
|
|
} |