Refactor; moving closer to C# coding style

Signed-off-by: mharb <mharb@noreply.localhost>
This commit is contained in:
mharb 2025-07-05 20:22:53 -04:00
parent ebcb560ef4
commit 534d72f79b

View File

@ -1,206 +1,206 @@
using Modbus.Device; // NModbus namespace using Modbus.Device; // NModbus namespace for Modbus communication
using System.IO.Ports; using System.IO.Ports; // Namespace for serial port communication
using static System.Console; using static System.Console; // Static reference to Console for easier access
internal class Program internal class Program
{ {
// Registers // Modbus Register Addresses for various parameters
private const ushort READINPUT1 = 100; private static class ModbusRegisters
private const ushort INPUT1ERROR = 101; {
private const ushort ALARM1STATUS = 102; public const ushort ReadInput1 = 100; // Register for reading input 1
private const ushort ALARM2STATUS = 106; public const ushort Input1Error = 101; // Register for input 1 error status
private const ushort ANALOGINPUT1DECIMAL = 606; public const ushort Alarm1Status = 102; // Register for alarm 1 status
private const ushort POWEROUTPUT1A = 103; public const ushort Alarm2Status = 106; // Register for alarm 2 status
private const ushort SETPOINT1 = 300; public const ushort AnalogInput1Decimal = 606; // Register for analog input 1 decimal setting
private const ushort CURRENTDAY = 1920; public const ushort PowerOutput1A = 103; // Register for power output 1A
private const ushort CURRENTMONTH = 1919; public const ushort SetPoint1 = 300; // Register for set point 1
private const ushort CURRENTYEAR = 1921; public const ushort CurrentDay = 1920; // Register for current day
private const ushort CURRENTHOUR = 1916; public const ushort CurrentMonth = 1919; // Register for current month
private const ushort CURRENTMINUTE = 1917; public const ushort CurrentYear = 1921; // Register for current year
private const ushort CURRENTSECOND = 1918; public const ushort CurrentHour = 1916; // Register for current hour
private const ushort OUTPUT1AFUNCTION = 700; public const ushort CurrentMinute = 1917; // Register for current minute
private const ushort OUTPUT1ACYCLETIMETYPE = 509; public const ushort CurrentSecond = 1918; // Register for current second
private const ushort OUTPUT1ACYCLETIME = 506; public const ushort Output1AFunction = 700; // Register for output 1A function
private const ushort DIGITALINPUT1FUNCTION = 1060; public const ushort Output1ACycleTimeType = 509; // Register for output 1A cycle time type
private const ushort DIGITALINPUT1CONDITION = 1061; public const ushort Output1ACycleTime = 506; // Register for output 1A cycle time
private const ushort DIGITALINPUT1STATUS = 201; public const ushort DigitalInput1Function = 1060; // Register for digital input 1 function
private const ushort POWEROUTACTION = 1206; public const ushort DigitalInput1Condition = 1061; // Register for digital input 1 condition
private const ushort POWEROUTTIME = 1213; public const ushort DigitalInput1Status = 201; // Register for digital input 1 status
private const ushort ANALOGINPUTUNITS = 608; public const ushort PowerOutAction = 1206; // Register for power output action
private const ushort CONTROLOUTPUTTYPE = 701; public const ushort PowerOutTime = 1213; // Register for power output time
private const ushort ANALOGINPUT1SENSORTYPE = 601; public const ushort AnalogInputUnits = 608; // Register for analog input units
private const ushort ANALOGINPUT1SENSOR = 600; public const ushort ControlOutputType = 701; // Register for control output type
private const ushort ANALOGINPUT1SETPOINTHIGHLIMIT = 603; public const ushort AnalogInput1SensorType = 601; // Register for analog input 1 sensor type
private const ushort ANALOGINPUT1SETPOINTLOWLIMIT = 602; public const ushort AnalogInput1Sensor = 600; // Register for analog input 1 sensor
private const ushort TEMPSCALEDISPLAY = 1923; public const ushort AnalogInput1SetPointHighLimit = 603; // Register for high limit of analog input 1 set point
private const ushort TEMPSCALE = 901; public const ushort AnalogInput1SetPointLowLimit = 602; // Register for low limit of analog input 1 set point
private const ushort ANALOGOUTPUT1ATYPE = 701; public const ushort TempScaleDisplay = 1923; // Register for temperature scale display
private const ushort PROPORTIONALBAND = 500; public const ushort TempScale = 901; // Register for temperature scale
public const ushort AnalogOutput1AType = 701; // Register for analog output 1A type
public const ushort ProportionalBand = 500; // Register for proportional band
}
// Configuration // Configuration for Modbus Slave ID
private const byte slaveID = 1; private const byte SlaveID = 1;
private static void Main(string[] args) private static void Main(string[] args)
{ {
ushort[] registers;
// Initialize the F4
SerialPort serialPort = (SerialPort)InitializeModbusSerialPort();
ModbusSerialMaster master = (ModbusSerialMaster)InitializeModbusMaster(serialPort);
// Then, run it
try try
{ {
// Monitor continuously using SerialPort serialPort = InitializeSerialPort();
while (true) using ModbusSerialMaster master = InitializeModbusMaster(serialPort);
{
// Check for escape key press
if (KeyAvailable)
{
ConsoleKeyInfo key = ReadKey(true);
if (key.Key == ConsoleKey.Escape)
{
WriteLine("<ESC> pressed. Exiting...");
break;
}
}
// Display current process values MonitorProcessValues(master);
try
{
registers = master.ReadInputRegisters(slaveID, INPUT1ERROR, 1);
if (registers[0] != 0)
{
WriteLine("Failure in the temperature input channel; program ends here...\n");
return;
};
registers = master.ReadInputRegisters(slaveID, READINPUT1, 1);
Write("temperature is {0:F1}; ", registers[0] / 10.0);
registers = master.ReadInputRegisters(slaveID, POWEROUTPUT1A, 1);
Write("power output is {0:F2}%\n", registers[0] / 100.0);
// Pause before next read
Thread.Sleep(750);
}
catch (Exception ex)
{
WriteLine($"Error: {ex.Message}");
break;
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {
WriteLine($"Initialization error: {ex.Message}"); WriteLine($"Initialization error: {ex.Message}");
} }
finally
{
// Shut off the output
master?.WriteSingleRegister(slaveID, SETPOINT1, 0);
// Clean up
master?.Dispose();
serialPort?.Close();
} }
static object InitializeModbusSerialPort() private static void MonitorProcessValues(ModbusSerialMaster master)
{ {
SerialPort serialPort; while (true)
{
if (KeyAvailable && ReadKey(true).Key == ConsoleKey.Escape)
{
WriteLine("<ESC> pressed. Exiting...");
break;
}
serialPort = new SerialPort try
{ {
PortName = "COM1", if (IsInputError(master))
BaudRate = 19200, {
DataBits = 8, WriteLine("Failure in the temperature input channel; program ends here...\n");
Parity = Parity.None, return; // Exit if there's an error
StopBits = StopBits.One, }
ReadTimeout = 1000
DisplayCurrentValues(master);
Thread.Sleep(750); // Wait before the next read
}
catch (Exception ex)
{
WriteLine($"Error: {ex.Message}");
break; // Exit on error
}
}
}
private static bool IsInputError(ModbusSerialMaster master)
{
ushort[] registers = master.ReadInputRegisters(SlaveID, ModbusRegisters.Input1Error, 1);
return registers[0] != 0; // Non-zero indicates an error
}
private static void DisplayCurrentValues(ModbusSerialMaster master)
{
ushort[] temperatureRegisters = master.ReadInputRegisters(SlaveID, ModbusRegisters.ReadInput1, 1);
Write("Temperature is {0:F1}; ", temperatureRegisters[0] / 10.0); // Convert to proper format
ushort[] powerOutputRegisters = master.ReadInputRegisters(SlaveID, ModbusRegisters.PowerOutput1A, 1);
WriteLine("Power output is {0:F2}%", powerOutputRegisters[0] / 100.0); // Convert to percentage
}
private static SerialPort InitializeSerialPort()
{
SerialPort serialPort = new SerialPort
{
PortName = "COM1", // Set the COM port
BaudRate = 19200, // Set the baud rate
DataBits = 8, // Set data bits
Parity = Parity.None, // Set parity
StopBits = StopBits.One, // Set stop bits
ReadTimeout = 1000 // Set read timeout
}; };
serialPort.Open(); serialPort.Open(); // Open the serial port
return serialPort; return serialPort; // Return the configured serial port
} }
static object InitializeModbusMaster(SerialPort serialPort) private static ModbusSerialMaster InitializeModbusMaster(SerialPort serialPort)
{ {
ushort[] registers; ModbusSerialMaster master = ModbusSerialMaster.CreateRtu(serialPort);
ushort setPoint = 1000; ConfigureModbusSettings(master); // Configure Modbus settings
ModbusSerialMaster master; return master; // Return the Modbus master
DateTime dateTime;
master = ModbusSerialMaster.CreateRtu(serialPort);
// Set sensor type
WriteLine("Set sensor type to 100 Ω DIN platinum RTD");
master.WriteSingleRegister(slaveID, ANALOGINPUT1SENSOR, 1);
master.WriteSingleRegister(slaveID, ANALOGINPUT1SENSORTYPE, 11);
// Set to one decimal place (this cannot be the first initialization instruction)
WriteLine("Set to one decimal place on display");
master.WriteSingleRegister(slaveID, ANALOGINPUT1DECIMAL, 1);
// Display current setpoint high and low limits
registers = master.ReadInputRegisters(slaveID, ANALOGINPUT1SETPOINTLOWLIMIT, 1);
WriteLine("Setpoint low limit is {0}", registers[0]);
registers = master.ReadInputRegisters(slaveID, ANALOGINPUT1SETPOINTHIGHLIMIT, 1);
WriteLine("Setpoint high limit is {0}", registers[0]);
// Set to proportional mode
WriteLine("Make proportional band 5°F");
master.WriteSingleRegister(slaveID, PROPORTIONALBAND, 5);
// Set output function to heating
WriteLine("Output function is heating");
master.WriteSingleRegister(slaveID, OUTPUT1AFUNCTION, 1);
// Set analog output1 to 4-20 ma
WriteLine("Set the analog output to 4-20 MA");
master.WriteSingleRegister(slaveID, ANALOGOUTPUT1ATYPE, 0);
// Set analog input parameter to temperature
master.WriteSingleRegister(slaveID, ANALOGINPUTUNITS, 0);
// Set temperature SCALE to ON
master.WriteSingleRegister(slaveID, TEMPSCALEDISPLAY, 1);
// Set temperature scale type to Fahrenheit
master.WriteSingleRegister(slaveID, TEMPSCALE, 0);
// Set power failure response
master.WriteSingleRegister(slaveID, POWEROUTACTION, 2);
// Set output1 cycle time type to variable burst
master.WriteSingleRegister(slaveID, OUTPUT1ACYCLETIMETYPE, 0);
// Read current output1 cycle time
registers = master.ReadInputRegisters(slaveID, OUTPUT1ACYCLETIME, 1);
WriteLine("Output cycle time is {0}", registers[0]);
// Set output1 cycle time to new value
master.WriteSingleRegister(slaveID, OUTPUT1ACYCLETIME, 500);
// Check new value
registers = master.ReadInputRegisters(slaveID, OUTPUT1ACYCLETIME, 1);
WriteLine("Output cycle time is now {0}", registers[0]);
// Write setpoint to F4
WriteLine("Setting the process variable setpoint");
master.WriteSingleRegister(slaveID, SETPOINT1, setPoint);
// Verify setpoint value
WriteLine("Verifying the setpoint value");
registers = master.ReadInputRegisters(slaveID, SETPOINT1, 1);
WriteLine("Setpoint is {0:F1}", registers[0] / 10.0);
// Set F4 clock to current date and time
dateTime = DateTime.Now;
master.WriteSingleRegister(slaveID, CURRENTDAY, (ushort)dateTime.Day);
master.WriteSingleRegister(slaveID, CURRENTMONTH, (ushort)dateTime.Month);
master.WriteSingleRegister(slaveID, CURRENTYEAR, (ushort)dateTime.Year);
master.WriteSingleRegister(slaveID, CURRENTHOUR, (ushort)dateTime.Hour);
master.WriteSingleRegister(slaveID, CURRENTMINUTE, (ushort)dateTime.Minute);
master.WriteSingleRegister(slaveID, CURRENTSECOND, (ushort)dateTime.Second);
WriteLine("Set F4 clock to {0} {1}", dateTime.ToLongTimeString(), dateTime.ToLongDateString());
return master;
} }
private static void ConfigureModbusSettings(ModbusSerialMaster master)
{
WriteLine("Configuring Modbus settings...");
// Set sensor type and configuration
master.WriteSingleRegister(SlaveID, ModbusRegisters.AnalogInput1Sensor, 1);
master.WriteSingleRegister(SlaveID, ModbusRegisters.AnalogInput1SensorType, 11);
master.WriteSingleRegister(SlaveID, ModbusRegisters.AnalogInput1Decimal, 1);
// Set limits and modes for the Modbus device
SetSetPointLimits(master);
SetOutputFunction(master);
SetAnalogOutput(master);
SetTemperatureScale(master);
SetPowerFailureResponse(master);
SetOutputCycleTime(master);
SetCurrentDateTime(master);
}
private static void SetSetPointLimits(ModbusSerialMaster master)
{
ushort[] lowLimitRegisters = master.ReadInputRegisters(SlaveID, ModbusRegisters.AnalogInput1SetPointLowLimit, 1);
WriteLine("Setpoint low limit is {0}", lowLimitRegisters[0]);
ushort[] highLimitRegisters = master.ReadInputRegisters(SlaveID, ModbusRegisters.AnalogInput1SetPointHighLimit, 1);
WriteLine("Setpoint high limit is {0}", highLimitRegisters[0]);
master.WriteSingleRegister(SlaveID, ModbusRegisters.ProportionalBand, 5);
master.WriteSingleRegister(SlaveID, ModbusRegisters.SetPoint1, 1000);
}
private static void SetOutputFunction(ModbusSerialMaster master)
{
master.WriteSingleRegister(SlaveID, ModbusRegisters.Output1AFunction, 1);
}
private static void SetAnalogOutput(ModbusSerialMaster master)
{
master.WriteSingleRegister(SlaveID, ModbusRegisters.AnalogOutput1AType, 0);
}
private static void SetTemperatureScale(ModbusSerialMaster master)
{
master.WriteSingleRegister(SlaveID, ModbusRegisters.AnalogInputUnits, 0);
master.WriteSingleRegister(SlaveID, ModbusRegisters.TempScaleDisplay, 1);
master.WriteSingleRegister(SlaveID, ModbusRegisters.TempScale, 0);
}
private static void SetPowerFailureResponse(ModbusSerialMaster master)
{
master.WriteSingleRegister(SlaveID, ModbusRegisters.PowerOutAction, 2);
}
private static void SetOutputCycleTime(ModbusSerialMaster master)
{
master.WriteSingleRegister(SlaveID, ModbusRegisters.Output1ACycleTimeType, 0);
ushort[] cycleTimeRegisters = master.ReadInputRegisters(SlaveID, ModbusRegisters.Output1ACycleTime, 1);
WriteLine("Output cycle time is {0}", cycleTimeRegisters[0]); // Display current cycle time
master.WriteSingleRegister(SlaveID, ModbusRegisters.Output1ACycleTime, 500); // Set new cycle time
cycleTimeRegisters = master.ReadInputRegisters(SlaveID, ModbusRegisters.Output1ACycleTime, 1);
WriteLine("Output cycle time is now {0}", cycleTimeRegisters[0]); // Confirm new cycle time
}
private static void SetCurrentDateTime(ModbusSerialMaster master)
{
DateTime currentDateTime = DateTime.Now;
master.WriteSingleRegister(SlaveID, ModbusRegisters.CurrentDay, (ushort)currentDateTime.Day);
master.WriteSingleRegister(SlaveID, ModbusRegisters.CurrentMonth, (ushort)currentDateTime.Month);
master.WriteSingleRegister(SlaveID, ModbusRegisters.CurrentYear, (ushort)currentDateTime.Year);
master.WriteSingleRegister(SlaveID, ModbusRegisters.CurrentHour, (ushort)currentDateTime.Hour);
master.WriteSingleRegister(SlaveID, ModbusRegisters.CurrentMinute, (ushort)currentDateTime.Minute);
master.WriteSingleRegister(SlaveID, ModbusRegisters.CurrentSecond, (ushort)currentDateTime.Second);
WriteLine("Set F4 clock to {0} {1}", currentDateTime.ToLongTimeString(), currentDateTime.ToLongDateString()); // Display confirmation
} }
} }