This guide walks through writing a Cast application: connecting to a probe, receiving
real-time images, controlling basic imaging, and pulling raw data. It targets the
publicly released v12 API. Snippets are C using the headers in
include/cast; the same sequence applies to the Python
(pyclariuscast), Swift, and Android bindings in examples.
🔴 The Clarius App must be running and connected to a probe to use the Cast API. Cast is a secondary connection for streaming — it cannot run stand-alone. The PC or device running your Cast program must be on the same wireless network as the probe and the App. Contrast this with Solum, which connects to the probe directly without the App.
flowchart LR
prb[Probe]
subgraph mobile[Mobile Device]
app[Clarius App]
end
subgraph pc[PC / device]
cast[Your Cast app]
end
prb <-- Primary Connection --> app
prb <-- Cast Connection --> cast
Lifecycle:
castInit(callbacks, width, height)
castConnect(ip, port, cert, fn)
-> imageCallback(image) fires repeatedly
-> castUserFunction(...) to freeze / change params
castDisconnect()
castDestroy()
For a Cast-licensed probe, the Clarius App shows the probe's IP address and Cast port when you tap the battery/temperature display area. Both are required to connect.
- The address is typically on the probe's own Wi-Fi network (SSID prefixed
DIRECT-). The network password is on the App's Status page. - Optionally set Clarius Cast Permission → Research in the App to force the Cast port to 5828, which makes automated connections simpler.
Start from castDefaultInitParams(), register callbacks, set the output buffer size, and
call castInit(). It must succeed before anything else.
#include <cast/cast.h>
CusInitParams p = castDefaultInitParams();
p.args.argc = argc;
p.args.argv = argv;
p.storeDir = "/path/to/keys"; // writable dir for security keys
p.width = 640;
p.height = 480;
p.newProcessedImageFn = newProcessedImageFn; // scan-converted frames
p.newRawImageFn = newRawImageFn; // pre-scan / RF frames
p.newSpectralImageFn = newSpectralImageFn; // M / PW spectra
p.newImuDataFn = newImuDataFn; // IMU samples
p.freezeFn = freezeFn;
p.buttonFn = buttonFn;
p.progressFn = progressFn;
p.errorFn = errorFn;
if (castInit(&p) < 0)
return -1;All callbacks are listed in the API reference. Functions
return 0 (CUS_SUCCESS) / -1 (CUS_FAILURE) unless noted.
// pass "research" as the certificate to bypass authentication
castConnect("192.168.1.1", 5828, "research", connectFn);void connectFn(int imagePort, int imuPort, int swRevMatch)
{
if (imagePort == CUS_FAILURE) { /* connection failed */ return; }
if (swRevMatch == CUS_FAILURE) {
// API and App versions mismatch — update the Cast API to match the App
}
// imagePort / imuPort are the UDP ports now streaming
}Version lock. The Cast API performs a firmware check on connect and has no forward/backward compatibility. When Clarius releases a new App, download the matching Cast binaries from releases. A
swRevMatchofCUS_FAILUREmeans your API build doesn't match the running App.
void newProcessedImageFn(const void* img, const CusProcessedImageInfo* nfo,
int npos, const CusPosInfo* pos)
{
// img is nfo->imageSize bytes; default format is 32-bit ARGB.
// nfo->width x nfo->height; pos[0..npos) carries IMU samples for this frame.
}- Default output is uncompressed 32-bit ARGB; switch with
castSetFormat()(8-bit gray, JPEG, PNG). - Resize output any time with
castSetOutputSize(w, h). - Call
castSeparateOverlays(1)to receive grayscale and color/strain overlays as separate callbacks. - Pre-scan-converted (polar) and RF frames arrive on
newRawImageFn; checknfo->rf. - M-mode and PW spectra arrive on
newSpectralImageFn.
IMU data streams when enabled in the App; it arrives both tagged on image frames (pos)
and via newImuDataFn.
Cast offers secondary control — handy, but the App remains the primary UI. Use
castUserFunction() with a CusUserFunction command:
castUserFunction(Freeze, 0, returnFn); // toggle freeze
castUserFunction(SetDepth, 7.0, returnFn); // depth in cm
castUserFunction(SetGain, 60.0, returnFn); // gain in %
castUserFunction(ColorDoppler, 0, returnFn); // switch modeMost commands ignore the val argument; SetDepth and SetGain use it. See the full
command list. For lower-level acoustic control there is a
separate set of research parameters.
Raw data (IQ, RF, envelope) is read off the probe once imaging is frozen and raw-data buffering was enabled in the App (the Buffer mode icon). The exception is RF streaming, which interleaves in real time when RF mode is on.
// after freezing (castUserFunction(Freeze, ...))
castRawDataAvailability(availFn); // 1. list buffered timestamps
castRequestRawData(0, 0, 1, reqFn); // 2. request all (lzo=1 compresses)
// reqFn returns the byte size to allocate, then:
castReadRawData(&buffer, rawFn); // 3. download into your buffercastRequestRawData(start, end, lzo, fn) selects frames by nanosecond timestamp
(0,0 = all buffered); lzo=1 returns an LZO-compressed tarball. The package format is
documented in the research repository.
The v12 API can compose a capture (image + overlays + labels + measurements) and submit it back to the exam:
int id = castStartCapture(timestamp);
castAddImageOverlay(id, data, w, h, 1.0f, 0.0f, 0.0f, 0.5f); // red @ 50% opacity
castAddLabelOverlay(id, "ROI", x, y, w, h);
double pts[4] = { x1, y1, x2, y2 };
castAddMeasurement(id, CusMeasurementTypeDistance, "len", pts, 4);
castFinishCapture(id, returnFn);These capture-authoring functions exist in v12. They are being reworked in v13 — build against v12 if you depend on them today.
castDisconnect(returnFn);
castDestroy(); // free resources before exiting- API reference — every function, callback, enum, and struct
- Parameter reference — user functions and low-level research parameters
- Raw data formats — decoding captured IQ/RF/envelope
- Example programs in
examples(caster,caster_qt,python, Swift, Android)