XTOS / OPEN SOURCE REAL-TIME SYSTEMOPEN SOURCE · VERSION 0.9.0 · BUILD FROM SOURCE
文档代码示例

代码示例

三个带 main 的 C 示例:RT 队列、合成信号和 BCI 会话。

本页目录

运行前提

将三个代码块分别保存为 rt-example.c、signal-example.c、bci-example.c,放在 OpenXTOS 仓库根目录。先构建三个 SDK,再执行对应 gcc 命令。代码只使用公开头文件中的 API。

RT 使用 SCHED_OTHER、不改亲和性、不调用 mlock;signal 只用合成数组;BCI 需要已注册 XTOS 设备,只展示 start/stop 和统计,不读取有格式缺口的 float 路径。

RT 示例

示例在当前线程设置普通策略并读回策略/优先级,顺序演示一次 push/pop 深拷贝和空队列 EAGAIN。单线程顺序使用满足 SPSC;不证明并发吞吐或硬件实时延迟。输入、输出在调用方栈上,所有操作后才销毁队列。

完整文件:rt-example.c
#define _GNU_SOURCE
#include <errno.h>
#include <inttypes.h>
#include <sched.h>
#include <stdint.h>
#include <stdio.h>
#include <xtos/rt.h>
#include <xtos/spsc.h>

int main(void)
{
    const struct xtos_rt_config config = {
        .policy = SCHED_OTHER, .priority = 0, .cpu = XTOS_RT_NO_CPU
    };
    struct xtos_spsc_queue *queue;
    int32_t input[2] = {1200, -3400};
    int32_t output[2];
    struct xtos_sample_frame sent = {
        .timestamp_ns = UINT64_C(1000000000), .sequence = 1,
        .channels = 2, .sample_rate_hz = 250, .quality_flags = 0,
        .samples_nv = input
    };
    struct xtos_sample_frame received;
    struct xtos_spsc_stats stats;
    int policy, priority;

    if (xtos_rt_apply(&config) < 0 ||
        xtos_rt_get_current(&policy, &priority) < 0) {
        perror("scheduler");
        return 1;
    }
    queue = xtos_spsc_create(4, 2);
    if (queue == NULL) {
        perror("queue");
        return 1;
    }
    if (xtos_spsc_push(queue, &sent) < 0 ||
        xtos_spsc_pop(queue, &received, output, 2) < 0) {
        perror("frame");
        xtos_spsc_destroy(queue);
        return 1;
    }
    printf("policy=%d priority=%d\n", policy, priority);
    printf("sequence=%" PRIu64 " timestamp_ns=%" PRIu64
           " samples_nv=%" PRId32 ",%" PRId32 "\n",
           received.sequence, received.timestamp_ns, output[0], output[1]);
    if (xtos_spsc_pop(queue, &received, output, 2) != -1 || errno != EAGAIN) {
        fputs("expected empty queue\n", stderr);
        xtos_spsc_destroy(queue);
        return 1;
    }
    xtos_spsc_get_stats(queue, &stats);
    printf("pushed=%" PRIu64 " popped=%" PRIu64 " empty=EAGAIN\n",
           stats.pushed, stats.popped);
    xtos_spsc_destroy(queue);
    return 0;
}
bash
gcc -std=c11 -Wall -Wextra -Werror -O2 \
  -Isdk/libxtos-rt/include rt-example.c \
  sdk/libxtos-rt/libxtos-rt.a -o rt-example
./rt-example

成功判定:退出状态 0;读回 SCHED_OTHER/0;样本、序号一致;pushed/popped 各为 1;第二次 pop 为 EAGAIN。扩展 FIFO/RR 前先核验权限、恢复策略和退出路径。

Signal 示例

示例生成 256 Hz、256 点的 10/20/9 Hz 组合信号,重建并校验时间戳,执行 50 Hz 陷波和 5–40 Hz 带通。DFT/SSVEP 使用原始数组;滤波单独报告最后一个值。P300 使用独立基线和人工峰,结果仅用于数值演示。

完整文件:signal-example.c
#include <inttypes.h>
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <xtos/signal.h>

#define N 256
#define FS 256U
#define PI 3.14159265358979323846

int main(void)
{
    uint64_t timestamps[N];
    double input[N], filtered[N], power[N / 2 + 1];
    double epoch[N] = {0};
    struct xtos_signal_validation validation;
    struct xtos_notch_filter notch;
    struct xtos_bandpass_filter bandpass;
    struct xtos_ssvep_feature ssvep;
    struct xtos_p300_feature p300;
    int status;

    if (xtos_signal_correct_timestamps(UINT64_C(1000000000), FS,
                                        timestamps, N) < 0) {
        perror("timestamps");
        return 1;
    }
    status = xtos_signal_validate_timestamps(timestamps, N, FS, 0, &validation);
    if (status != 0) {
        if (status < 0) perror("validate");
        else fputs("timestamp anomalies\n", stderr);
        return 1;
    }
    for (size_t i = 0; i < N; ++i) {
        double phase = 2.0 * PI * (double)i / FS;
        input[i] = sin(10.0 * phase) + 0.5 * sin(20.0 * phase)
                 + 0.25 * sin(9.0 * phase);
    }
    if (xtos_notch_init(&notch, FS, 50.0, 20.0) < 0 ||
        xtos_bandpass_init(&bandpass, FS, 5.0, 40.0) < 0 ||
        xtos_notch_process(&notch, input, filtered, N) < 0 ||
        xtos_bandpass_process(&bandpass, filtered, filtered, N) < 0 ||
        xtos_signal_fft_power(input, N, power, N / 2 + 1) < 0 ||
        xtos_signal_ssvep_feature(input, N, FS, 10.0, 2, 1, &ssvep) < 0) {
        perror("signal");
        return 1;
    }
    for (size_t i = 0; i < 32; ++i)
        epoch[i] = (i & 1U) ? 1.0 : -1.0;
    epoch[128] = 5.0;
    if (xtos_signal_p300_feature(epoch, N, FS, 32, 250, 500, 4.0, &p300) < 0) {
        perror("p300");
        return 1;
    }
    printf("interval_ns=%" PRIu64 " anomalies=%zu/%zu\n",
           validation.expected_interval_ns, validation.interval_anomalies,
           validation.timestamp_anomalies);
    printf("bins=%d power[10]=%.3f filtered_last=%.6f\n",
           N / 2 + 1, power[10], filtered[N - 1]);
    printf("ssvep_bin=%zu harmonics=%zu snr=%.3f snr_db=%.3f\n",
           ssvep.target_bin, ssvep.harmonics_used, ssvep.snr, ssvep.snr_db);
    printf("p300_detected=%d z=%.3f latency_ms=%.3f\n",
           p300.detected, p300.peak_z_score, p300.peak_latency_ms);
    return 0;
}
bash
gcc -std=c11 -Wall -Wextra -Werror -O2 \
  -Isdk/libxtos-signal/include signal-example.c \
  sdk/libxtos-signal/libxtos-signal.a -lm -o signal-example
./signal-example

输出包括时间间隔和异常数、频谱长度与 bin 功率、滤波值、SSVEP 谐波、P300 z 分数和潜伏期。频谱容量为 N/2+1;滤波器先 init,再按顺序处理。没有真实 EEG、诊断、受试者实验或硬件延迟结果。

BCI 示例

示例读取创建时缓存的设备信息,限长打印 name,启动后立即停止,读取驱动统计并清理。它不改采样率或增益,不调用占位校准,不读 float 样本,也不把统计计数称为应用消费帧。无设备时只能编译。

完整文件:bci-example.c;无设备时只检查编译
#include <inttypes.h>
#include <stdio.h>
#include <xtos/bci.h>

int main(int argc, char **argv)
{
    const char *path = argc > 1 ? argv[1] : "/dev/xtos0";
    xtos_bci_session_t *session;
    struct xtos_bci_device_info info;
    struct xtos_bci_statistics stats;
    int exit_status = 1;

    session = xtos_bci_session_create(path);
    if (session == NULL) {
        perror("session_create");
        return 1;
    }
    if (xtos_bci_get_info(session, &info) < 0) {
        perror("get_info");
        goto cleanup;
    }
    if (info.num_channels == 0 || info.sampling_rate == 0) {
        fputs("invalid cached device info\n", stderr);
        goto cleanup;
    }
    printf("device=%.*s channels=%" PRIu32 " rate=%" PRIu32 " Hz\n",
           (int)sizeof(info.name), info.name, info.num_channels, info.sampling_rate);
    if (xtos_bci_start(session) < 0) {
        perror("start");
        goto cleanup;
    }
    /* Control-path example: do not interpret the published float read ABI. */
    if (xtos_bci_stop(session) < 0) {
        perror("stop");
        goto cleanup;
    }
    if (xtos_bci_get_stats(session, &stats) < 0) {
        perror("get_stats");
        goto cleanup;
    }
    printf("driver_samples=%" PRIu64 " dropped=%" PRIu64
           " errors=%" PRIu64 " overruns=%" PRIu64 "\n",
           stats.samples_read, stats.samples_dropped, stats.errors, stats.overruns);
    exit_status = 0;
cleanup:
    xtos_bci_session_destroy(session);
    return exit_status;
}
bash
gcc -std=c11 -Wall -Wextra -Werror -O2 \
  -Isdk/libxtos-bci/include bci-example.c \
  sdk/libxtos-bci/libxtos-bci.a -o bci-example

# Run only with a registered device and read/write permission:
./bci-example /dev/xtos0

ENOENT:检查设备绑定和注册;EACCES:检查节点权限;EBUSY:检查已有打开者;invalid cached device info 可能表示 create 时 GET_INFO 失败。保留 start/stop 错误并查看驱动日志,不能创建空设备文件绕过。

验证与扩展

记录公开提交 ID、gcc --version、完整命令、退出状态和原始 stdout/stderr。RT/signal 可在普通 Linux 主机运行;目标 XTOS 仍需复验 ABI 和环境。BCI 编译只证明符号和类型可链接;设备运行还需驱动、连接和实际采样记录。

扩展 RT 时使用一个采集线程和一个消费者,两个线程退出后销毁队列;扩展 signal 时先用固定输入验证跨块滤波和时间标签;扩展 BCI 时先解决读取格式、串口帧解析和时间标签,再接 DSP。