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