Skip to main content

Working with Digital IO

This guide covers reading digital inputs, controlling digital outputs, monitoring for changes with events, and using latches and counters on ED-series devices.

Reading Digital Inputs​

Digital inputs read the state of external signals: HIGH (1) or LOW (0).

using Brainboxes.IO;

using (EDDevice ed = EDDevice.Create("192.168.0.100"))
{
// Read a single input
int state = ed.Inputs[0].Value;
Console.WriteLine($"Input 0 is {(state == 1 ? "HIGH" : "LOW")}");

// Read all inputs
for (int i = 0; i < ed.Inputs.Count; i++)
{
Console.WriteLine($"Input {i}: {ed.Inputs[i].Value}");
}
}

Value Caching​

IO values are cached for IOLineCacheTimeout milliseconds (default 250 ms). Reading any single input refreshes all digital inputs in one network call. This means iterating through all inputs is efficient — only one command is sent to the device.

You can adjust the cache timeout:

// Faster polling (more network traffic)
ed.IOLineCacheTimeout = 50;

// Slower polling (less network traffic)
ed.IOLineCacheTimeout = 500;

Controlling Digital Outputs​

Digital outputs control relays, LEDs, motors, or other actuators: CLOSED (1) or OPEN (0).

using (EDDevice ed = EDDevice.Create("192.168.0.100"))
{
// Set an output HIGH (closed)
ed.Outputs[0].Value = 1;

// Set an output LOW (open)
ed.Outputs[0].Value = 0;

// Toggle an output (returns the new value)
int newState = ed.Outputs[0].Toggle();
Console.WriteLine($"Output 0 is now {newState}");
}

Write Suppression​

If you set an output to its current cached value within the cache window, no command is sent to the device. This makes it safe to write values in a loop without generating unnecessary network traffic.

DIO, Digital Inputs and Digital Outputs​

Note on some devices like the ED-588, ED-527 and ED-516 individual lines are only either inputs or outputs e.g. DIN0 is Digital Input 0. Where as on other devices like ED-008 and BB-400 a single line can be an either an input or an output depending how it is wired to the outside world. e.g DIO 0 is Digital Input or Output 0. In the software simply refer to the line number in the correct context of either input or output e.g.

// Connect to a BB-400 or ED-008 or ED-588
using (EDDevice ed = EDDevice.Create("192.168.0.100"))
{
// For: BB-400 or ED-008 DIO 0 is used as a button input
// equivalent for ED-588 is to read DIN0
Console.WriteLine($"Button DIO 0 is {ed.Inputs[0].Value}");

// For: BB-400 or ED-008 DIO 1 is used as an LED output
// equivalent for ED-588 would be set DOUT1
ed.Outputs[1].Toggle();
Console.WriteLine($"LED Output DIO1 is now {ed.Outputs[1].Value}");

}

Setting All Outputs at Once​

You can set a group of outputs to the same value simultaneously using the IOList Values property of a collection:

// set all outputs high/ON
ed.Outputs.Values = 1;
// set the last 4 (out of 8) outputs low/OFF:
ed.Outputs.Skip(4).Values = 0;

You can set also set all outputs simultaneously using a raw command:

// Set all outputs using a bitmask via SendCommand
ed.SendCommand("@01001F"); // device-specific ASCII command

Event-Driven Monitoring​

Instead of polling in a loop, you can subscribe to events that fire when IO lines change state. Events are driven by the device's internal polling timer. The polling interval is controlled by IOLineCacheTimeout

Per-Line Events​

using (EDDevice ed = EDDevice.Create("192.168.0.100"))
{
// DIN0 Rising edge: input went from LOW (0) to HIGH (1)
ed.Inputs[0].IOLineRisingEdge += (line, device, changeType) =>
{
Console.WriteLine($"Input {line.IONumber} went HIGH");
};

// Falling edge: input went from HIGH (1) to LOW (0)
ed.Inputs[0].IOLineFallingEdge += (line, device, changeType) =>
{
Console.WriteLine($"Input {line.IONumber} went LOW");
};

// Any change on DIN 2 (rising, falling, or latched)
ed.Inputs[2].IOLineChanged += (line, device, changeType) =>
{
Console.WriteLine($"Input {line.IONumber}: {changeType}");
};

Console.WriteLine("Monitoring input 0... press any key to stop.");
Console.ReadKey();
}

Device-Level Events​

To monitor all IO lines at once, subscribe at the device level:

using (EDDevice ed = EDDevice.Create("192.168.0.100"))
{
ed.IOLineChanged += (line, device, changeType) =>
{
Console.WriteLine($"{line} changed: {changeType}");
};

ed.IOLineRisingEdge += (line, device, changeType) =>
{
Console.WriteLine($"{line} rising edge");
};

Console.ReadKey();
}

Change Types​

The IOChangeTypes enum describes what happened:

ValueMeaning
NoChangeNo state change detected
RisingEdgeLOW → HIGH (input) or OPEN → CLOSED (output)
FallingEdgeHIGH → LOW (input) or CLOSED → OPEN (output)
LatchedBoth rising and falling edges occurred within one polling interval
UndefinedInitial state (device just connected, no previous value)

The Latched state catches high-frequency changes that happen faster than the polling interval. For example, if an input goes HIGH then LOW between two polls, neither a simple rising nor falling edge would be detected, but the latch registers capture both transitions.

Latch Status​

Latch registers on the device record whether a transition has occurred since the last latch read. This is useful for detecting pulses that are shorter than the polling interval.

// Check if input 0 has gone HIGH since last check
bool wentHigh = ed.Inputs[0].HighLatchedStatus;

// Check if input 0 has gone LOW since last check
bool wentLow = ed.Inputs[0].LowLatchedStatus;

Latch values are also cached with the same IOLineCacheTimeout as regular values.

Counters​

Digital input lines have hardware counters that track the number of transitions:

// Read the current count
int count = ed.Inputs[0].Count;
Console.WriteLine($"Input 0 has transitioned {count} times");

// Reset the counter
ed.Inputs[0].ClearCount();

Counter Events​

You can subscribe to count change events:

ed.Inputs[0].IOLineCount += (line, device, changeType) =>
{
Console.WriteLine($"Input {line.IONumber} count changed: {line.Count}");
};

Counter Modes​

You can configure how counters operate:

ModeDescription
CounterMode16Bits16-bit counter (0 – 65,535)
CounterMode32Bits32-bit counter (0 – 4,294,967,295)

Device Status Monitoring​

Monitor the device connection status (e.g. connected or disconnected) and availability (e.g. online or offline):

using (EDDevice ed = EDDevice.Create("192.168.0.100"))
{
ed.DeviceStatusChangedEvent += (device, property, newValue) =>
{
Console.WriteLine($"{property} changed to {newValue}");

if (!device.IsConnected && device.IsAvailable)
{
Console.WriteLine("Reconnecting...");
device.Connect();
}
};

Console.ReadKey();
}

Labels​

You can assign labels to IO lines for easier debugging:

ed.Inputs[0].Label = "Door sensor";
ed.Outputs[0].Label = "Alarm LED";

// Labels appear in ToString() and Describe()
Console.WriteLine(ed.Inputs[0]); // "Door sensor DIn00 (line 00)"
Console.WriteLine(ed.Inputs[0].Describe()); // Full diagnostic output