====== CFHEADER Mode of Operation ======
The CFHEADER serves as a USB device interface between a host PC and the CFNET IO modules.
{{ :cfnet:cfheader:mode_of_operation:cfnet_cfheader_io_modules_comm.png?900 }}
The host PC communicates with the CFHEADER module over USB while the CFHEADER module communicates with each CFNET IO module over I²C.
===== Normal Mode of Operation =====
- The program running on the host PC updates the state of the output modules by writing to properties such as [[https://api.comfiletech.com/csharp/api/ComfileTech.Cfnet.Cfheader.DigitalOutputModule.Channel.State.html#ComfileTech_Cfnet_Cfheader_DigitalOutputModule_Channel_State|DigitalOutputModule.Channel.State]].
- When the [[https://api.comfiletech.com/csharp/api/ComfileTech.Cfnet.Cfheader.Cfheader.Sync.html#ComfileTech_Cfnet_Cfheader_Cfheader_Sync|Cfheader.Sync()]] function is called:
- The host PC transmits the updated state of the CFNET output modules to the CFHEADER's memory over USB.
- The CFHEADER module writes the updated state to the CFNET output modules via I²C.
- The CFHEADER module reads the state of the CFNET input modules via I²C.
- The CFHEADER module transmits the updated state of the CFNET input modules to the host PC over USB.
- The host PC updates the state of the CFNET input modules in the host PC's memory by writing to properties such as [[https://api.comfiletech.com/csharp/api/ComfileTech.Cfnet.Cfheader.DigitalInputModule.Channel.State.html#ComfileTech_Cfnet_Cfheader_DigitalInputModule_Channel_State|DigitalInputModule.Channel.State]].
- The program, running on the host, processes the updated state of the CFNET input modules as read from the CFHEADER module.
That procedure can be visualized in source code form in the following program.
using ComfileTech.Cfnet.Cfheader;
// Get CFHEADER module at address 0
var cfheader0 = Cfheader.Instances[0];
// Get digital output module at address 0
var do0= cfheader0.DigitalOutputModules[0];
// Get digital input module at address 0
var di0= cfheader0.DigitalInputModules[0];
// Open USB communication with the CFHEADER module
cfheader0.Open();
while (true)
{
// Update the state of the digital output modules
foreach(var doChannel in do0.Channels)
{
doChannel.State = true;
}
// Write the updated state of the output modules to the CFHEADER module, and
// read the updated state of the input modules from the CFHEADER module
cfheader0.Sync();
// Process the new state of the digital input modules
foreach(var diChannel in di0.Channels)
{
// Process the digital input channel's state
Console.WriteLine(diChannel.State);
}
}
==== Calling `Sync` Asynchronously With `BackgroundSync` ====
Calling [[https://api.comfiletech.com/csharp/api/ComfileTech.Cfnet.Cfheader.Cfheader.Sync.html#ComfileTech_Cfnet_Cfheader_Cfheader_Sync|Sync()]] synchronously on the main thread may be straightforward for a console application, but for a graphical user interface, it may be best to call [[https://api.comfiletech.com/csharp/api/ComfileTech.Cfnet.Cfheader.Cfheader.Sync.html#ComfileTech_Cfnet_Cfheader_Cfheader_Sync|Sync()]] asynchronously in the background.
Use the [[https://api.comfiletech.com/csharp/api/ComfileTech.Cfnet.Cfheader.BackgroundSync.html|BackgroundSync]] class to call [[https://api.comfiletech.com/csharp/api/ComfileTech.Cfnet.Cfheader.Cfheader.Sync.html#ComfileTech_Cfnet_Cfheader_Cfheader_Sync|Sync()]] asynchronously and repeatedly in a background thread.
using ComfileTech.Cfnet.Cfheader;
// Get CFHEADER module at address 0
var cfheader0 = Cfheader.Instances[0];
// Get digital output module at address 0
var do0 = cfheader0.DigitalOutputModules[0];
// Get digital input module at address 0
var di0 = cfheader0.DigitalInputModules[0];
// Open USB communication with the CFHEADER module
cfheader0.Open();
// Start the background sync thread
cfheader0.BackgroundSync.Start();
while (true)
{
// Update the state of the digital output modules
foreach(var doChannel in do0.Channels)
{
doChannel.State = true;
}
// Process the new state of the digital input modules
foreach(var diChannel in di0.Channels)
{
// Process the digital input channel's state
Console.WriteLine(diChannel.State);
}
}
Use polling in a timer, or subscribe to [[https://api.comfiletech.com/csharp/api/ComfileTech.Cfnet.Cfheader.BackgroundSync.html|BackgroundSync]]'s, IO modules', and channels' events (e.g. [[https://api.comfiletech.com/csharp/api/ComfileTech.Cfnet.Cfheader.BackgroundSync.Synced.html|Synced]], [[https://api.comfiletech.com/csharp/api/ComfileTech.Cfnet.Cfheader.DigitalInputModule.Channel.StateChanged.html|StateChanged]], [[https://api.comfiletech.com/csharp/api/ComfileTech.Cfnet.Cfheader.AnalogInputModule.Channel.ConversionCompleted.html|ConversionCompleted]], etc.) to respond to state changes. Be aware that the events fired from [[https://api.comfiletech.com/csharp/api/ComfileTech.Cfnet.Cfheader.BackgroundSync.html|BackgroundSync]] will be in the context of the background thread, so it may be necessary to use techniques such as [[https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.control.begininvoke?view=windowsdesktop-9.0|BeginInvoke]] and [[https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.components.componentbase.invokeasync?view=aspnetcore-9.0|InvokeAsync]] to update a UI on the main UI thread.
===== Error Handling =====
To program a robust IO solution, all sources of errors must be handled. For the CFHEADER, there 2 primary sources for potential errors.
- USB communication errors
- I²C communication errors
==== Handling USB Communication Errors ====
USB communications errors can occur in either the [[https://api.comfiletech.com/csharp/api/ComfileTech.Cfnet.Cfheader.Cfheader.Open.html#ComfileTech_Cfnet_Cfheader_Cfheader_Open|Cfheader.Open()]] method or the [[https://api.comfiletech.com/csharp/api/ComfileTech.Cfnet.Cfheader.Cfheader.Sync.html|Cfheader.Sync()]] method. To handle any errors that may occur in those methods, simply wrap them in a ''try...catch'' block, and handle any exceptions that occur in the ''catch'' block.
using ComfileTech.Cfnet.Cfheader;
// Open USB communication with the CFHEADER module
try
{
cfheader0.Open();
}
catch (Exception ex)
{
// Handle any USB communication errors that occur here.
}
while (true)
{
// Write the updated state of the output modules to the CFHEADER module, and
// read the updated state of the input modules from the CFHEADER module
try
{
cfheader0.Sync();
}
catch (Exception ex)
{
// Handle any USB communication errors that occur here.
}
}
For any error that occurs when calling [[https://api.comfiletech.com/csharp/api/ComfileTech.Cfnet.Cfheader.Cfheader.Sync.html|Sync()]], it may be necessary to [[https://api.comfiletech.com/csharp/api/ComfileTech.Cfnet.Cfheader.Cfheader.Close.html|Close()]] and [[https://api.comfiletech.com/csharp/api/ComfileTech.Cfnet.Cfheader.Cfheader.Open.html#ComfileTech_Cfnet_Cfheader_Cfheader_Open|Open()]] the CFHEADER module again to recover.
=== Handling USB Communication Errors From `BackgroundSync` ===
If using [[https://api.comfiletech.com/csharp/api/ComfileTech.Cfnet.Cfheader.BackgroundSync.html|BackgroundSync]], subscribe to the [[https://api.comfiletech.com/csharp/api/ComfileTech.Cfnet.Cfheader.BackgroundSync.ExceptionThrown.html|BackgroundSync.ExceptionThrown]] event to capture any errors that occur when the background thread calls [[https://api.comfiletech.com/csharp/api/ComfileTech.Cfnet.Cfheader.Cfheader.Sync.html|Cfheader.Sync()]].
using ComfileTech.Cfnet.Cfheader;
// Open USB communication with the CFHEADER module
try
{
cfheader0.Open();
}
catch (Exception ex)
{
// Handle any USB communication errors that occur here.
}
// Capture any errors that occur when calling `Sync` in the background thread.
cfheader0.BackgroundSync.ExceptionThrown += (bs, ex) =>
{
Console.Error.WriteLine($"Exception was through from `BackgroundSync`: {ex.Message}");
}
// Start the background sync thread
cfheader0.BackgroundSync.Start();
while (true)
{
Thread.Yield();
}
For any error that occurs, it may be necessary to [[https://api.comfiletech.com/csharp/api/ComfileTech.Cfnet.Cfheader.Cfheader.Close.html|Close()]] and [[https://api.comfiletech.com/csharp/api/ComfileTech.Cfnet.Cfheader.Cfheader.Open.html#ComfileTech_Cfnet_Cfheader_Cfheader_Open|Open()]] the CFHEADER module again to recover.
==== Handling I²C Communication Errors ====
If the CFHEADER module encounters an error while communicating with CFNET IO module over I²C, then the error will be reported in the [[https://api.comfiletech.com/csharp/api/ComfileTech.Cfnet.Cfheader.IIOModule.I2cStatus.html#ComfileTech_Cfnet_Cfheader_IIOModule_I2cStatus|IIOModule.I2cStatus]] property after the [[https://api.comfiletech.com/csharp/api/ComfileTech.Cfnet.Cfheader.Cfheader.Sync.html|Sync()]] method returns.
If such an error occurs, the CFHEADER module will no longer attempt to communicate with the CFNET IO module until the [[https://api.comfiletech.com/csharp/api/ComfileTech.Cfnet.Cfheader.IIOModule.AcknowledgeI2cFailure.html|IIOModule.AcknowledgeI2cFailure()]] method is called to acknowledge the error. After acknowledging the error, the CFHEADER module will attempt to communicate with the CFNET IO module again in the next call to [[https://api.comfiletech.com/csharp/api/ComfileTech.Cfnet.Cfheader.Cfheader.Sync.html|Sync()]].
while (true)
{
// Write the updated state of the output modules to the CFHEADER module, and
// read the updated state of the input modules from the CFHEADER module
cfheader0.Sync();
if (do0.I2cStatus != I2cStatus.Success)
{
// Handle the I²C communication failure
Console.Error.WriteLine($"I²C communication with the digital output module at address {do0.Address} failed.");
// Acknowledge the I²C communication failure
do0.AcknowledgeI2cFailure();
}
}
=== Handling I²C Communication Errors If Using `BackgroundSync` ===
If using [[https://api.comfiletech.com/csharp/api/ComfileTech.Cfnet.Cfheader.BackgroundSync.html|BackgroundSync]], subscribe the the IO module's [[https://api.comfiletech.com/csharp/api/ComfileTech.Cfnet.Cfheader.IIOModule.I2cFailed.html|I2cFailed]] event to capture any I²C communication errors that occur with that module.
do0.I2cFailed += module =>
{
Console.WriteLine($"I²C communication with digital output module at address {module.Address} failed.");
}
[[..:index|CFHEADER - USB Interface to CFNET IO Modules]]