This page documents the helper headers that come with the additive
cpp_logic interface in ecmc.
Use it when:
cpp_logic moduleFor the IOC loading and runtime model, start with C++ Logic.
The current helper headers are:
ecmcCppLogic.hpp
Includes the core binding/export API, host-service helpers, and startup
macro helpers.ecmcCppMotion.hppecmcCppControl.hppecmcCppUtils.hppecmcCppTrace.hppecmcCppPersist.hppThese are additive helper layers on top of the cpp_logic ABI. They do not
replace the original plugin ABI in ecmcPluginDefs.h.
This is the core C++ programming layer.
It provides:
ecmcCpp::LogicBaseECMC_CPP_LOGIC_REGISTER(...)ECMC_CPP_LOGIC_REGISTER_DEFAULT(...)ecmc... item-binding builderepics... export builderTypical pattern:
struct MyLogic : public ecmcCpp::LogicBase {
int32_t actual_position {0};
int16_t velocity_setpoint {1000};
MyLogic() {
ecmc.input("ec.s14.positionActual01", actual_position);
epics.writable("main.velocity_setpoint", velocity_setpoint);
}
void run() override {}
};
ECMC_CPP_LOGIC_REGISTER_DEFAULT(MyLogic)
For scalar values:
ecmc.input(...)ecmc.output(...)epics.readOnly(...)epics.writable(...)For arrays:
ecmc.inputArray(...)ecmc.outputArray(...)ecmc.inputAutoArray(...)ecmc.outputAutoArray(...)epics.readOnlyArray(...)epics.writableArray(...)For raw buffers:
ecmc.inputBytes(...)ecmc.outputBytes(...)epics.readOnlyBytes(...)epics.writableBytes(...)The core header also exposes small helper functions backed by ECMC host services:
ecmcCpp::getCycleTimeS()ecmcCpp::getEcMasterStateWord(...)ecmcCpp::getEcSlaveStateWord(...)ecmcCpp::lutExists(...)ecmcCpp::lutGetValue(...)ecmcCpp::getIocState()ecmcCpp::requestIocExit(...)ecmcCpp::setEnableDbg(...)ecmcCpp::publishDebugText(...)Typical use cases:
Lookup table access uses the same LUT objects as the PLC lut_get_value(...)
helper:
double correction = 0.0;
if (ecmcCpp::lutExists(0)) {
correction = ecmcCpp::lutGetValue(0, position);
}
The first argument is the LUT id. The second argument is the input/index value.
The helper returns 0.0 if the LUT id is out of range or if the LUT object has
not been loaded. Use ecmcCpp::lutExists(...) when logic should check for an
optional LUT without logging an error. See Lookup Tables
for loading and file format details.
IOC exit requests are deferred through the main realtime loop. The helper only sets an exit request flag:
if (fatal_condition) {
ecmcCpp::requestIocExit(1);
}
Do not call exit() or epicsExit() directly from run(). Use
requestIocExit(...) for fatal conditions where the whole IOC should stop. The
main realtime loop observes the request and leaves through the ecmc cleanup path.
The IOC loadCppLogic.cmd MACROS argument is available to user code as a
plain text string. It is intended for small configuration values such as slave
ids, axis ids, feature flags, and simple numeric tuning constants.
Available helpers:
ecmcCpp::getMacrosString()ecmcCpp::getMacroValue(macros, key)ecmcCpp::getMacroValueString(macros, key, defaultValue)ecmcCpp::getMacroValueInt(macros, key, defaultValue)ecmcCpp::getMacroValueDouble(macros, key, defaultValue)Typical use:
const std::string macros = ecmcCpp::getMacrosString();
const int slave_id = ecmcCpp::getMacroValueInt(macros, "S_ID", 14);
const int axis_id = ecmcCpp::getMacroValueInt(macros, "AXIS_ID", 1);
const bool dbg = ecmcCpp::getMacroValueInt(macros, "DBG", 0) != 0;
const double gain = ecmcCpp::getMacroValueDouble(macros, "GAIN", 1.0);
const std::string mode = ecmcCpp::getMacroValueString(macros, "MODE", "normal");
ecmcCpp::setEnableDbg(dbg);
getMacroValue(...) returns an empty string when the key is missing.
getMacroValueString(...) returns the default value when the key is missing.
The numeric helpers return the default value when the key is missing or when
parsing fails. The parser accepts comma-separated KEY=VALUE text and ignores
commas inside single or double quoted values. Optional matching quotes around a
value are removed.
ecmcCppLogic.hpp also exposes direct axis-oriented helpers backed by ECMC host
services. These are separate from the MC_* wrappers in ecmcCppMotion.hpp.
Trajectory and encoder source selection:
ecmcCpp::axisUseInternalTraj(...)ecmcCpp::axisUseExternalTraj(...)ecmcCpp::axisUseInternalEnc(...)ecmcCpp::axisUseExternalEnc(...)Axis state readback:
ecmcCpp::axisGetActualPos(...)ecmcCpp::axisGetSetpointPos(...)ecmcCpp::axisGetActualVel(...)ecmcCpp::axisGetSetpointVel(...)ecmcCpp::axisIsEnabled(...)ecmcCpp::axisIsBusy(...)ecmcCpp::axisHasError(...)ecmcCpp::axisGetErrorId(...)External source value injection:
ecmcCpp::axisSetExternalSetpointPos(...)ecmcCpp::axisSetExternalEncoderPos(...)Use these helpers when the logic should work directly with ECMC axis source
selection or external trajectory/encoder feeds, instead of using the higher
level PLCopen-style MC_* blocks.
Current control helper:
ecmcCpp::PidIt supports:
Kp, Ki, KdFF and KffOutMin / OutMaxIMin / IMaxDFilterTauOutputs include:
OutputErrorPPartIPartDPartFFPartLimitedThis header provides MC_* style wrappers on top of the existing ecmc
motion backend.
Current wrappers include:
ecmcCpp::McAxisRefecmcCpp::McPowerecmcCpp::McResetecmcCpp::McMoveAbsoluteecmcCpp::McMoveRelativeecmcCpp::McHomeecmcCpp::McMoveVelocityecmcCpp::McStopecmcCpp::McReadStatusecmcCpp::McReadActualPositionecmcCpp::McReadActualVelocityUse it when you want PLCopen-style motion patterns from native C++ logic without writing the lower-level axis API calls directly.
This header contains the small reusable helpers that are most often used in scan-based logic.
ecmcCpp::RTrigecmcCpp::FTrigecmcCpp::TonecmcCpp::TofecmcCpp::TpThese are intended to feel familiar to users coming from IEC/ST helper blocks.
ecmcCpp::SrecmcCpp::RsecmcCpp::FlipFlopecmcCpp::BlinkecmcCpp::StateTimer<T>ecmcCpp::DebounceBoolecmcCpp::StartupDelayecmcCpp::RateLimiterecmcCpp::FirstOrderFilterecmcCpp::HysteresisBoolecmcCpp::IntegratorecmcCpp::MoveAverageecmcCpp::MinMaxHoldecmcCpp::applyDeadband(...)ecmcCpp::clampValue(...)ecmcCpp::inWindow(...)ecmcCpp::readBit(...)ecmcCpp::writeBit(...)ecmcCpp::setBit(...)ecmcCpp::clearBit(...)ecmcCpp::toggleBit(...)The bit helpers work on integer word types such as uint8_t, uint16_t,
int32_t, and uint64_t. They return a value and do not modify the input by
reference.
Example:
uint16_t drive_control {0};
drive_control = ecmcCpp::setBit(drive_control, 0);
drive_control = ecmcCpp::writeBit(drive_control, 3, enable_brake);
const bool brake_enabled = ecmcCpp::readBit(drive_control, 3);
Out-of-range bit indexes are handled without undefined shifts:
readBit(...) returns false, while the write-style helpers return the
unchanged input value.
ecmcCpp::EcMasterStatusecmcCpp::EcSlaveStatusCurrent trace helper:
ecmcCpp::TriggeredTrace<T, Capacity>It provides:
Current persistence helper:
ecmcCpp::RetainedValue<T>It provides:
restore() and store() callsThe main example families are:
See the IOC-style examples in:
examples/PSI/plugins/cpp_logic/
The best example for container and array bindings is the array-oriented example. The best example for timers/triggers/filtering is the control example. The best examples for the new helpers are the dedicated trace and retained examples.