Relay (RY) Family Guide

Overview

The RY family is NAI’s line of mechanical relay smart function modules. Each channel is a real electromechanical relay — a set of metal contacts that physically open and close under software command — so a RY module lets your application switch and route actual electrical signals: connect or disconnect a circuit, steer a signal down one of two paths, or switch a load on and off, all with the full galvanic isolation that only mechanical contacts provide. Because the contacts are physical metal, they can carry far more than a logic-level signal: up to 220 VDC / 250 VAC at 2 A (cumulative switching power 60 W / 62.5 VA per channel), AC or DC, analog or digital.

This page is the starting point for any RY module. Use it to understand the family, pick between the non-latching (RY1) and latching (RY2) members, wire a channel’s contacts, and confirm the module is switching correctly. It’s aimed at engineers who need to route or switch real electrical signals under program control — not just read or drive logic levels.

Each channel is a single-pole Form-C (DPDT, changeover / break-before-make) relay with three terminals: a Common (C), a Normally Closed (N/C), and a Normally Open (N/O). The signal on Common is always connected to one of the two outputs — N/C when the channel is de-energized (“reset”/open), N/O when energized (“set”/closed) — and the relay breaks the old path before making the new one, so the two outputs are never tied together.

In a real system, a RY module is most often used to:

  • Route a signal down one of two paths — Common is wired to a source and N/C and N/O to two destinations; commanding the channel steers the source to one destination or the other (a software-controlled SPDT switch / 1-of-2 multiplexer).
  • Switch a load or circuit on and off — connect a load across Common and N/O and the load is powered only when the channel is energized; lamps, solenoids, contactors, heaters, and similar loads within the contact rating.
  • Provide power-on-safe / fail-safe default states — a non-latching channel always comes up (and reverts on power loss) to a known de-energized position, so a circuit defaults to a safe state; a latching channel instead holds its last position through a power loss.
  • Select between redundant units or channels — switch a bus, antenna, or instrument between a primary and a backup (A/B failover) under software control.
  • Build automated test-stand / ATE signal routing — connect instruments to a unit-under-test’s pins on demand, with each relay isolating the paths it isn’t using.
  • Isolate circuits galvanically — because the contacts are mechanical, the control side and the switched side share no electrical connection, which solid-state switches cannot match.

RY is the mechanical-relay member of NAI’s discrete/switching I/O families. The other three switch solid-state — faster, no moving parts, but no galvanic isolation and limited to lower voltages: the DT family handles field-level single-ended discrete I/O, the TL family logic-level TTL/CMOS I/O, and the DF family differential (RS-422/485) signaling. A relay is the right choice when you need true mechanical isolation, or must switch AC, higher voltages, or analog signals that a transistor switch can’t carry.

RY modules at a glance

Both members are 4-channel, Gen5, Form-C relay modules with identical contacts, ratings, and software interface. They differ in exactly one way: what happens to the contacts when power is removed.

ModuleRelay typeChannelsContact formMax switchingBackground BITManual
RY1Non-latching4Single-pole Form-C (DPDT, changeover)220 VDC / 250 VAC @ 2 A; 60 W / 62.5 VA per channelYesRY1-RY2 Manual
RY2Latching4Single-pole Form-C (DPDT, changeover)220 VDC / 250 VAC @ 2 A; 60 W / 62.5 VA per channelYesRY1-RY2 Manual

Note

Each channel is physically a double-pole Form-C relay, but only one pole carries your signal. The second pole is dedicated to Built-In-Test — it reads back the relay’s actual contact position so the module can continuously compare commanded state against real position (see Confirm communication and Features). Confirm the exact contact ratings and timing for your part on the RY1-RY2 data sheet and in the RY1-RY2 Manual.

Choosing a member:

  • Pick by power-loss behavior — that’s the only functional difference. Choose RY1 (non-latching) when you want every channel to return to a known de-energized state on power loss (fail-safe defaults). Choose RY2 (latching) when a channel’s position must survive a power loss or power cycle, or when you want to avoid holding coil current to maintain a state.
  • Everything else is identical — both have four independent Form-C channels, the same contact ratings, the same continuous background BIT, and the same naibrd_RLY_* software interface. Code written for one runs unchanged on the other.
  • The module reports its own type at runtime. naibrd_RLY_GetRelayType returns NAIBRD_RLY_NONLATCHING or NAIBRD_RLY_LATCHING, so an application can adapt without being told which board it’s on.

Note

NAI’s pre-Gen5 relay modules — KN (non-latching) and KL (latching) — are still recognized by the library (module IDs NAIBRD_MODULE_ID_KN / _KL) for legacy systems, but RY1 / RY2 are the current Gen5 parts and what this guide covers. The Gen5 modules add the real-time (dynamic) BIT status register alongside the latched one; the legacy KN/KL provide only the latched register.

No combination module carries relay I/O. Relay channels are available only as the dedicated RY1 / RY2 modules — the multi-function combination modules (CM-series) don’t include a relay function. If you need relays alongside other I/O, add a RY module to the system.

Latching vs. non-latching — how they relate

RY1 and RY2 are the same module with two different relay mechanisms. The table below lays out how they differ; neither is “better” — they suit different power and safety requirements.

RY1 — non-latchingRY2 — latching
Holding mechanismCoil is energized to hold the “set” (closed) positionMagnetic latch holds the last position with no coil current
On power lossReverts to reset (de-energized: COM↔N/C)Holds the last commanded position
On power-upComes up reset (de-energized / open)Comes up in whatever position it was latched in
Holding powerDraws coil current the whole time a channel is “set”Draws current only during the set/reset transition
Typical fitFail-safe defaults — you want a known de-energized state on power lossState must persist across power cycles or loss; lower holding power
Command & readbackSetRelayState / GetRelayState / GetRelayPositionidenticalidentical
Reported byGetRelayTypeNAIBRD_RLY_NONLATCHINGGetRelayTypeNAIBRD_RLY_LATCHING

The key idea: “set” / “reset” and “closed” / “open” describe the same two contact positions — energized (COM connected to N/O, the N/O contact closed) versus de-energized (COM connected to N/C, the N/O contact open). RY1 and RY2 switch between those positions with the exact same commands. What changes is only whether the position is held by the coil (RY1, lost on power-down) or held by a magnetic latch (RY2, retained on power-down).

Physical setup

A RY channel is a set of mechanical contacts you wire into your own circuit — there’s no “signal level” to match, just contacts that open and close. Each of the four channels brings out three terminals: Common (C), Normally Closed (N/C), and Normally Open (N/O). The relay connects C to exactly one of the other two at any instant. The exact pins are per-module, so always get them from the module’s manual or overlay card; the pattern is the same for every RY module:

  1. Identify the module’s slot number on your NAI motherboard or system.
  2. Bring the channel’s lines out through the breakout board, where the slot’s pins appear as generic IO# numbers.
  3. Map the IO# pins to the channel’s C, N/C, and N/O terminals per the pinout in the manual.
  4. Wire your signal or load to those terminals (see the examples below).

A few things hold for every RY module:

  • The two contact positions. De-energized (“reset” / open, NAIBRD_RLY_STATE_OPEN): C↔N/C are connected and C↔N/O is open. Energized (“set” / closed, NAIBRD_RLY_STATE_CLOSE): C↔N/O are connected and C↔N/C is open. The contact is always tied to one side or the other.
  • Break-before-make. On a changeover the relay disconnects the old contact before connecting the new one, so N/C and N/O are never momentarily bridged through C. There is a brief instant during transfer when C is connected to neither — design for that gap if your circuit can’t tolerate an open moment.
  • Respect the contact rating. Each channel switches up to 220 VDC / 250 VAC at 2 A, with a cumulative maximum switching power of 60 W / 62.5 VA per channel. Stay within both the voltage/current and the power limit. For inductive loads (relay coils, solenoids, motors), add appropriate flyback/snubber protection — mechanical contacts can arc when breaking inductive current, which shortens contact life.
  • The BIT pole is internal — you don’t wire it. Each channel is physically double-pole, but only the C/N/C/N/O pole above is yours. The second pole is used internally to read the relay’s actual position for Built-In-Test; there’s nothing to connect.
  • De-bounce is built in. Internal de-bounce circuits remove the contact-bounce chatter mechanical relays produce, so the position readback and BIT don’t see false transitions.
  • Power-loss behavior is the member difference. On a RY1, every channel reverts to reset (C↔N/C) when power is removed; on a RY2, each channel holds its last position. If you rely on a known state at power-off (e.g. a fail-safe disconnect), wire that path through a RY1’s N/C, or use a RY2 if the position must persist.

Worked examples (use your module’s pinout for the actual pins):

  • Route one source to either of two destinations. Wire the source → C, destination A → N/O, destination B → N/C. De-energized, the source reaches destination B (N/C); energized (SetRelayStateCLOSE), it reaches destination A (N/O). This is a software-controlled SPDT switch.
  • Switch a load on and off. Wire the supply → C and the load → N/O. The load is unpowered at reset/power-on (and stays off through a power loss on a RY1) and powered when you set the channel. Wire the load to N/C instead if it should be powered by default and switched off when the channel is set.

Software

There’s nothing RY-specific about which software you run. The NAI SSK (naibrd library) is identical across every OS and architecture — PetaLinux, VxWorks, DEOS, Windows. What OS you’re on is determined by your motherboard/SBC, not by the RY module. The only family-specific part is which API functions you call: relay modules use the naibrd_RLY_* calls.

RY calls are stateless — there’s no Open/Init/Free lifecycle to manage. Per-channel operations take (cardIndex, module, channel); module-level calls (such as reading the relay type or a whole-module status word) take (cardIndex, module); and the module-property queries take the module ID (modId). Where to find what you need:

  • Which functions/registers to call — the RY1-RY2 Manual documents every naibrd_RLY_* register (set position, read position/relay type, BIT status, and the interrupt controls).
  • Building and deploying on your platformConnecting to Boards covers the toolchain, deployment, and terminal access for PetaLinux/ARM Linux, VxWorks, DEOS, and Windows.
  • Launching the app on the board itselfRunning Applications from the Target walks through loading and launching your executable on the target.

Example — close a relay and read its actual contact position back:

/* SSK 1.x */
naibrd_RLY_SetRelayState(cardIndex, module, channel, NAI_RLY_STATE_CLOSE);   /* energize: COM↔N.O. */
nai_rly_state_t position;
naibrd_RLY_GetRelayPosition(cardIndex, module, channel, &position);          /* read the real contact position */
/* SSK 2.x */
naibrd_RLY_SetRelayState(cardIndex, module, channel, NAIBRD_RLY_STATE_CLOSE); /* energize: COM↔N.O. */
naibrd_rly_state_t position;
naibrd_RLY_GetRelayPosition(cardIndex, module, channel, &position);           /* read the real contact position */

Confirm communication

A relay module gives you an unusually direct proof of life: because the second pole reads back the relay’s actual position, you can command a channel and confirm the contacts physically moved — with no external wiring at all. That single readback exercises the whole path: your board connection, the SSK, and the module’s command and sensing hardware.

Command-and-read-back (no wiring). Set a channel, then read its position back. GetRelayState returns what you commanded; GetRelayPosition returns what the contacts actually did (sensed on the BIT pole) — they should agree. Also read the channel’s real-time BIT, where 0 = Go (healthy) and 1 = Nogo (fault):

/* SSK 1.x — command a channel, read the real contact position + BIT (no external wiring) */
naibrd_RLY_SetRelayState(cardIndex, module, channel, NAI_RLY_STATE_CLOSE);
nai_rly_state_t position;
naibrd_RLY_GetRelayPosition(cardIndex, module, channel, &position);          /* should read CLOSE */
 
nai_status_bit_t bit;
naibrd_RLY_GetStatus(cardIndex, module, channel, NAI_RLY_BIT_STATUS_REALTIME, &bit);  /* 0 = Go */
/* SSK 2.x — command a channel, read the real contact position + BIT (no external wiring) */
naibrd_RLY_SetRelayState(cardIndex, module, channel, NAIBRD_RLY_STATE_CLOSE);
naibrd_rly_state_t position;
naibrd_RLY_GetRelayPosition(cardIndex, module, channel, &position);          /* should read CLOSE */
 
nai_status_bit_t bit;
naibrd_RLY_GetChanMappedStatus(cardIndex, module, channel,
   NAIBRD_RLY_CHAN_MAPPED_STATUS_BIT_REALTIME, &bit);                        /* 0 = Go */

If the position readback follows what you commanded and BIT reads Go, the board, the SSK, and the module are all confirmed. The RLY BasicOps sample drives exactly this flow — open/close a channel, set all four at once with a state word, and watch the relay setting, position readback, and BIT status update per channel.

Features

Each RY operation works per channel (a few are per module) through the naibrd_RLY_* API. The blocks below group the calls by what you’re doing, with the SSK 1.x and 2.x signatures side by side. The function names for the standard operations are identical in both versions; the 1.x → 2.x differences are narrow: the enum/typedef names gained the naibrd_ prefix (nai_rly_*naibrd_rly_*), out-parameters gained the p_out prefix, the status calls GetStatus / ClearStatus became per-channel GetChanMappedStatus / ClearChanMappedStatus, and the interrupt calls were renamed to the channel-mapped form.

Switch a relay channel

What it does: the core operation — command a channel open (STATE_OPEN, de-energized: COM↔N/C) or closed (STATE_CLOSE, energized: COM↔N/O), and read back both the commanded setting (GetRelayState) and the relay’s actual sensed position (GetRelayPosition, from the BIT pole). Drive one channel at a time, or set/read all four at once as a bitmapped word (LSB = Ch1) with the group-raw calls. GetRelayType reports whether the module is latching or non-latching.

Applies to: all RY modules (RY1, RY2).

Also here: state values are NAIBRD_RLY_STATE_OPEN / NAIBRD_RLY_STATE_CLOSE; relay-type values NAIBRD_RLY_NONLATCHING / NAIBRD_RLY_LATCHING; the group-raw type selects the word — NAIBRD_RLY_RAW_GROUP_RELAYSTATE (the setting) or NAIBRD_RLY_RAW_GROUP_RELAYSTATE_READBACK (the position), with group index 1. The channel count is naibrd_RLY_GetChannelCount(modId).

Relevant APIs:

/* SSK 1.x */
nai_status_t naibrd_RLY_SetRelayState(int32_t cardIndex, int32_t module, int32_t channel, nai_rly_state_t setstate);
nai_status_t naibrd_RLY_GetRelayState(int32_t cardIndex, int32_t module, int32_t channel, nai_rly_state_t* outstate);
nai_status_t naibrd_RLY_GetRelayPosition(int32_t cardIndex, int32_t module, int32_t channel, nai_rly_state_t* outstate);
nai_status_t naibrd_RLY_GetRelayType(int32_t cardIndex, int32_t module, nai_rly_relaytype_t* outtype);
nai_status_t naibrd_RLY_SetGroupRaw(int32_t cardIndex, int32_t module, int32_t group, nai_rly_raw_group_t type, uint32_t rawdata);
nai_status_t naibrd_RLY_GetGroupRaw(int32_t cardIndex, int32_t module, int32_t group, nai_rly_raw_group_t type, uint32_t* outrawdata);
int32_t naibrd_RLY_GetChannelCount(uint32_t modid);
/* SSK 2.x */
nai_status_t naibrd_RLY_SetRelayState(int32_t cardIndex, int32_t module, int32_t channel, naibrd_rly_state_t state);
nai_status_t naibrd_RLY_GetRelayState(int32_t cardIndex, int32_t module, int32_t channel, naibrd_rly_state_t* p_outstate);
nai_status_t naibrd_RLY_GetRelayPosition(int32_t cardIndex, int32_t module, int32_t channel, naibrd_rly_state_t* p_outstate);
nai_status_t naibrd_RLY_GetRelayType(int32_t cardIndex, int32_t module, naibrd_rly_relaytype_t* p_outtype);
nai_status_t naibrd_RLY_SetGroupRaw(int32_t cardIndex, int32_t module, int32_t group, naibrd_rly_raw_group_type_t type, uint32_t rawData);
nai_status_t naibrd_RLY_GetGroupRaw(int32_t cardIndex, int32_t module, int32_t group, naibrd_rly_raw_group_type_t type, uint32_t* p_outrawData);
int32_t naibrd_RLY_GetChannelCount(uint32_t modId);

Exercise it: RLY BasicOps (Open / Close, Set Word) · RLY BasicOps (1.x).

Monitor relay health (BIT)

What it does: the module runs a continuous background BIT that compares each channel’s commanded state against the position sensed on the second pole — a mismatch (a stuck, welded, or failed contact) flags that channel. Read the per-channel BIT in real-time (live state) or latched (any fault since the last clear) form, where 0 = Go (healthy) and 1 = Nogo (fault). The latched flag is write-1-to-clear: clear it with ClearChanMappedStatus. The BIT runs transparently — no setup or programming is needed to enable it.

Applies to: all RY modules.

Also here: status types are NAIBRD_RLY_CHAN_MAPPED_STATUS_BIT_REALTIME / _BIT_LATCHED (SSK 1.x: NAI_RLY_BIT_STATUS_REALTIME / _LATCHED). You can also read the whole-module latched or real-time BIT word across all channels at once with naibrd_RLY_GetGroupRaw (NAIBRD_RLY_RAW_GROUP_BIT_LATCHED_STATUS / _BIT_REALTIME_STATUS).

Relevant APIs:

/* SSK 1.x */
nai_status_t naibrd_RLY_GetStatus(int32_t cardIndex, int32_t module, int32_t channel, nai_rly_status_type_t type, nai_status_bit_t* outstatusBit);
nai_status_t naibrd_RLY_ClearStatus(int32_t cardIndex, int32_t module, int32_t channel, nai_rly_status_type_t type);
/* SSK 2.x */
nai_status_t naibrd_RLY_GetChanMappedStatus(int32_t cardIndex, int32_t module, int32_t channel, naibrd_rly_chan_mapped_status_type_t type, nai_status_bit_t* p_outstatusBit);
nai_status_t naibrd_RLY_ClearChanMappedStatus(int32_t cardIndex, int32_t module, int32_t channel, naibrd_rly_chan_mapped_status_type_t type);

Exercise it: RLY BasicOps (status display, Reset BIT Status) · RLY BasicOps (1.x).

Interrupt on a BIT fault

What it does: instead of polling, have the module raise an interrupt when a channel’s BIT flags a fault. Enable the interrupt per channel, choose edge triggering (fire once when the fault first appears) or level triggering (fire as long as the fault persists), and set the interrupt vector (an identifier reported to your interrupt service routine) and steering (where to send it).

Applies to: all RY modules. Enable and trigger-type are per channel; vector and steering are per module.

Also here: trigger type is edge/level (SSK 1.x nai_rly_interrupt_t: NAI_RLY_EDGE_INTERRUPT / NAI_RLY_LEVEL_INTERRUPT; SSK 2.x naibrd_int_trigger_type_t); steering directs the interrupt to VME (1), the ARM processor via SerDes (2), PCIe (5), or cPCI (6). The vector and steering registers live in Motherboard Common Memory, keyed to the module’s slot. Each setter below has a matching Get… getter.

Relevant APIs:

/* SSK 1.x */
nai_status_t naibrd_RLY_SetInterruptEnable(int32_t cardIndex, int32_t module, int32_t channel, nai_rly_status_type_t type, bool_t enable);
nai_status_t naibrd_RLY_SetEdgeLevelInterrupt(int32_t cardIndex, int32_t module, int32_t channel, nai_rly_status_type_t type, nai_rly_interrupt_t interruptType);
nai_status_t naibrd_RLY_SetGroupInterruptVector(int32_t cardIndex, int32_t module, int32_t group, nai_rly_status_type_t type, uint32_t vector);
nai_status_t naibrd_RLY_SetGroupInterruptSteering(int32_t cardIndex, int32_t module, int32_t group, nai_rly_status_type_t type, naibrd_int_steering_t steering);
/* SSK 2.x */
nai_status_t naibrd_RLY_SetChanMappedInterruptEnable(int32_t cardIndex, int32_t module, int32_t channel, naibrd_rly_chan_mapped_status_type_t type, bool_t enable);
nai_status_t naibrd_RLY_SetChanMappedInterruptTriggerType(int32_t cardIndex, int32_t module, int32_t channel, naibrd_rly_chan_mapped_status_type_t type, naibrd_int_trigger_type_t interruptType);
nai_status_t naibrd_RLY_SetChanMappedInterruptVector(int32_t cardIndex, int32_t module, naibrd_rly_chan_mapped_status_type_t type, uint32_t vector);
nai_status_t naibrd_RLY_SetChanMappedInterruptSteering(int32_t cardIndex, int32_t module, naibrd_rly_chan_mapped_status_type_t type, naibrd_int_steering_t steering);

Exercise it: RLY BasicOps (interrupt enable / trigger) · RLY Interrupt (Basic) · RLY Interrupt (1.x).

Try it

The snippets below show the order of naibrd_RLY_* calls for each task — drop them into the body of an NAI sample app (after the standard board-connection flow: naiapp_RunBoardMenu()naiapp_query_CardIndex() / naiapp_query_ModuleNumber()cardIndex / module, see Opening a Software Handle to Your Board) and you have working relay control. Each is the conceptual sequence, not a fully-buildable program; the RLY BasicOps sample is the full reference. RY calls are stateless — there is no Open/Init/Free.

Try it — Open and close a channel

Command a channel closed, confirm the contacts actually moved (commanded setting and sensed position), then open it again.

/* SSK 1.x — close a channel, read back setting + actual position, reopen */
naibrd_RLY_SetRelayState(cardIndex, module, channel, NAI_RLY_STATE_CLOSE);   /* energize: COM↔N.O. */
 
nai_rly_state_t setting, position;
naibrd_RLY_GetRelayState(cardIndex, module, channel, &setting);              /* what you commanded */
naibrd_RLY_GetRelayPosition(cardIndex, module, channel, &position);          /* what the contacts did */
 
naibrd_RLY_SetRelayState(cardIndex, module, channel, NAI_RLY_STATE_OPEN);    /* de-energize: COM↔N.C. */
/* SSK 2.x — close a channel, read back setting + actual position, reopen */
naibrd_RLY_SetRelayState(cardIndex, module, channel, NAIBRD_RLY_STATE_CLOSE); /* energize: COM↔N.O. */
 
naibrd_rly_state_t setting, position;
naibrd_RLY_GetRelayState(cardIndex, module, channel, &setting);              /* what you commanded */
naibrd_RLY_GetRelayPosition(cardIndex, module, channel, &position);          /* what the contacts did */
 
naibrd_RLY_SetRelayState(cardIndex, module, channel, NAIBRD_RLY_STATE_OPEN);  /* de-energize: COM↔N.C. */

Try it — Set all four channels at once

Drive every channel from one bitmapped word — LSB = Ch1, a 1 bit sets/closes that channel. For example 0x5 (0b0101) closes Ch1 and Ch3 and opens Ch2 and Ch4. Group index is 1.

/* SSK 1.x — close Ch1 + Ch3, open Ch2 + Ch4, then read positions back */
uint32_t stateWord = 0x5;  /* 0b0101: bit per channel, LSB = Ch1 */
naibrd_RLY_SetGroupRaw(cardIndex, module, 1, NAI_RLY_RAW_GROUP_RELAYSTATE, stateWord);
 
uint32_t positionWord;
naibrd_RLY_GetGroupRaw(cardIndex, module, 1, NAI_RLY_RAW_GROUP_RELAYSTATE_READBACK, &positionWord);
/* SSK 2.x — close Ch1 + Ch3, open Ch2 + Ch4, then read positions back */
uint32_t stateWord = 0x5;  /* 0b0101: bit per channel, LSB = Ch1 */
naibrd_RLY_SetGroupRaw(cardIndex, module, 1, NAIBRD_RLY_RAW_GROUP_RELAYSTATE, stateWord);
 
uint32_t positionWord;
naibrd_RLY_GetGroupRaw(cardIndex, module, 1, NAIBRD_RLY_RAW_GROUP_RELAYSTATE_READBACK, &positionWord);

Try it — Watch health and interrupt on a BIT fault

Read a channel’s real-time BIT, then have the module raise an edge-triggered interrupt the moment a BIT fault appears (set the vector and steering per module — see Features).

/* SSK 1.x — read BIT, then enable an edge interrupt on a BIT fault */
nai_status_bit_t bit;
naibrd_RLY_GetStatus(cardIndex, module, channel, NAI_RLY_BIT_STATUS_REALTIME, &bit);  /* 0 = Go, 1 = Nogo */
 
naibrd_RLY_SetEdgeLevelInterrupt(cardIndex, module, channel, NAI_RLY_BIT_STATUS_LATCHED, NAI_RLY_EDGE_INTERRUPT);
naibrd_RLY_SetInterruptEnable(cardIndex, module, channel, NAI_RLY_BIT_STATUS_LATCHED, TRUE);
/* SSK 2.x — read BIT, then enable an edge interrupt on a BIT fault */
nai_status_bit_t bit;
naibrd_RLY_GetChanMappedStatus(cardIndex, module, channel, NAIBRD_RLY_CHAN_MAPPED_STATUS_BIT_REALTIME, &bit);  /* 0 = Go, 1 = Nogo */
 
naibrd_RLY_SetChanMappedInterruptTriggerType(cardIndex, module, channel, NAIBRD_RLY_CHAN_MAPPED_STATUS_BIT_LATCHED, /* edge */ 0);
naibrd_RLY_SetChanMappedInterruptEnable(cardIndex, module, channel, NAIBRD_RLY_CHAN_MAPPED_STATUS_BIT_LATCHED, NAI_TRUE);

Building and running the SSK samples. The snippets above are condensed for orientation. For full, buildable programs see the “Exercise it:” links under each block in FeaturesRLY BasicOps (2.x) and RLY BasicOps (1.x) — and Using NAI SSK 2.x Sample Applications · Using NAI SSK 1.x Sample Applications for build/run instructions across platforms.

Hardware capabilities and status monitoring

This section covers what the hardware provides and what you can monitor — for how to drive each function (switch, BIT, interrupts), see Features and Try it above.

What the hardware provides:

  • Four independent Form-C relay channels — single-pole, DPDT changeover (break-before-make) mechanical contacts, with full galvanic isolation between the switched circuit and the control side.
  • High switching capability — up to 220 VDC / 250 VAC at 2 A, cumulative 60 W / 62.5 VA per channel; AC or DC, analog or digital signals.
  • Non-latching (RY1) or latching (RY2) — coil-held position that reverts on power loss, or a magnetic latch that retains the last position with no power.
  • Break-before-make changeover — Common transfers between N/C and N/O without ever bridging them.
  • Independent position read-back — a dedicated second contact pole senses each relay’s actual position, separately from the command.
  • Continuous background BIT — automatic per-channel comparison of commanded state vs. sensed position; transparent, no programming required.
  • Internal de-bounce — removes mechanical contact-bounce chatter from the readback and BIT.
  • Double-buffered data — readings are buffered for immediate availability.

Statuses you can monitor programmatically (per channel):

StatusWhat it tells you
Relay settingThe state you commanded (GetRelayState, or the group state word)
Position read-backThe relay’s actual sensed contact position (GetRelayPosition, or the group readback word)
Real-time BITLive command-vs-position match for the channel (0 = Go, 1 = Nogo)
Latched BITAny BIT fault since the last clear (write-1-to-clear)

A persistent disagreement between the setting and the position read-back is exactly what trips BIT — it means a contact didn’t go where it was told (stuck, welded, or failed).

Common pitfalls

  • “Open” / “Closed” describe the N/O contact, not COM. STATE_OPEN (reset) means COM is connected to N/C (the N/O contact is open); STATE_CLOSE (set) connects COM to N/O. A signal on COM appears at N/C when the channel is “open” — easy to invert when wiring.
  • Break-before-make leaves a brief open moment. During a changeover COM is connected to neither contact for an instant. Don’t rely on make-before-break behavior; design for the gap if your circuit can’t tolerate it.
  • Respect the per-channel limits. Stay within 220 VDC / 250 VAC, 2 A, and 60 W / 62.5 VA per channel — exceeding any of them damages the contacts.
  • Protect against inductive loads. Switching relay coils, solenoids, or motors arcs the contacts when the current breaks; add a flyback diode (DC) or snubber (AC) to protect contact life.
  • Know your power-loss behavior. A RY1 channel reverts to reset (COM↔N/C) on power loss; a RY2 channel holds its last position. Don’t assume a non-latching relay holds state, or that a latching one resets — wire fail-safe paths accordingly, and use GetRelayType if your code must adapt.
  • Setting and position are two different reads. GetRelayState returns what you commanded; GetRelayPosition returns what the contacts actually did. A lasting mismatch is a hardware BIT fault, not a software bug.
  • Latched BIT is write-1-to-clear. A transient fault stays latched until you clear it with ClearChanMappedStatus — it won’t clear itself when the fault goes away.
  • The group word is bitmapped, LSB = Ch1. A 1 bit sets/closes the channel; mind the bit order so you don’t drive the wrong channels.