Introduce iPerl ASIC Reader with diagnostic LED control, RadioService, OptoHeadTest, SerialDriver, and TouchRead protocol improvements.
This commit is contained in:
parent
8fffb9e366
commit
fff7951957
@ -3,8 +3,6 @@ using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using log4net;
|
||||
using TBF.Rig.Output.Printers.Label;
|
||||
using TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Utils;
|
||||
using CliRunner = TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Utils.CliRunnerOld;
|
||||
using OptoHeadStatus = TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols.OptoHeadStatus;
|
||||
using SerialPortData = TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Utils.SerialPortData;
|
||||
|
||||
@ -2,104 +2,200 @@ namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4
|
||||
{
|
||||
/// <summary>
|
||||
/// Device-specific TouchRead sub-commands.
|
||||
/// These commands are used with the DeviceSpecific (0xFD) command.
|
||||
/// These sub-commands are used together with the
|
||||
/// <see cref="TouchReadCommand.DeviceSpecific"/> (0xFD) command.
|
||||
/// </summary>
|
||||
public enum TouchReadDeviceSubCommand : byte
|
||||
{
|
||||
// ---- Alarm / Mask -----------------------------------------
|
||||
/// <summary>
|
||||
/// View Alarm Mask (lower 16 bits).
|
||||
/// Returns a 2-byte little-endian alarm bit field.
|
||||
/// </summary>
|
||||
ViewAlarmMask = 0x31,
|
||||
|
||||
/// <summary>
|
||||
/// Set Alarm Mask (lower 16 bits).
|
||||
/// Payload: 2-byte little-endian alarm bit field.
|
||||
/// </summary>
|
||||
SetAlarmMask = 0x32,
|
||||
|
||||
/// <summary>
|
||||
/// View alarm persistence period (days).
|
||||
/// Range: 8–90 days.
|
||||
/// </summary>
|
||||
ViewPersistence = 0x33,
|
||||
|
||||
/// <summary>
|
||||
/// Set alarm persistence period (days).
|
||||
/// Range: 8–90 days.
|
||||
/// </summary>
|
||||
SetPersistence = 0x34,
|
||||
|
||||
/// <summary>
|
||||
/// View leak duration (hours).
|
||||
/// Range: 24–180 hours.
|
||||
/// </summary>
|
||||
ViewLeakDuration = 0x35,
|
||||
|
||||
/// <summary>
|
||||
/// Set leak duration (hours).
|
||||
/// Range: 24–180 hours.
|
||||
/// </summary>
|
||||
SetLeakDuration = 0x36,
|
||||
|
||||
ViewAlarms = 0x37,
|
||||
SetAlarms = 0x38,
|
||||
// ==========================================================
|
||||
// System / Time
|
||||
// ==========================================================
|
||||
|
||||
/// <summary>
|
||||
/// View system time.
|
||||
/// Returns uint32 seconds since 2000-01-01.
|
||||
/// Returns uint32 seconds since 2000-01-01 00:00:00.
|
||||
/// </summary>
|
||||
ViewSystemTime = 0x10,
|
||||
|
||||
/// <summary>
|
||||
/// Set system time.
|
||||
/// Payload: uint32 seconds since 2000-01-01.
|
||||
/// If zero, device will reset and erase data.
|
||||
/// If set to zero, the meter resets and erases data.
|
||||
/// Protected by meter seal.
|
||||
/// </summary>
|
||||
SetSystemTime = 0x11,
|
||||
|
||||
// ==========================================================
|
||||
// Alarm Mask / Alarm Configuration
|
||||
// ==========================================================
|
||||
|
||||
// ---- Manufacture / Time -----------------------------------
|
||||
ViewManufactureDate = 0x39,
|
||||
SetManufactureDate = 0x3A,
|
||||
/// <summary>View alarm mask (lower 16 bits).</summary>
|
||||
ViewAlarmMask = 0x31,
|
||||
|
||||
ViewSecondsIdle = 0x3B,
|
||||
ViewSecondsActive = 0x3D,
|
||||
ViewSecondsUsed = 0x3F,
|
||||
/// <summary>Set alarm mask (lower 16 bits).</summary>
|
||||
SetAlarmMask = 0x32,
|
||||
|
||||
// ---- Snapshot / Logging -----------------------------------
|
||||
ViewSnapshotData = 0x41,
|
||||
ViewDatalogDuration = 0x43,
|
||||
SetDatalogDuration = 0x44,
|
||||
ReadDatalog = 0x45,
|
||||
ClearDatalog = 0x46,
|
||||
/// <summary>View alarm persistence period (days).</summary>
|
||||
ViewPersistence = 0x33,
|
||||
|
||||
// ---- History ----------------------------------------------
|
||||
ViewHistoryMask = 0x47,
|
||||
SetHistoryMask = 0x48,
|
||||
ReadHistory = 0x49,
|
||||
ClearHistory = 0x4A,
|
||||
/// <summary>Set alarm persistence period (days).</summary>
|
||||
SetPersistence = 0x34,
|
||||
|
||||
// ---- Diagnostics ------------------------------------------
|
||||
ViewDiagnostics = 0x4B,
|
||||
ResetDiagnostics = 0x4C,
|
||||
/// <summary>View leak duration (hours).</summary>
|
||||
ViewLeakDuration = 0x35,
|
||||
|
||||
// ---- Calibration / Build ----------------------------------
|
||||
ViewCalibration = 0x53,
|
||||
SetCalibration = 0x54,
|
||||
/// <summary>Set leak duration (hours).</summary>
|
||||
SetLeakDuration = 0x36,
|
||||
|
||||
ViewIPerlBuild = 0x65,
|
||||
SetIPerlBuild = 0x66,
|
||||
/// <summary>View current alarm states.</summary>
|
||||
ViewAlarms = 0x37,
|
||||
|
||||
// ---- Bootloader (dangerous!) ------------------------------
|
||||
EnterBootloader = 0x81,
|
||||
ReadFlash = 0x82,
|
||||
EraseAll = 0x83,
|
||||
EraseSegment = 0x84,
|
||||
UpdateCode = 0x85,
|
||||
ExitBootloader = 0x86
|
||||
/// <summary>Set alarm states (protected by meter seal).</summary>
|
||||
SetAlarms = 0x38,
|
||||
|
||||
// ==========================================================
|
||||
// Manufacture / Counters
|
||||
// ==========================================================
|
||||
|
||||
/// <summary>View manufacture date.</summary>
|
||||
ViewManufactureDate = 0x39,
|
||||
|
||||
/// <summary>Set manufacture date (protected by meter seal).</summary>
|
||||
SetManufactureDate = 0x3A,
|
||||
|
||||
/// <summary>View seconds idle.</summary>
|
||||
ViewSecondsIdle = 0x3B,
|
||||
|
||||
/// <summary>View seconds active.</summary>
|
||||
ViewSecondsActive = 0x3D,
|
||||
|
||||
/// <summary>View seconds used.</summary>
|
||||
ViewSecondsUsed = 0x3F,
|
||||
|
||||
// ==========================================================
|
||||
// Snapshot / Datalog
|
||||
// ==========================================================
|
||||
|
||||
/// <summary>View snapshot data.</summary>
|
||||
ViewSnapshotData = 0x41,
|
||||
|
||||
/// <summary>View datalog duration.</summary>
|
||||
ViewDatalogDuration = 0x43,
|
||||
|
||||
/// <summary>Set datalog duration.</summary>
|
||||
SetDatalogDuration = 0x44,
|
||||
|
||||
/// <summary>Read datalog.</summary>
|
||||
ReadDatalog = 0x45,
|
||||
|
||||
/// <summary>Clear datalog.</summary>
|
||||
ClearDatalog = 0x46,
|
||||
|
||||
// ==========================================================
|
||||
// History
|
||||
// ==========================================================
|
||||
|
||||
/// <summary>View history mask.</summary>
|
||||
ViewHistoryMask = 0x47,
|
||||
|
||||
/// <summary>Set history mask.</summary>
|
||||
SetHistoryMask = 0x48,
|
||||
|
||||
/// <summary>Read history.</summary>
|
||||
ReadHistory = 0x49,
|
||||
|
||||
/// <summary>Clear history.</summary>
|
||||
ClearHistory = 0x4A,
|
||||
|
||||
// ==========================================================
|
||||
// Diagnostics / Status
|
||||
// ==========================================================
|
||||
|
||||
/// <summary>View diagnostics.</summary>
|
||||
ViewDiagnostics = 0x4B,
|
||||
|
||||
/// <summary>Reset diagnostics.</summary>
|
||||
ResetDiagnostics = 0x4C,
|
||||
|
||||
/// <summary>View status file.</summary>
|
||||
ViewStatusFile = 0x4F,
|
||||
|
||||
/// <summary>Set status file (protected by meter seal).</summary>
|
||||
SetStatusFile = 0x50,
|
||||
|
||||
// ==========================================================
|
||||
// Calibration / Configuration
|
||||
// ==========================================================
|
||||
|
||||
/// <summary>View calibration structure.</summary>
|
||||
ViewCalibrationStructure = 0x51,
|
||||
|
||||
/// <summary>Set calibration structure (protected by meter seal).</summary>
|
||||
SetCalibrationStructure = 0x52,
|
||||
|
||||
/// <summary>View calibration.</summary>
|
||||
ViewCalibration = 0x53,
|
||||
|
||||
/// <summary>Set calibration (protected by meter seal).</summary>
|
||||
SetCalibration = 0x54,
|
||||
|
||||
/// <summary>View reboot count.</summary>
|
||||
ViewRebootCount = 0x55,
|
||||
|
||||
/// <summary>Set reboot count (protected by meter seal).</summary>
|
||||
SetRebootCount = 0x56,
|
||||
|
||||
/// <summary>View temperature.</summary>
|
||||
ViewTemperature = 0x57,
|
||||
|
||||
/// <summary>Set temperature (protected by meter seal).</summary>
|
||||
SetTemperature = 0x58,
|
||||
|
||||
// ==========================================================
|
||||
// Diagnostic LED / Hardware
|
||||
// ==========================================================
|
||||
|
||||
/// <summary>
|
||||
/// Set diagnostic LED state.
|
||||
/// Enables or disables high-speed LED serial output.
|
||||
/// <para>
|
||||
/// See <see cref="TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed.DiagnosticLedState"/>
|
||||
/// diagnostic LED output modes.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
SetDiagnosticLEDState = 0x60,
|
||||
|
||||
|
||||
// ==========================================================
|
||||
// Build / Firmware Info
|
||||
// ==========================================================
|
||||
|
||||
/// <summary>View iPERL build information.</summary>
|
||||
ViewIPerlBuild = 0x65,
|
||||
|
||||
/// <summary>Set iPERL build (protected by meter seal).</summary>
|
||||
SetIPerlBuild = 0x66,
|
||||
|
||||
// ==========================================================
|
||||
// Bootloader (DANGEROUS – use with care)
|
||||
// ==========================================================
|
||||
|
||||
/// <summary>Enter bootloader mode.</summary>
|
||||
EnterBootloader = 0x81,
|
||||
|
||||
/// <summary>Read FLASH memory.</summary>
|
||||
ReadFlash = 0x82,
|
||||
|
||||
/// <summary>Erase all FLASH memory.</summary>
|
||||
EraseAll = 0x83,
|
||||
|
||||
/// <summary>Erase FLASH segment.</summary>
|
||||
EraseSegment = 0x84,
|
||||
|
||||
/// <summary>Update firmware code.</summary>
|
||||
UpdateCode = 0x85,
|
||||
|
||||
/// <summary>Exit bootloader mode.</summary>
|
||||
ExitBootloader = 0x86
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4
|
||||
{
|
||||
@ -47,6 +48,14 @@ namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public TouchReadFrameBuilder AddDiagnosticLedState(DiagnosticLedState state)
|
||||
{
|
||||
_information.Add((byte)TouchReadCommand.DeviceSpecific);
|
||||
_information.Add((byte)TouchReadDeviceSubCommand.SetDiagnosticLEDState);
|
||||
_information.Add((byte)state);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TouchReadFrameBuilder AddNullTerminatedAscii(string text)
|
||||
{
|
||||
|
||||
@ -1,13 +1,93 @@
|
||||
namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed
|
||||
{
|
||||
/// <summary>
|
||||
/// Diagnostic LED output mode.
|
||||
/// <para>
|
||||
/// Determines the format and content of high-speed serial diagnostic data
|
||||
/// emitted by the meter when the diagnostic LED is enabled.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Each state corresponds to a specific TAB-separated ASCII HEX frame layout
|
||||
/// as defined in the iPERL TouchRead protocol documentation.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// See <see cref="TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.TouchReadDeviceSubCommand.SetDiagnosticLEDState"/>
|
||||
/// diagnostic LED States.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public enum DiagnosticLedState : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Diagnostic LED OFF - State #0.
|
||||
/// <para>
|
||||
/// Basic diagnostic output containing raw ADC, field strength,
|
||||
/// flow rate, volume accumulator, and capacitor voltage.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
StateOFF = 0x00,
|
||||
|
||||
/// <summary>
|
||||
/// Diagnostic LED State #1.
|
||||
/// <para>
|
||||
/// Basic diagnostic output containing raw ADC, field strength,
|
||||
/// flow rate, volume accumulator, and capacitor voltage.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
State1 = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// Diagnostic LED State #2.
|
||||
/// <para>
|
||||
/// Extends State #1 with LCD volume, meter state,
|
||||
/// and low-flow cutoff indication.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
State2 = 0x02,
|
||||
|
||||
/// <summary>
|
||||
/// Diagnostic LED State #3.
|
||||
/// <para>
|
||||
/// Extends State #1 with field calibration value,
|
||||
/// ASIC timestamp, and field drive time.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
State3 = 0x03,
|
||||
|
||||
/// <summary>
|
||||
/// Diagnostic LED State #4.
|
||||
/// <para>
|
||||
/// Extended diagnostic output including mean flow rate,
|
||||
/// field measurements, integrator calibration values,
|
||||
/// and ASIC state.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
State4 = 0x04,
|
||||
|
||||
/// <summary>
|
||||
/// Diagnostic LED State #5.
|
||||
/// <para>
|
||||
/// Extends State #4 with water impedance measurement.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
State5 = 0x05,
|
||||
|
||||
/// <summary>
|
||||
/// Diagnostic LED State #6.
|
||||
/// <para>
|
||||
/// Extends State #5 with electrode delta, spike detection data,
|
||||
/// pipe status, LCD volume, and additional ASIC state.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
State6 = 0x06,
|
||||
|
||||
/// <summary>
|
||||
/// Diagnostic LED State #7.
|
||||
/// <para>
|
||||
/// Extends State #6 with raw ADC before offset correction,
|
||||
/// detrended ADC value, imaginary water impedance,
|
||||
/// electrode voltage noise, and ADC offset learning status.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
State7 = 0x07
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
using log4net;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication
|
||||
{
|
||||
public class OpthoHeadService
|
||||
{
|
||||
protected static readonly ILog rfidDataLogger = LogManager.GetLogger("RfidData");
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,140 @@
|
||||
using System;
|
||||
using System.IO.Ports;
|
||||
using Common;
|
||||
using log4net;
|
||||
using TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4;
|
||||
using TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed;
|
||||
using TBF.Rig.RegisterReaders.iPerlASICReader.communication.Utils;
|
||||
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication
|
||||
{
|
||||
public class OptoHeadTest
|
||||
{
|
||||
protected static readonly ILog rfidDataLogger = LogManager.GetLogger("RfidData");
|
||||
|
||||
internal static string ReadRequest_PCB(ISmartReader iHead)
|
||||
{
|
||||
byte[] frame = new TouchReadFrameBuilder()
|
||||
.RequestResponse(true)
|
||||
.AddCommand(TouchReadCommand.ViewFactoryId)
|
||||
.BuildBytes();
|
||||
|
||||
if (iHead.DebugLevel == DebugMode.Simulate)
|
||||
{
|
||||
return "-OK Simulated response-";
|
||||
}
|
||||
|
||||
string serialNo = null;
|
||||
try
|
||||
{
|
||||
if (iHead != null)
|
||||
{
|
||||
var driver = new SerialDriverBuilder()
|
||||
.WithPort($"COM{iHead.RfidComPortNr}")
|
||||
.WithBaudRate(57600)
|
||||
.WithDataBits(8)
|
||||
.WithParity(Parity.None)
|
||||
.WithStopBits(StopBits.Two)
|
||||
.WithTimeouts(1000, 1000)
|
||||
.BuildAndConnect();
|
||||
|
||||
RadioService headService = new RadioService(driver);
|
||||
serialNo = headService.ReadRequest_PCB(iHead);
|
||||
return serialNo;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (ex.Message.ToString());
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public static string SetTestMode(ISmartReader aISmartReader)
|
||||
{
|
||||
|
||||
//Set LED to state 1
|
||||
byte[] request = new TouchReadFrameBuilder()
|
||||
.RequestResponse(true)
|
||||
.AddDiagnosticLedState(DiagnosticLedState.State1)
|
||||
.BuildBytes();
|
||||
|
||||
if (aISmartReader.DebugLevel == DebugMode.Simulate)
|
||||
{
|
||||
return "-OK Simulated response-";
|
||||
}
|
||||
|
||||
string serialNo = null;
|
||||
try
|
||||
{
|
||||
if (aISmartReader != null)
|
||||
{
|
||||
var driver = new SerialDriverBuilder()
|
||||
.WithPort($"COM{aISmartReader.RfidComPortNr}")
|
||||
.WithBaudRate(57600)
|
||||
.WithDataBits(8)
|
||||
.WithParity(Parity.None)
|
||||
.WithStopBits(StopBits.Two)
|
||||
.WithTimeouts(1000, 1000)
|
||||
.BuildAndConnect();
|
||||
|
||||
RadioService headService = new RadioService(driver);
|
||||
serialNo = headService.SetTestMode(aISmartReader);
|
||||
//correct or incorrect response
|
||||
//okResponse, errorResponse
|
||||
return serialNo;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (ex.Message.ToString());
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public static string SetActiveMode(ISmartReader aISmartReader)
|
||||
{
|
||||
//Set LED to state 1
|
||||
byte[] request = new TouchReadFrameBuilder()
|
||||
.RequestResponse(true)
|
||||
.AddDiagnosticLedState(DiagnosticLedState.StateOFF)
|
||||
.BuildBytes();
|
||||
|
||||
if (aISmartReader.DebugLevel == DebugMode.Simulate)
|
||||
{
|
||||
return "-OK Simulated response-";
|
||||
}
|
||||
|
||||
string serialNo = null;
|
||||
try
|
||||
{
|
||||
if (aISmartReader != null)
|
||||
{
|
||||
var driver = new SerialDriverBuilder()
|
||||
.WithPort($"COM{aISmartReader.RfidComPortNr}")
|
||||
.WithBaudRate(57600)
|
||||
.WithDataBits(8)
|
||||
.WithParity(Parity.None)
|
||||
.WithStopBits(StopBits.Two)
|
||||
.WithTimeouts(1000, 1000)
|
||||
.BuildAndConnect();
|
||||
|
||||
RadioService headService = new RadioService(driver);
|
||||
serialNo = headService.SetTestMode(aISmartReader);
|
||||
//correct or incorrect response
|
||||
//okResponse, errorResponse
|
||||
return serialNo;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (ex.Message.ToString());
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,126 @@
|
||||
using Common;
|
||||
using log4net;
|
||||
using TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4;
|
||||
using TBF.Rig.RegisterReaders.iPerlASICReader.communication.C4.diagnosticLed;
|
||||
using TBF.Rig.RegisterReaders.iPerlASICReader.communication.Utils;
|
||||
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication
|
||||
{
|
||||
public class RadioService
|
||||
{
|
||||
|
||||
static string okResponse = "Command complete, no errors";
|
||||
static string errorResponse = "Unable to execute";
|
||||
|
||||
private SerialDriver serialDriver;
|
||||
public RadioService(SerialDriver serialDriver)
|
||||
{
|
||||
this.serialDriver = serialDriver;
|
||||
}
|
||||
|
||||
public string ReadRequest_PCB(ISmartReader iHead)
|
||||
{
|
||||
if (!serialDriver.IsOpen())
|
||||
{
|
||||
serialDriver.Open();
|
||||
}
|
||||
|
||||
var request = new TouchReadFrameBuilder()
|
||||
.RequestResponse(true)
|
||||
.AddCommand(TouchReadCommand.ViewFactoryId)
|
||||
.BuildBytes();
|
||||
|
||||
|
||||
byte[] rawData = serialDriver.SendAndWait(request, 1000);
|
||||
if (rawData == null)
|
||||
return null;
|
||||
|
||||
// parse rawData
|
||||
var parser = new TouchReadFrameParser();
|
||||
TouchReadResponse decoded = parser.Parse(rawData);
|
||||
if (decoded.IsOk)
|
||||
{
|
||||
return decoded.GetAsciiPayload();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public string SetTestMode(ISmartReader iHead)
|
||||
{
|
||||
if (!serialDriver.IsOpen())
|
||||
{
|
||||
serialDriver.Open();
|
||||
}
|
||||
|
||||
//Set LED to state 1
|
||||
byte[] request = new TouchReadFrameBuilder()
|
||||
.RequestResponse(true)
|
||||
.AddDiagnosticLedState(DiagnosticLedState.State1)
|
||||
.BuildBytes();
|
||||
|
||||
byte[] rawData = serialDriver.SendAndWait(request, 1000);
|
||||
if (rawData == null)
|
||||
return null;
|
||||
|
||||
|
||||
// parse rawData
|
||||
var parser = new TouchReadFrameParser();
|
||||
TouchReadResponse decoded = parser.Parse(rawData);
|
||||
if (decoded.IsOk)
|
||||
{
|
||||
string asciiPayload = decoded.GetAsciiPayload();
|
||||
|
||||
//correct or incorrect response
|
||||
//okResponse, errorResponse
|
||||
|
||||
return asciiPayload;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// stop data streaming by LED
|
||||
/// </summary>
|
||||
/// <param name="iHead"></param>
|
||||
/// <returns></returns>
|
||||
public string SetActiveMode(ISmartReader iHead)
|
||||
{
|
||||
if (!serialDriver.IsOpen())
|
||||
{
|
||||
serialDriver.Open();
|
||||
}
|
||||
|
||||
//Set LED to state 1
|
||||
byte[] request = new TouchReadFrameBuilder()
|
||||
.RequestResponse(true)
|
||||
.AddDiagnosticLedState(DiagnosticLedState.StateOFF)
|
||||
.BuildBytes();
|
||||
|
||||
byte[] rawData = serialDriver.SendAndWait(request, 1000);
|
||||
if (rawData == null)
|
||||
return null;
|
||||
|
||||
|
||||
|
||||
|
||||
// parse rawData
|
||||
var parser = new TouchReadFrameParser();
|
||||
TouchReadResponse decoded = parser.Parse(rawData);
|
||||
if (decoded.IsOk)
|
||||
{
|
||||
string asciiPayload = decoded.GetAsciiPayload();
|
||||
|
||||
//correct or incorrect response
|
||||
//okResponse, errorResponse
|
||||
|
||||
return asciiPayload;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,243 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO.Ports;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.Utils
|
||||
{
|
||||
public class SerialDriver : IDisposable
|
||||
{
|
||||
public string ErrorMessage { get; private set; }
|
||||
public Collection<byte> SerialPortReadBuffer = new Collection<byte>();
|
||||
|
||||
private SerialPort _serialPort;
|
||||
private readonly List<byte[]> _binMessages = new List<byte[]>();
|
||||
private bool _isReading;
|
||||
|
||||
// Stored configuration (used by Builder)
|
||||
private readonly string _portName;
|
||||
private readonly int _baudRate;
|
||||
private readonly int _dataBits;
|
||||
private readonly Parity _parity;
|
||||
private readonly StopBits _stopBits;
|
||||
private readonly int _readTimeout;
|
||||
private readonly int _writeTimeout;
|
||||
|
||||
private readonly ManualResetEvent _responseReceived = new ManualResetEvent(false);
|
||||
|
||||
#region Constructors
|
||||
|
||||
// Default constructor (legacy support)
|
||||
public SerialDriver()
|
||||
{
|
||||
_serialPort = new SerialPort();
|
||||
}
|
||||
|
||||
// Builder constructor
|
||||
internal SerialDriver(
|
||||
string portName,
|
||||
int baudRate,
|
||||
int dataBits,
|
||||
Parity parity,
|
||||
StopBits stopBits,
|
||||
int readTimeout,
|
||||
int writeTimeout)
|
||||
{
|
||||
_portName = portName;
|
||||
_baudRate = baudRate;
|
||||
_dataBits = dataBits;
|
||||
_parity = parity;
|
||||
_stopBits = stopBits;
|
||||
_readTimeout = readTimeout;
|
||||
_writeTimeout = writeTimeout;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Open / Close
|
||||
|
||||
// Builder-based open
|
||||
public bool Open()
|
||||
{
|
||||
return OpenConnection(
|
||||
_portName,
|
||||
_baudRate,
|
||||
_dataBits,
|
||||
_parity,
|
||||
_stopBits,
|
||||
_readTimeout,
|
||||
_writeTimeout
|
||||
);
|
||||
}
|
||||
|
||||
// Legacy API (unchanged)
|
||||
public bool OpenConnection(
|
||||
string comPort,
|
||||
int baudrate,
|
||||
int dataBits,
|
||||
Parity parity,
|
||||
StopBits stopbits,
|
||||
int readTimeout = 1000,
|
||||
int writeTimeout = 1000)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
CloseConnection();
|
||||
|
||||
try
|
||||
{
|
||||
ErrorMessage = string.Empty;
|
||||
|
||||
_serialPort = new SerialPort(comPort, baudrate, parity, dataBits, stopbits)
|
||||
{
|
||||
ReadTimeout = readTimeout,
|
||||
WriteTimeout = writeTimeout
|
||||
};
|
||||
|
||||
_serialPort.DataReceived += DataReceivedHandler;
|
||||
_serialPort.Open();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ErrorMessage = $"COM error: Open failed {comPort}. {ex.Message}";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_serialPort.IsOpen)
|
||||
{
|
||||
ErrorMessage = $"COM error: Can't open {comPort}.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void CloseConnection()
|
||||
{
|
||||
if (_serialPort != null)
|
||||
{
|
||||
_serialPort.DataReceived -= DataReceivedHandler;
|
||||
if (_serialPort.IsOpen)
|
||||
_serialPort.Close();
|
||||
|
||||
_serialPort.Dispose();
|
||||
_serialPort = null;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsOpen() => _serialPort?.IsOpen == true;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Send / Receive
|
||||
|
||||
public bool SendMessage(byte[] sendDataBytes, int length, int readTimeout = 1000, int writeTimeout = 1000)
|
||||
{
|
||||
if (!IsOpen()) return false;
|
||||
if (sendDataBytes.Length == 0) return true;
|
||||
|
||||
try
|
||||
{
|
||||
PrepareReading();
|
||||
|
||||
_serialPort.WriteTimeout = writeTimeout;
|
||||
_serialPort.ReadTimeout = readTimeout;
|
||||
_serialPort.Write(sendDataBytes, 0, length);
|
||||
|
||||
_isReading = true;
|
||||
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
while (_isReading)
|
||||
{
|
||||
if (stopwatch.ElapsedMilliseconds > readTimeout)
|
||||
{
|
||||
ErrorMessage = "COM error: Receive timeout";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ErrorMessage = $"COM error: Transmit failed {_serialPort.PortName}. {ex.Message}";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void PrepareReading()
|
||||
{
|
||||
_serialPort.DiscardInBuffer();
|
||||
_binMessages.Clear();
|
||||
_responseReceived.Reset();
|
||||
_isReading = true;
|
||||
}
|
||||
|
||||
public byte[] GetRawData()
|
||||
{
|
||||
return _binMessages.Count > 0 ? _binMessages[0] : null;
|
||||
}
|
||||
|
||||
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (_serialPort == null || !_serialPort.IsOpen) return;
|
||||
|
||||
try
|
||||
{
|
||||
Thread.Sleep(50);
|
||||
|
||||
SerialPortReadBuffer = new Collection<byte>();
|
||||
|
||||
while (_serialPort.BytesToRead > 0)
|
||||
{
|
||||
SerialPortReadBuffer.Add((byte)_serialPort.ReadByte());
|
||||
}
|
||||
|
||||
if (SerialPortReadBuffer.Count > 0)
|
||||
{
|
||||
_binMessages.Add(SerialPortReadBuffer.ToArray());
|
||||
_responseReceived.Set();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore shutdown race conditions
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isReading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] SendAndWait(byte[] data, int timeoutMs)
|
||||
{
|
||||
if (!IsOpen())
|
||||
throw new InvalidOperationException("Serial port not open");
|
||||
|
||||
PrepareReading();
|
||||
_serialPort.Write(data, 0, data.Length);
|
||||
|
||||
if (!_responseReceived.WaitOne(timeoutMs))
|
||||
{
|
||||
ErrorMessage = "COM error: response timeout";
|
||||
return null;
|
||||
}
|
||||
|
||||
return GetRawData();
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
CloseConnection();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using System.IO.Ports;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.iPerlASICReader.communication.Utils
|
||||
{
|
||||
public class SerialDriverBuilder
|
||||
{
|
||||
private string _portName;
|
||||
private int _baudRate = 9600;
|
||||
private int _dataBits = 8;
|
||||
private Parity _parity = Parity.None;
|
||||
private StopBits _stopBits = StopBits.One;
|
||||
private int _readTimeout = 1000;
|
||||
private int _writeTimeout = 1000;
|
||||
|
||||
public SerialDriverBuilder WithPort(string portName)
|
||||
{
|
||||
_portName = portName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SerialDriverBuilder WithBaudRate(int baudRate)
|
||||
{
|
||||
_baudRate = baudRate;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SerialDriverBuilder WithDataBits(int dataBits)
|
||||
{
|
||||
_dataBits = dataBits;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SerialDriverBuilder WithParity(Parity parity)
|
||||
{
|
||||
_parity = parity;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SerialDriverBuilder WithStopBits(StopBits stopBits)
|
||||
{
|
||||
_stopBits = stopBits;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SerialDriverBuilder WithTimeouts(int readTimeout, int writeTimeout)
|
||||
{
|
||||
_readTimeout = readTimeout;
|
||||
_writeTimeout = writeTimeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Build driver WITHOUT opening connection
|
||||
/// </summary>
|
||||
public SerialDriver Build()
|
||||
{
|
||||
return new SerialDriver(
|
||||
_portName,
|
||||
_baudRate,
|
||||
_dataBits,
|
||||
_parity,
|
||||
_stopBits,
|
||||
_readTimeout,
|
||||
_writeTimeout
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Build driver AND open connection
|
||||
/// </summary>
|
||||
public SerialDriver BuildAndConnect()
|
||||
{
|
||||
var driver = Build();
|
||||
if (!driver.Open())
|
||||
{
|
||||
throw new InvalidOperationException(driver.ErrorMessage);
|
||||
}
|
||||
return driver;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,7 @@ using System.Windows.Forms;
|
||||
using Common;
|
||||
using TBF.Rig.Generic;
|
||||
using TBF.Rig.RegisterReaders.CommonRR.IPerl.communication;
|
||||
using TBF.Rig.RegisterReaders.iPerlASICReader.communication;
|
||||
using TBF.Rig.RegisterReaders.iPerlReaderUNI.common;
|
||||
using TBF.Rig.RegisterReaders.iPerlReaderUNI.test;
|
||||
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
|
||||
@ -89,20 +90,21 @@ namespace TBF.Rig.RegisterReaders.iPerlASICReader.implementations
|
||||
{
|
||||
a.RfidOutputListBox.Items.Clear();
|
||||
|
||||
using (Tools.LogChecker logChecker = new Tools.LogChecker("RfidData", log4net.Core.Level.Debug))
|
||||
using (Tools.LogChecker logChecker = new Tools.LogChecker("ASIC_RfidData", log4net.Core.Level.Debug))
|
||||
{
|
||||
ListItem rfidListItem = new ListItem();
|
||||
rfidListItem.Attributes.Add("style", "font-weight:bold");
|
||||
Operations selectedOperation;
|
||||
if(!ItemsForIperlOperations.TryGetValue((string)a.RfidCommandComboBox.SelectedValue, out selectedOperation))
|
||||
selectedOperation = Operations.EmptyCmd;
|
||||
|
||||
switch (selectedOperation)
|
||||
{
|
||||
case Operations.ReadPcbCmd:
|
||||
rfidListItem.Text = $"PCB: {OpticalHeadTest.ReadRequest_PCB(a.ISmartReader)}";
|
||||
rfidListItem.Text = $"PCB: {OptoHeadTest.ReadRequest_PCB(a.ISmartReader)}";
|
||||
break;
|
||||
case Operations.SetTestModeCmd:
|
||||
rfidListItem.Text = OpticalHeadTest.SetTestMode(a.ISmartReader);
|
||||
rfidListItem.Text = OptoHeadTest.SetTestMode(a.ISmartReader);
|
||||
a.OptoListBox.Items.Clear();
|
||||
stopWorkerThread = false;
|
||||
optoThread = new Thread(OptoWorker);
|
||||
@ -114,7 +116,7 @@ namespace TBF.Rig.RegisterReaders.iPerlASICReader.implementations
|
||||
|
||||
break;
|
||||
case Operations.SetActiveModeCmd:
|
||||
rfidListItem.Text = OpticalHeadTest.SetActiveMode(a.ISmartReader);
|
||||
rfidListItem.Text = OptoHeadTest.SetActiveMode(a.ISmartReader);
|
||||
stopWorkerThread = true;
|
||||
a.ISmartReader.StopDataStreamProcessing(); // close opto port
|
||||
break;
|
||||
|
||||
@ -1279,6 +1279,11 @@
|
||||
<Compile Include="Rig\RegisterReaders\iPerlASICReader\communication\C4\TouchReadFrameParser.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\iPerlASICReader\communication\C4\TouchReadProtocol.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\iPerlASICReader\communication\C4\TouchReadResponse.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\iPerlASICReader\communication\OpthoHeadService.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\iPerlASICReader\communication\OptoHeadTest.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\iPerlASICReader\communication\RadioService.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\iPerlASICReader\communication\Utils\SerialDriverBuilder.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\iPerlASICReader\communication\Utils\SerialDriver.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\iPerlASICReader\Factory.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\iPerlASICReader\implementations\IPerlASICImplHeadTestCtrl.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\iPerlASICReader\implementations\SmartReader.cs" />
|
||||
|
||||
Loading…
Reference in New Issue
Block a user