---
name: matlab/matlab-call-nidaqmx
source: https://app.decimal.ai/s/matlab-matlab-call-nidaqmx@1/SKILL.md
source_sha256: 52451a6026e0
---

# matlab-call-nidaqmx

Translate NI-DAQmx C signatures into correct `calldaqlib` MATLAB calls on
Data Acquisition Toolbox R2026a+.

## When to Use

- User explicitly mentions `calldaqlib` or a specific `DAQmx*` C function
- User needs NI-DAQmx capability the daq object doesn't expose (retriggerable,
  export signal, reference triggers, enhanced alias rejection, digital filters)
- User is debugging at the driver level (reading back what the NI driver holds)
- User is translating existing C/LabVIEW code to MATLAB

## When NOT to Use

- User describes a capability achievable with the daq object alone (`dq.Rate`,
  `addtrigger`, `addclock`, `addinput`, `read`, `write`, `start`, `stop`)
- User asks about the Session-based (legacy) DAQ interface
- User needs `DAQmxCreateTask` or `DAQmxLoadTask` (these cannot work through
  calldaqlib — it owns task creation internally)

## Decision Tree

### Step 0 — Read the user's intent

Did the user explicitly mention `calldaqlib` or a specific DAQmx C function?

- **Yes** — Write the calldaqlib call they asked for. Do NOT redirect to the
  daq object. They have a reason (driver debugging, matching C code, capability
  gap, learning). Skip to Step 2.
- **No** — They described a capability without naming calldaqlib. Go to Step 1.

### Step 1 — Pick the right tool

Can the daq object property/method do this? (`dq.Rate`, `addtrigger`,
`addclock`, `addinput`, `dq.NumScansAvailable`, etc.)

- **Yes** — Recommend the daq object. Mention calldaqlib only if the user needs
  driver-level diagnostics or a capability outside daq object coverage.
- **No** — Proceed to Step 2.

### Step 2 — Device-level check

Does the C function lack a `taskHandle` parameter (device-level API)?

- Functions like `DAQmxGetDevIsSimulated`, `DAQmxGetDevAISupportedMeasTypes`:
  Use an **empty daq object** (no channels added). Pass the device name as an
  argument. Returns a plain scalar or array, not a dictionary.
- Functions like `DAQmxCreateTask`, `DAQmxLoadTask`: These **do not work**
  through calldaqlib at all (calldaqlib owns task creation internally).
- Functions like `DAQmxConnectTerms`, `DAQmxDisconnectTerms`: Use an **empty
  daq object** (same as device-level queries). These work on X-series devices.

### Step 3 — Multi-task check

Does the daq object have multiple internal task handles (e.g., AI + DIO)?

- **Getters with a channel arg**: The call runs on both tasks. The irrelevant
  task warns. Read the dictionary key you care about. Acceptable.
- **Setters targeting one measurement type**: No scoping mechanism. Split into
  separate daq objects (loses synchronized start/stop).

### Step 4 — Buffer placeholder check

Is this a getter returning a string or array?

- **String getter** (`char *data, uInt32 bufferSize` in C): Pass `""` then
  `bufferSize`. Example: `calldaqlib(dq, "DAQmxGetSampClkSrc", "", 256)`
- **Array getter** (`int32 data[], uInt32 arraySize` in C): Pass
  `zeros(1,N,'type')` then `N`. Example:
  `calldaqlib(dq, "DAQmxGetDevAISupportedMeasTypes", "Dev1", zeros(1,32,'int32'), 32)`

### Step 5 — Enum check

Does any argument correspond to a C `int32` enum slot?

- **Always use the string form**: `"DAQmx_Val_RisingSlope"` not `int32(10280)`.
  Both work, but strings are self-documenting and prevent silent wrong-enum bugs.
- See `references/enum-constants.md` for the 15 most-used enum names.

## Call Forms

Six distinct patterns cover all `calldaqlib` usage:

### 1. Config (DAQmxCfg*)

```matlab
dq = daq("ni");
addinput(dq, "Dev1", "ai0", "Voltage");
calldaqlib(dq, "DAQmxCfgSampClkTiming", "/Dev1/PFI0", 5000, ...
    "DAQmx_Val_Rising", "DAQmx_Val_FiniteSamps", uint64(1000));
```

### 2. Setter (DAQmxSet*)

```matlab
calldaqlib(dq, "DAQmxSetStartTrigRetriggerable", true);
```

### 3. Getter — scalar (DAQmxGet* returning numeric)

```matlab
result = calldaqlib(dq, "DAQmxGetSampClkRate");
rate = result("Dev1_ai0");
```

Returns a `dictionary` keyed by channel name — even on single-channel objects.

### 4. Getter — string (DAQmxGet* with char output)

```matlab
result = calldaqlib(dq, "DAQmxGetSampClkSrc", "", 256);
source = result("Dev1_ai0");
```

The `""` is required as a placeholder for the `char *data` output slot.
`bufferSize` follows immediately. Use 256 for short names, 1024 for long paths.

### 5. Getter — array (DAQmxGet* with typed array output)

```matlab
dEmpty = daq("ni");
result = calldaqlib(dEmpty, "DAQmxGetDevAISupportedMeasTypes", ...
    "Dev1", zeros(1, 32, "int32"), 32);
measTypes = result(result ~= 0);
```

Pre-allocate a typed buffer (`zeros(1,N,'int32')`) matching the C signature's
array type. Filter unused slots with `result(result ~= 0)`.

### 6. Device-level (no taskHandle in C signature)

```matlab
dEmpty = daq("ni");
isSim = calldaqlib(dEmpty, "DAQmxGetDevIsSimulated", "Dev1");
```
Use an empty daq (no channels added). Pass device name as argument.
Returns a plain scalar (not a dictionary).

Also works for terminal routing on X-series devices:

```matlab
dEmpty = daq("ni");
calldaqlib(dEmpty, "DAQmxConnectTerms", "/Dev1/PFI0", "/Dev1/PFI1", "DAQmx_Val_DoNotInvertPolarity");
calldaqlib(dEmpty, "DAQmxDisconnectTerms", "/Dev1/PFI0", "/Dev1/PFI1");
```

## C-to-calldaqlib Translation

| C argument | calldaqlib equivalent |
|---|---|
| `TaskHandle taskHandle` | **Omit** — daq object owns it |
| `const char source[]` | MATLAB string `"/Dev1/PFI0"` |
| `float64 rate` | MATLAB double |
| `int32 activeEdge` (enum) | Enum name string `"DAQmx_Val_Rising"` |
| `uInt64 sampsPerChan` | `uint64(1000)` |
| `bool32 data` (input) | `true` / `false` |
| `float64 *data` (output scalar) | Becomes return value (dictionary) |
| `int32 *data` (output scalar) | Becomes return value (dictionary) |
| `char *data, uInt32 bufferSize` (output pair) | Pass `""` + bufferSize |
| `int32 data[], uInt32 arraySize` (output array) | Pass `zeros(1,N,'int32')` + N |
| Any getter return | Always a `dictionary` keyed by `DevN_chanName` |

## Hard Rules

1. **taskHandle is implicit.** The daq object owns it. Never pass it.

2. **calldaqlib loops over every internal task.** A daq with AI + DIO has 2
   NI tasks; both get the call. For getters with a channel arg, ignore the
   warning from the irrelevant task and read the dictionary key you want.
   For setters targeting one measurement type, split into separate daq objects.

3. **Output-pointer args still need a placeholder + bufferSize.** String
   getters: pass `""` before bufferSize. Array getters: pass
   `zeros(1,N,'type')` before arraySize.

4. **start() clobbers calldaqlib-set rate and clock source.** `start()`
   reapplies `dq.Rate` to the driver. If you set rate via
   `DAQmxCfgSampClkTiming` then call `start()`, it snaps back to `dq.Rate`.
   Fix: set `dq.Rate` first, use calldaqlib only for parameters the daq
   object does not track. Alternative: use `DAQmxStartTask`/`DAQmxStopTask`
   via calldaqlib to bypass the daq object's commit pass entirely.

5. **Enum constants: use the string form.** `"DAQmx_Val_RisingSlope"` not
   `int32(10280)`. Strings are readable and prevent wrong-enum bugs. The
   error on a bad string is misleading ("Value must be of type int32") —
   it means the string wasn't recognized, not that you should pass an int.

6. **Device-level APIs need an empty daq.** Functions whose C signature has
   no `taskHandle` (like `DAQmxGetDevIsSimulated`,
   `DAQmxGetDevAISupportedMeasTypes`) work only when the daq object has no
   channels. Create `dEmpty = daq("ni")` and pass the device name as an arg.

7. **`DAQmxCreateTask` and `DAQmxLoadTask` cannot work through calldaqlib.**
   These functions create a new task — calldaqlib already owns task creation
   internally. `DAQmxConnectTerms`/`DAQmxDisconnectTerms` DO work via an
   empty daq object on X-series devices (same pattern as device-level queries).

8. **Property values are scalar.** Passing a vector where a scalar is
   expected errors. To set the same property on multiple channels, loop.

9. **Channel/device paths are not validated client-side.** A bad path
   produces no error until `start()`.

10. **Trigger support is per-device.** Not all devices support all trigger
    types. Error -200077 lists the supported enum values — read it.

11. **All task-level getter results return a `dictionary`.** Keyed by
    `DevN_chanName`. Never expect a bare scalar. Use `result("Dev1_ai0")`
    or iterate `keys(result)`.

12. **Buffer-size too small returns NI Error -200228.** The error message
    includes "Required Buffer Size in Bytes: N" — parse it and retry with N.
    Heuristic: 256 for short names, 1024 for long paths/channel lists.

13. **Array getters return a fixed-size buffer.** Filter unused trailing
    zeros with `result(result ~= 0)`.

## Conventions

- Always set `dq.Rate` before using calldaqlib for timing config
- Always use enum name strings, never raw integers
- Always expect a dictionary return from task-level getters
- Always pass `""` before bufferSize for string getters
- Always pre-allocate typed buffer for array getters
- Use empty daq (no channels) for device-level queries
- Warn about multi-task semantics in prose before the code block
- Configure trigger type before enabling retriggerable mode
- Retriggerable mode requires `DAQmx_Val_FiniteSamps` — it does not work with `ContSamps`
- Use specific getter function names (`DAQmxGetSampClkRate`) not generic attribute getters (`DAQmxGetTimingAttribute`)

## References

- `references/hot-signatures.md` — 20 most-used calldaqlib signatures by category
- `references/enum-constants.md` — 15 DAQmx_Val_* enum name strings
- `references/common-mistakes.md` — Mistakes from discovery trials and customer usage

----

Copyright 2026 The MathWorks, Inc.

----