Generated reference › C Code — Control Systems/User Defined
kind: generated#block#control-systems-user-defined

C Code — Control Systems/User Defined

.c

Control_Systems/User_Defined/C_Code · 1 input / 1 output port(s) at insert · exports to C

Description#

The block's own DESCRIPTION_HTML, rendered verbatim — the same text the config dialog's info panel and the library navigator show. Fix a wrong sentence in the block's .cpp (R-D9), never here.

C Code

Control Systems / User Defined

Runs C you write, once per simulation step, compiled by the system C compiler at simulation start. Use it for anything the library has no block for – a nonlinearity, a lookup, a hand-written controller – when the model must also export to C.

The contract

Your code defines one function:

void compute(double t, const ICoreCMatrix* u, int uCount, ICoreCMatrix* y, int yCount)

  • t – the current simulation time, in seconds.
  • u – the input ports in order, u[0] to u[uCount-1], each an ICoreCMatrix (rows, cols, row-major data). Treat them as read-only.
  • y – the output ports in order. Set each y[i].rows and y[i].cols and fill y[i].data (capacity ICORE_MAX_MATRIX_ELEMENTS = 4096 doubles). Element (i, j) of a matrix m is ICORE_AT(m, i, j).
  • state – declare static variables for anything the block must remember; they persist between steps and are reset at every simulation start.

Ports

  • Inputs and Outputs – one of each by default, and both counts are user-editable. u and y follow the port order on the canvas. Output sizes are learned from a trial call on zero inputs at build time and must stay fixed during a simulation.

Parameters

  • C Code – edited in the code editor, opened from the Edit Code button on the config dialog's toolbar rather than in the parameter pane. math.h, stdlib.h and string.h are pre-included.
  • Sampling Time (s) – how often compute is called. Zero or less inherits the solver's rate.

Code export

C only – your code is embedded verbatim into the generated C core (with compute renamed per block, so several C Code blocks can share one export). The other nine targets (Python, MATLAB, Java, Rust, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text) are not supported: hand-written C cannot be mechanically translated, so an export to any of them fails loudly for this block rather than emitting something that does not run. Replace the block with library blocks, or with a state space, when the model has to reach those targets.

Simulink bridge

Both directions, to simulink/User-Defined Functions/C Function. The ports cross as SymbolSpec symbols (u1…, y1…, in port order) so the wiring survives, and the code crosses into the block's Output Code as text – C CodeOutputCode. The two contracts differ: ICore calls your compute once per step, while the C Function block runs its output code directly over the symbols, so the code needs adapting after crossing before the model runs on the other side. Sampling Time (s) → SampleTime, as on every block.

Notes

  • Discrete by nature: the block is stepped, never integrated, since its state lives in C statics that update per sample.
  • A compile error in your code is reported with the block's path and stops the run. Your compiled code runs in-process: a crash in it (a bad pointer, a division by zero trap) is a crash of the app, so guard your own bounds.
  • Helper functions and statics you define are file-scope in the generated C export – prefix them if the model carries more than one C Code block.

Code facts#

FactValue
registered typeControl_Systems/User_Defined/C_Code
familyControl_Systems/User_Defined
solver environment classICoreBlock_0_Control_Systems_1_User_Defined_2_C_Code
sourcesrc/ICoreSDK/ICoreBlockLibrary/Blocks/Control_Systems/User_Defined/C_Code/ICoreBlock_0_Control_Systems_1_User_Defined_2_C_Code.cpp
headersrc/ICoreSDK/ICoreBlockLibrary/Blocks/Control_Systems/User_Defined/C_Code/ICoreBlock_0_Control_Systems_1_User_Defined_2_C_Code.h
default size on canvas100 × 80 px
ports at insert1 in, 1 out
code generators implementedC

Ports#

#DirectionSignal typeDescription label
1inICoreDouble
2outICoreDouble

Ports the constructor creates. A block whose port list changes with its configuration adds or removes ports at load time; the count above is the one a freshly inserted block has.

Configuration variables#

Config variableDefaultSimulink parameter
CONFIG_C_CODE (unresolved)DEFAULT_CODE_TEMPLATE

Every block also carries Sampling Time (s) from ICoreBlockSolverEnvironment: zero or less inherits the solver's rate, a positive value runs the block at that period.

supportSupport::Both
Simulink pathsimulink/User-Defined Functions/C Function
port-count rulePortsParam::
SampleTime parameteryes
portsderived from a SymbolSpec (addSymbol), not a port-count parameter
ICore configSimulink parameterValue translation
C CodeOutputCodepasses through

Caveat (shown to the user): the code crosses into the C Function block's OutputCode as text, but the contracts differ: ICore calls compute(t, u, uCount, y, yCount) while Simulink runs the output code directly over its SymbolSpec symbols (u1.., y1..), so the code needs adapting after crossing

Catalog contract: src/ICoreSDK/ICoreCoder/ICoreCommandSystem/SimulinkBridge/ICoreSimulinkBlockCatalog.h

Description vs code#

⚠ Mismatch. Fixed at the source — the description or the code, whichever is wrong (R-D9) — never explained away on a docs page:

  • B7 no ICoreSimulinkBlockCatalog::registerEntry — the bridge treats an unregistered type as unsupported, so the block owes an entry

The verdict above is tools/docs/check_block_descriptions.py (P7.1), which compares LISTS. It cannot read a sentence: "stateless" on a block with a state, an initial-value semantic the recursion does not implement, a "not synthesizable" caveat the HDL banner contradicts. That is the agent audit (P7.3) on BLOCK_DESCRIPTION_AUDIT.md, and this tool's green is not a substitute for one.

File banner (developer view)#

The top comment of the block's .cpp — the maths, the realization and the export strategy, addressed to whoever changes it. It must not contradict the description above (P7.5).

C Code block — user-editable compute(t, u, uCount, y, yCount) over row-major matrices The user's source lives in a private config variable (edited via the config dialog's "Edit Code" toolbar button, persisted base64 by the recipe serializer). Contract:

void compute(double t, const ICoreCMatrix* u, int uCount, ICoreCMatrix* y, int yCount)

  • t: time [s]; u: input ports in order (read-only, row-major);

y: output ports in order — SET rows/cols and fill data. statics persist between steps and reset at every simulation start. */

Simulation: discrete-only block; compute_h_discrete runs the code compiled by the system C compiler and loaded in-process (ICoreCRuntime). Output port sizes are inferred at build time by a trial call on zero inputs; the compiled library is cached by source text since the build's port-size pass repeats and a compiler run per pass would crawl. Code export: C only — every other language keeps the base class's empty default, which the exporters report as unsupported.

Sample results#

C Code — Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sampleC Code — Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample-202-2-10123inputoutput
tin ICoreDouble-Out-0out ICoreDouble-Out-0
0-2-2
0.40.50.5
0.8-2-2
1.20.50.5
1.6-2-2
20.50.5
2.4-2-2
2.80.50.5
3.2-2-2
3.60.50.5
4-2-2
4.40.50.5
4.8-2-2
5.20.50.5

Every 4th of 60 samples, from the table stimulus.

The same rig also ran:

StimulusWhat it isOutput range
impulseImpulse: one sample of 1 at k = 5, 0 elsewhere (Repeating Sequence Stair)0 … 1
rampRamp: slope 1 from t = 00 … 5.8
sineSine Wave: amplitude 1, 2 rad/s, no phase, no bias-1 … 0.9996
stepStep: 0 -> 1 at t = 1 s0 … 1

Plotted: table — Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample

Category static · sample time 0.1 · 60 steps · commit ccf005c8 · produced by docsSample --out <folder> --steps 60 · data docs/generated/samples/Control_Systems__User_Defined__C_Code.json · the SVG is generated from those numbers by tools/docs/plot_svg.py, so it is a run and not a drawing (R-D10).