Innovenergy_trunk/csharp/Lib/Devices/BatteryDeligreen/BatteryDeligreenDevice.cs

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;
}
}