欢迎使用 Synex
Synex 是面向工程调试的一体化桌面工具,适合串口、UDP、TCP、CAN、MDF/MF4 等多类数据接入和分析场景。它的目标是让你在一个界面里完成设备连接、协议解析、实时观测、控制交互和测试复盘。
如果你正在做电机控制、传感器调试、车载总线分析或嵌入式上位机联调,可以优先从“第一次连接设备”和“协议解析”两节开始。
安装与下载
建议优先从首页下载区获取最新 Windows 发布包。若网络访问 Gitee 不稳定,可以使用百度网盘备用链接。
- Synex 支持的最低系统版本为 Windows 10。
- 下载压缩包后解压到不含特殊权限限制的目录。
- 首次启动前确认运行目录内的 Qt 依赖、CAN 驱动依赖和资源文件没有被杀毒软件隔离。
- 使用 CAN 硬件前,请先安装对应厂商驱动。
- 如果启动时报错缺少
msvcp*.dll、vcruntime*.dll或类似 VC++ 运行库文件,请安装最新版 Microsoft Visual C++ Redistributable 64 位运行库后再启动。
从 v3.0.4 开始,Synex 支持软件内自动升级。自动升级会检查当前版本和最新发布包,下载完成后按提示重启即可更新;低于 v3.0.4 的旧版本需要先手动下载新版安装包。
第一次连接设备
推荐先用虚拟数据源确认绘图功能正常,再切换到真实串口、UDP 或 TCP 设备。这样可以快速区分是软件配置问题,还是外部设备/协议链路问题。
- 打开连接页,选择连接类型。
- 选择协议类型,例如
JustFloat、FireWater、RawData或CustomBinary。 - 设置绘图周期和缓冲区大小。
- 点击连接开关,观察实时曲线是否开始刷新。
连接方式
Synex 将串口、UDP、TCP 服务端、TCP 客户端和虚拟数据源统一到同一套连接配置中。对于高吞吐测试,建议优先使用二进制协议和更大的缓冲区。
协议解析
连接页的数据引擎决定收到的字节如何变成曲线、图片或控制台原始帧。调试早期优先用 FireWater 或 RawData 验证链路;高频波形用 JustFloat;量产项目或字段结构固定的设备建议发布 CustomBinary。
JustFloat 高速浮点协议
JustFloat 的普通波形帧由若干个小端 float32 顺序排列,最后追加 0x7F800000 作为帧尾。下面假设电流、转速等业务变量已经在你的控制代码里定义,这里只展示打包和周期发送。
#include <stdint.h>
#include <string.h>
#include "usart.h"
extern UART_HandleTypeDef huart2;
extern float g_synex_iq;
extern float g_synex_id;
extern float g_synex_speed_rpm;
// JustFloat 按 float32 小端顺序发送通道值,并在最后追加 0x7F800000 帧尾。
void Synex_UploadJustFloat(void)
{
float frame[4];
const uint32_t tail = 0x7F800000u;
frame[0] = g_synex_iq;
frame[1] = g_synex_id;
frame[2] = g_synex_speed_rpm;
memcpy(&frame[3], &tail, sizeof(tail));
HAL_UART_Transmit_DMA(&huart2, (uint8_t *)frame, sizeof(frame));
}
// 在 1 ms 或更快的调度任务中调用,发送频率由你的控制周期决定。
void Synex_JustFloatTask1ms(void)
{
Synex_UploadJustFloat();
}
FireWater 文本 CSV 协议
FireWater 每行文本是一帧,通道值用英文逗号分隔,行尾必须带 \n。实际工程里它最适合早期联调,直接用 printf 输出当前波形或性能监测值即可。
#include <stdio.h>
extern float g_synex_bus_voltage;
extern float g_synex_iq;
extern float g_synex_id;
extern float g_synex_speed_rpm;
// FireWater 发送一行 CSV;Synex 会按逗号拆成多通道曲线。
void Synex_UploadFireWater(void)
{
printf("%.2f,%.2f,%.2f,%.1f\n", g_synex_bus_voltage, g_synex_iq, g_synex_id, g_synex_speed_rpm);
}
// FireWater 是文本协议,建议放在 1 ms 到 10 ms 的低速状态任务里。
void Synex_FireWaterTask10ms(void)
{
Synex_UploadFireWater();
}
图片数据混合流
图片混合流不需要单独协议。设备端先发送一整帧图片包,再紧跟一帧普通波形数据即可;图片包里的 image_size 会告诉 Synex 精确取走多少图片字节,剩余字节会继续按当前协议解析。示例中的 27 表示 JPG,28 表示 PNG;串口 DMA 场景下,Synex_WriteBytes() 需要保证上一段发完再发下一段。
#include <stdint.h>
#include <stdio.h>
extern const uint8_t g_synex_jpg_bytes[];
extern const uint32_t g_synex_jpg_size;
extern float g_synex_iq;
extern float g_synex_id;
extern float g_synex_speed_rpm;
extern int Synex_WriteBytes(const uint8_t *data, uint32_t length);
// FireWater 图片包是 image 头行 + JPG/PNG 原始字节;后面可以继续追加普通 CSV 波形帧。
void Synex_UploadFireWaterImageAndWave(void)
{
char image_header[48];
char wave_line[64];
int image_header_length = snprintf(image_header, sizeof(image_header), "\nimage:0,%lu,-1,-1,27\n", (unsigned long)g_synex_jpg_size);
int wave_line_length = snprintf(wave_line, sizeof(wave_line), "%.3f,%.3f,%.1f\n", g_synex_iq, g_synex_id, g_synex_speed_rpm);
if (image_header_length <= 0 || image_header_length >= (int)sizeof(image_header)) return;
if (wave_line_length <= 0 || wave_line_length >= (int)sizeof(wave_line)) return;
(void)Synex_WriteBytes((const uint8_t *)image_header, (uint32_t)image_header_length);
(void)Synex_WriteBytes(g_synex_jpg_bytes, g_synex_jpg_size);
(void)Synex_WriteBytes((const uint8_t *)wave_line, (uint32_t)wave_line_length);
}
#include <stdint.h>
#include <string.h>
extern const uint8_t g_synex_jpg_bytes[];
extern const uint32_t g_synex_jpg_size;
extern float g_synex_iq;
extern float g_synex_id;
extern float g_synex_speed_rpm;
extern int Synex_WriteBytes(const uint8_t *data, uint32_t length);
// JustFloat 图片头由同步帧尾、5 个 int32 参数和 2 个连续帧尾组成,随后紧跟图片字节。
void Synex_UploadJustFloatImageAndWave(void)
{
const uint32_t tail = 0x7F800000u;
uint32_t image_header[8];
float wave_frame[4];
image_header[0] = tail;
image_header[1] = 0u;
image_header[2] = g_synex_jpg_size;
image_header[3] = 0xFFFFFFFFu;
image_header[4] = 0xFFFFFFFFu;
image_header[5] = 27u;
image_header[6] = tail;
image_header[7] = tail;
wave_frame[0] = g_synex_iq;
wave_frame[1] = g_synex_id;
wave_frame[2] = g_synex_speed_rpm;
memcpy(&wave_frame[3], &tail, sizeof(tail));
(void)Synex_WriteBytes((const uint8_t *)image_header, sizeof(image_header));
(void)Synex_WriteBytes(g_synex_jpg_bytes, g_synex_jpg_size);
(void)Synex_WriteBytes((const uint8_t *)wave_frame, sizeof(wave_frame));
}
CustomBinary 自定义二进制协议
CustomBinary 按协议编辑器发布的字段顺序解析固定长度帧。Header、Tail、Checksum 和大小端都由协议编辑器配置;下位机端直接使用自动生成的 synex_protocol_sender.h / synex_protocol_sender.c。业务代码只填充 Payload,并把底层 UART DMA 发送函数作为回调传给生成的 send_frame。
#include <stdint.h>
#include "synex_protocol_sender.h"
#include "usart.h"
extern UART_HandleTypeDef huart2;
extern float g_synex_phase_current;
extern float g_synex_bus_voltage;
extern float g_synex_motor_temp;
extern float g_synex_speed_rpm;
static SynexProtocolSenderFrame g_synex_protocol_frame;
static SynexProtocolSenderPayload g_synex_protocol_payload;
// 适配自动生成代码需要的底层发送回调;这里用 STM32 HAL UART DMA 举例。
int SynexProtocol_WriteBytes(const uint8_t *data, uint16_t length, void *user)
{
UART_HandleTypeDef *huart = (UART_HandleTypeDef *)user;
if (data == 0 || length == 0u || huart == 0) return -1;
return (int)HAL_UART_Transmit_DMA(huart, (uint8_t *)data, length);
}
// 填充自动生成的 Payload,然后交给 send_frame 统一完成组帧、校验和发送。
void Synex_UploadCustomBinary(void)
{
g_synex_protocol_payload.phase_current = g_synex_phase_current;
g_synex_protocol_payload.bus_voltage = g_synex_bus_voltage;
g_synex_protocol_payload.motor_temp = g_synex_motor_temp;
g_synex_protocol_payload.speed_rpm = g_synex_speed_rpm;
(void)synex_protocol_sender_send_frame(&g_synex_protocol_frame, &g_synex_protocol_payload, SynexProtocol_WriteBytes, &huart2);
}
// CustomBinary 适合固定字段的高速上报,可以放在 200 us 或 1 ms 调度任务里。
void Synex_CustomBinaryTask200us(void)
{
Synex_UploadCustomBinary();
}
RawData 原始数据模式
RawData 适合确认线路、波特率、端口和真实输出内容。它不会生成多通道曲线,建议用短文本把关键状态打出来;等链路稳定后,再切换到 FireWater、JustFloat 或 CustomBinary。
#include <stdio.h>
extern float g_synex_iq;
extern float g_synex_id;
extern float g_synex_speed_rpm;
// RawData 只用于观察原始文本,不参与曲线解析。
void Synex_UploadRawDataDebug(void)
{
printf("iq=%.3f, id=%.3f, speed=%.1f\n", g_synex_iq, g_synex_id, g_synex_speed_rpm);
}
// RawData 主要用于链路检查,周期不宜过高,避免文本日志刷屏。
void Synex_RawDataTask100ms(void)
{
Synex_UploadRawDataDebug();
}
个人工作台
个人工作台用于把实时观察、控制指令和现场诊断放在同一个页面。你可以按调试对象自由组合绘图、数值、仪表、姿态、图片、串口控制台、滑条、开关和模式选择控件,形成专属于当前设备的联调面板。
- 可添加控件:绘图、数值、仪表、姿态、图片、串口控制台、滑条、开关、模式选择。
- 常用操作:右键空白处添加控件,拖动控件移动位置,拖动边缘调整大小,支持复制、粘贴和批量删除。
- 布局方式:工作台使用 12 x 8 大栅格,每个大格继续细分为 8 x 8 小格,控件移动和缩放时会吸附到网格。
添加、选择和删除控件
在个人工作台空白区域右键,可以从菜单中添加控件;新控件会优先出现在右键所在位置。单击控件可以激活它,按住 Ctrl 单击可以加入或移出多选,拖动空白区域可以框选多个控件。选中控件后按 Delete 删除,输入框、下拉框和数值编辑框正在编辑时不会触发删除。
复制控件时,先选中目标控件并按 Ctrl + C,再把鼠标移动到希望放置的位置并按 Ctrl + V。粘贴出的控件会保留原控件配置,并生成新的控件 ID。
栅格布局与层级
个人工作台采用栅格化布局。当前页面按 12 列、8 行大栅格组织,每个大格再细分为 8 x 8 小格,因此控件既能保持整齐,也能做较细的尺寸调整。工作台允许控件重叠,最近操作的控件会移动到更靠前的层级。
顶部工具栏
- 新增页面:创建新的个人工作台页面,用于区分不同设备、不同实验或不同调试阶段。
- 开始 / 暂停:暂停或恢复实时绘图刷新,窗口聚焦时可用
Space切换,也可用全局快捷键Ctrl + Space切换。 - 自动 Y / 动态 Y:自动 Y 立即校准纵轴;动态 Y 会持续跟随可见数据范围。
- 复位视图:恢复完整 X 范围,并重新校准当前绘图视图。
- 清零 / 降采样:清空历史数据,或在大数据量场景下降低显示压力。
- X 光标同步:同步当前工作台内 YT 图的 X 光标,便于多图对齐观察。
- 保存 / 加载:保存或载入当前绘图数据,适合复盘短时间实验过程。
- 左右面板:显示或隐藏指令台、通道配置面板,让工作台给核心控件留出更多空间。
实时绘图控件
实时绘图控件用于观察一个或多个通道的高速波形。它支持 YT/XY 图、游标、FFT、截图和右键菜单配置,适合把关键变量放在同一个视图里分析。
性能状态显示:绘图区域会显示 FPS、点数等渲染状态信息,用于观察当前刷新和绘制压力。高通道数、大缓冲区、高 FPS 或高 MSAA 都会增加 CPU/GPU 负载,必要时可以开启降采样来保持交互流畅。
通道选择:在绘图控件顶部选择需要显示的通道,曲线名称和颜色会跟随右侧通道配置。一个绘图控件可以同时显示多条曲线,适合把同一组相关变量放在同一坐标系里比较。
时域 YT 图:默认模式是 YT 图,X 轴表示时间,Y 轴表示通道值。它适合观察电流、电压、速度、温度等随时间变化的信号。
XY 图:切换到 XY 图后,每条曲线可以选择一个 X 通道源,适合观察轨迹、相图、位置关系或两个变量之间的闭环关系。XY 图不参与时域 X 范围同步。
缩放和平移:在绘图区滚动鼠标滚轮会同时缩放 X/Y 方向;在 X 轴或 Y 轴刻度区域滚动时,只缩放对应轴。按住左键拖动可以平移当前视图。
X 光标:左键双击绘图区可以添加或移动 X 光标,用于读取某一时刻所有曲线的值。拖动 X 光标线可以调整位置。
Y 光标:按住 Ctrl 后左键双击可以添加或移动 Y 光标,用于标记目标值、阈值或对比某个固定幅值。
Tracer 标记:Tracer 用于在曲线上显示当前关注点和数值标签。右键菜单可以切换 Tracer 的标记样式,让它更适合不同密度和颜色的曲线。
自动 Y:顶部工具栏的自动 Y 会立即根据当前可见数据校准纵轴范围,适合数据范围突然变化后快速回到可读视图。
动态 Y:动态 Y 会持续跟随当前可见数据范围变化。它适合波形幅值变化较大但需要一直保持可读的场景,也可以在单个绘图控件的右键菜单里单独开关。
复位视图:复位视图会恢复当前绘图控件的完整 X 范围,并重新调整 Y 轴显示范围。视图被多次缩放、拖拽后,可以用它快速回到整体观察状态。
降采样:长时间运行或大缓冲区场景下,降采样可以减少实际绘制点数,降低显示压力。它不会改变原始缓存数据,只影响绘制负载。
X 光标同步:开启同步后,同一工作台内的 YT 绘图控件会同步 X 光标,适合多图排查同一时刻不同变量的状态。
截图复制:绘图控件支持复制当前主图截图。如果已经打开 FFT,也可以复制主图和 FFT 图的组合截图,便于粘贴到报告、聊天或问题记录中。
CSV 数据保存和加载:顶部工具栏可以保存当前绘图数据,也可以加载 CSV 数据进行离线查看。加载后可以复盘某次实验里的关键波形。
右键菜单功能:绘图控件的右键菜单集中放置显示方式、交互方式和截图工具,常用于临时调整某一个绘图控件的行为。
- 动态 Y 轴:选择“是”或“否”,控制当前绘图控件是否持续自动调整 Y 轴。
- 坐标模式:在
YT图和XY图之间切换。 - X 通道源:在 XY 图中为曲线选择 X 轴数据来源。
- X 轴滚动条:控制主图 YT 模式下是否显示 X 轴浮动滚动条。
- 绘图模式:可选择线图、点图或点线图。线图适合连续波形,点图适合离散采样,点线图适合同时观察趋势和采样点。
- Tracer 标记:可选择十字形 + 水平、圆圈 + 斜线、菱形 + 斜线三种标记样式。
- X 轴单位:可选择秒
s、毫秒ms或微秒us。 - 滚轮速度:可选择慢速 10%、中速 20% 或快速 35%,用于改变鼠标滚轮缩放灵敏度。
- 光标取值方式:可选择线性插值或最近点。线性插值适合平滑读取,最近点适合严格按采样点读取。
- 隐藏顶部栏:隐藏当前绘图控件顶部的通道和 FFT 配置区域,让曲线区域获得更多空间。
- 显示顶部栏:恢复被隐藏的顶部配置区域。
- 复制截图:复制当前主图截图。
- 复制所有截图:同时复制主图和 FFT 图截图。
FFT 通道:FFT 区域的通道下拉框用于选择参与频域分析的通道。通常选择当前最关心的一条电流、速度、振动或误差信号。
FFT 起始时间:起始时间决定从哪一段时域数据开始截取。你也可以拖动主图上的高亮分析窗口来调整起点。
FFT 分析区域:开启 FFT 后,实时绘图区会显示一段高亮分析区域。按住 Alt + 鼠标左键拖动这段区域,可以直接调整参与 FFT 的时域窗口。
FFT 周期数:周期数决定参与计算的数据长度。周期数越多,频率分辨率通常越高,但会使用更长的一段时域数据。
FFT 基波频率:基波频率用于标定分析窗口和频域参考,适合电机控制、周期振动和固定频率激励场景。
计算一次 FFT:点击计算按钮后,会按当前通道、起始时间、周期数和基波频率计算一次频谱,并显示在 FFT 绘图区。
实时 FFT:打开实时 FFT 后,频谱会跟随新数据刷新。它适合观察频率成分是否随控制状态变化,但计算负载会高于手动计算。
显示 / 隐藏 FFT:可以临时隐藏 FFT 绘图区,只保留主图;需要频域分析时再显示出来。
FFT 图右键菜单:FFT 绘图区也支持样式、Tracer、滚轮速度和截图相关操作,方便频域图单独查看和导出。
数值控件
数值控件用于突出显示单个通道的当前值,适合放置电流、电压、转速、温度等关键变量。它会跟随通道配置中的名称和颜色变化,便于和曲线颜色保持一致。
- 可以绑定一个实时通道。
- 可以配置标题、单位和显示精度。
- 适合和仪表、开关、滑条组合成紧凑控制区。
仪表控件
仪表控件用于把单个通道显示为圆形表盘,适合转速、母线电压、温度、占空比等有明确范围的变量。配置时通常需要选择通道,并设置标题、最小值、最大值、单位和小数位。
- 适合显示范围固定、需要快速判断是否超限的变量。
- 表盘颜色会尽量贴近绑定通道颜色。
- 建议给仪表设置清晰的单位和范围,避免现场误读。
姿态控件
姿态控件用于显示设备或机构的三维姿态,适合 IMU、云台、电机执行机构和机器人关节调试。它可以从欧拉角或四元数通道获取姿态,也可以配置模型文件、模型颜色、透明度、线框、坐标轴和校准参数。
- 输入模式可按工程数据源选择欧拉角或四元数。
- 支持选择 3D 模型文件,当前可加载
STL、glTF和GLB;没有选择模型或模型加载失败时,会回退显示默认立方体。 STL适合单色结构件预览,可通过控件配置模型颜色和透明度;glTF/GLB适合带材质、贴图或顶点颜色的 3D 彩色模型渲染。- 可配置模型外观、原始轴显示和模型坐标系校准,帮助区分设备坐标、模型坐标和世界坐标。
- 校准旋转和平移适合修正传感器安装方向。
图片控件
图片控件用于显示协议中的图片帧,适合摄像头、视觉算法、中间处理结果或设备截图。右键图片控件可以选择图片通道、填充方式、图片特效和名称显示方式。
- 同一条数据流可以混合图片帧和普通波形帧。
- 填充方式用于控制图片保持比例、裁切或铺满控件区域,常用模式包括等比完整显示、裁剪填充和拉伸填满。
- 图片特效可在右键菜单中实时切换,适合快速观察视觉算法结果、突出边缘或增强细节。
- 当前特效包括黑白、复古色、色调分层、暗角、像素化、卡通描边、边缘检测、浮雕、锐化、点阵化、边缘辉光、色彩隔离、移轴模糊、波普色彩和波纹扭曲。
- 图片名显示适合多路图片调试时快速确认来源。
串口控制台控件
串口控制台控件用于查看和发送原始串口数据,适合协议 bring-up、异常排查和文本日志观察,可以在文本/HEX、时间戳、解码、ANSI、RX/TX 显示和日志记录之间切换。
- 大量数据连续刷屏时依然保持流畅显示,便于观察高频日志和突发异常。
- 接收内容按真实到达顺序显示,方便回看每一段原始输入和输出。
- 适合长时间压力测试,不需要频繁清屏也能继续追踪后续数据。
- HEX 模式适合检查二进制协议帧。
- 时间戳适合定位设备输出节奏和异常间隔。
- 日志记录适合保存现场调试过程,尤其适合复盘偶发异常或长时间压力测试。
滑条控件
滑条控件用于把连续数值发送给设备,适合速度给定、电流给定、位置给定和占空比调节。配置时通常需要设置显示名称、数值范围、步进、初始值、命令模板和发送方式。
- 命令模板可以把当前滑条值填入串口指令。
- 适合绑定指令台中的已有指令,统一维护指令内容。
- 建议给危险控制量设置保守范围,并在设备端继续做限幅保护。
开关控件
开关控件用于发送双态控制命令,适合使能/失能、运行/停止、闭环/开环等场景。配置时可以设置开关名称、两种状态的显示文本、状态值、命令内容、校验方式和发送目标。
- 适合现场常用的二值控制动作。
- 配置页面里的“状态文本”决定按钮显示什么,例如
ON;OFF会分别显示选中态和未选中态。 - 配置页面里的“状态值”决定实际发送给命令模板的值,例如
1;0会把选中态映射为1,未选中态映射为0。 - 发送内容模板使用当前状态值作为参数,默认 Abc 模板类似
setToggle:%d\n;如果切换为 HEX 模式,也可以把状态值填入结构化十六进制帧。 - “状态文本”和“状态值”都使用英文分号分隔,并且数量必须一一对应。
- 可以配置重复发送次数,提高弱链路下的命令到达概率。
- 可以绑定指令台中的指令,避免同一条指令在多个位置重复维护。
模式选择控件
模式选择控件用于在多个离散模式之间切换,适合控制模式、测试阶段、运行档位和算法分支选择。每个模式都可以配置显示名称、模式值和对应命令。
- 比多个独立开关更适合互斥模式选择。
- 配置页面里的“模式文本”决定分段按钮上显示的名称,例如
idle;ready;run会生成三个可选模式。 - 配置页面里的“模式值”决定每个模式切换时传给发送模板的值,例如
0;1;2会让idle发送0、ready发送1、run发送2。 - “模式文本”和“模式值”都使用英文分号分隔,并且项数必须一致;它们按顺序一一对应。
- 发送内容模板使用当前模式值作为参数,默认 Abc 模板类似
setMode:%d\n;HEX 模式下也可以把模式值写入十六进制命令帧。 - 可以开启“同状态重发”,再次点击当前模式时也重新发送当前模式值。
- 和指令台绑定后,可以把模式切换纳入统一指令库管理。
指令台
指令台用于维护可复用的设备控制指令。它不是临时输入框,而是一个可以长期保存、分组、排序、重复发送并和个人工作台控件绑定的指令库,适合把使能、停止、清故障、设置目标值、切换模式等现场操作集中管理。
指令和指令组
指令台由指令和指令组组成。指令是一条具体发送内容,指令组用于把多条指令按顺序组织起来,例如“进入调试模式”“启动实验流程”“退出并复位”。
- 单条指令:保存名称、发送内容、校验方式、重复次数和发送间隔。
- 指令组:可以包含指令和子指令组,发送时会按列表顺序依次执行。
- 展开和折叠:顶部按钮可以全部展开或全部折叠,适合在大量指令中快速整理视图。
- 拖动排序:指令和指令组可以拖动调整顺序,也可以移动到不同组内。
- 复制和删除:常用指令可以复制后微调;删除指令组时会同时删除组内内容。
发送内容模板
每条指令都可以在 Abc 和 HEX 两种模式之间切换。Abc 适合文本指令和串口调试协议,HEX 适合二进制帧、寄存器写入和带参数的结构化指令。
- Abc 模式:支持普通文本、
\r、\n、[crc],也支持%d、%03d、%u、%x、%X、%.3f等数值占位符。 - HEX 模式:支持十六进制字节和占位符混写,例如
[i8]、[u8]、[i16]、[u16]、[i32]、[u32]、[f32]、[crc]。 - 模式独立保存:Abc 和 HEX 内容各自保存,切换模式时不会把文本指令强行转换成二进制指令。
- 参数来源:直接点击指令台发送时适合固定指令;绑定滑条、开关或模式选择后,占位符会使用控件传入的当前值。
校验和 CRC
指令台可以在发送内容中插入校验结果。你只需要在模板中写入 [crc],再选择校验类型和校验范围,Synex 会在发送前生成最终字节内容。
- 校验类型:支持 Sum8、Sum16、Xor8、CRC8、CRC8-Maxim、CRC16-Modbus、CRC16-CCITT、CRC16-XModem。
- 校验占位前:只对
[crc]前面的内容计算校验,适合常见的payload + crc + tail指令。 - 全帧去校验:对除校验字段自身之外的整帧计算校验,适合校验字段位于中间或固定位置的二进制帧。
- 输出形式:Abc 模式会插入可打印校验文本;HEX 模式会插入真实校验字节。
重复发送和顺序发送
单条指令和指令组都可以配置重复次数和发送间隔。单条指令用于重复发送同一个指令,指令组用于按顺序执行一组动作。
- 重复次数:
0表示发送一次,1表示发送两次,-1表示无限重复,直到再次点击停止。 - 发送间隔:控制重复发送或组内相邻指令之间的等待时间。
- 再次点击停止:正在发送的同一条指令或指令组,再次点击会停止当前任务。
- 组内跳过:某些指令可以设置为组发送时跳过,但手动点击单条指令时仍然可用。
- 发送前校验:如果模板格式错误,或需要控件参数但当前没有参数,Synex 会阻止发送并给出提示。
绑定个人工作台控件
滑条、开关和模式选择控件可以绑定指令台中的某条指令。绑定后,指令内容、校验、重发参数由指令台统一维护,控件只负责提供当前参数。
- 滑条绑定:滑条值可以填入 Abc 的数值占位符,或写入 HEX 模板中的
[f32]、[i16]等参数占位符。 - 开关绑定:开关的状态值作为参数传入绑定指令,适合
0/1、ON/OFF、使能/失能类控制。 - 模式选择绑定:当前模式值作为参数传入绑定指令,适合运行模式、测试阶段和控制档位切换。
- 集中维护:指令重命名后,绑定控件的显示会同步更新;指令被删除后,绑定会自动失效并回到控件自身发送逻辑。
导入、导出和清空
指令台可以导出为 JSON,用于项目备份、团队共享或跨电脑迁移。导入 JSON 会替换当前指令台内容,清空全部指令也会删除当前所有指令和指令组,这两类操作都会在执行前提醒确认。
- 导出 JSON:保存当前全部指令、指令组、顺序、发送内容和发送参数。
- 导入 JSON:读取
command-panel格式文件,并替换当前指令台配置。 - 清空全部:用于重新整理项目指令库,执行前需要确认。
协议编辑器
协议编辑器用于设计和发布 CustomBinary 自定义二进制协议。你可以把一帧数据拆成帧头、数据、校验、帧尾等字段积木,逐项配置字节数、字节序、缩放、偏移和曲线输出;发布后,连接页即可选择这个协议解析真实设备数据。
字段组件库
左侧字段组件库提供常用帧结构积木。点击字段即可追加到当前协议,之后可以在时间轴中选择并配置具体属性。
- Header:固定帧头,用于帮助解析器在连续字节流中同步一帧的开始,例如
AA 55。 - FrameId:帧类型标识,适合一个链路后续扩展多种帧格式时保留结构位置。
- Length:长度字段,通常用于描述整帧长度或数据区长度;当前更适合作为结构占位。
- Data:业务数据字段,可配置整型、浮点或原始字节,并可勾选输出到曲线。
- Checksum:校验字段,用于验证帧内容完整性,推荐放在数据字段之后、帧尾之前。
- Tail:固定帧尾,用于辅助判断一帧结束,例如
0D 0A。 - Skip:跳过字段,适合预留字节、保留位或暂时不关心的数据段。
帧结构时间轴
中间时间轴按字段顺序展示当前协议的完整帧布局。字段从左到右排列,顺序就是解析器读取字节的顺序;拖动字段可以调整同一协议内的字段顺序,拖动协议行可以调整多个协议在工作区中的排列。
- 字段选择:点击时间轴中的字段后,右侧属性面板会切换到该字段。
- 字段拖动:在同一协议行内拖动字段,可以重新排序帧头、数据、校验和帧尾。
- 协议拖动:当工作区里加载了多个协议时,可以拖动协议行调整显示顺序。
- 发布状态:时间轴会提示当前协议是否已经发布,便于区分“正在编辑的草稿”和“连接页正在使用的版本”。
字段属性配置
右侧字段属性面板用于决定某段字节的含义。Data 字段通常最常用:你可以设置字段名、类型、字节数、大小端、缩放、偏移,并选择是否输出到曲线。
- 字段名:决定曲线通道和生成代码中的变量命名,建议使用清晰的英文或拼音标识。
- 角色:决定字段在帧中的语义,例如数据、校验、帧头或帧尾。
- 类型和字节数:支持
bytes、int、uint、float;浮点字段固定 4 字节。 - 字节序:多字节整数和浮点字段可选择 little 或 big,单字节字段不受影响。
- 固定 Hex:Header 和 Tail 使用固定 Hex 描述帧边界。
- 校验配置:Checksum 字段支持
sum8、sum16、xor8、crc8、crc8-maxim、crc16-modbus、crc16-ccitt、crc16-xmodem,并可选择校验起点和终点。 - 缩放和偏移:设备发送原始值时,Synex 可按
物理值 = 原始值 * 缩放 + 偏移转换显示。 - 输出到曲线:勾选后,该 Data 字段会成为可绘制通道;不勾选的字段只参与解析或结构占位。
协议属性与多协议工作区
协议属性用于配置协议名称和代码生成模式。协议编辑器允许在同一个工作区中加载多个协议,适合对比不同版本、临时修改旧协议,或把多个设备的协议放在一起维护。
- 新建协议:创建一条新的协议行,从默认模板开始编辑。
- 复制协议:选中协议后点击复制或按
Ctrl + C,再粘贴会生成一个新的_Copy协议副本。 - 复制字段:选中字段后复制,再在目标协议中粘贴,可快速复用相同字段配置;粘贴字段会生成新的字段 ID。
- 删除协议:普通删除只会把协议从当前工作区移除;删除已发布协议会同时删除本地协议 JSON 文件。
- 导入导出:协议可以导入到当前工作区,也可以导出为 JSON,便于备份、共享和版本管理。
发布与连接页使用
编辑完成后,需要点击发布,当前协议才会写入本地协议库并同步给连接页。连接页选择对应 CustomBinary 协议后,解析器会按已发布的字段顺序和字段属性处理收到的数据。
- 修改后重新发布:字段顺序、校验范围、缩放或输出通道变化后,都应重新发布。
- 先用样本帧验证:真实设备接入前,建议先用固定样本帧检查帧头、长度、大小端、校验范围和帧尾。
- 曲线输出检查:如果连接后没有曲线,优先确认 Data 字段是否勾选了输出到曲线。
固件代码生成
协议编辑器可以根据当前协议生成下位机发送侧 .h / .c 代码。生成代码负责组帧、大小端处理和校验计算,业务代码只需要填充 Payload,并把底层 UART、USB CDC 或网络发送函数作为回调传入。
- 生成前校验:代码生成会检查协议是否适合发送侧模板,例如是否存在数据字段、校验字段数量是否合理。
- 代码生成模式:Classic 模式更通用;Struct 模式更接近结构体直发,但对字段布局要求更严格。
- 工程接入:生成后把文件加入固件工程,在周期任务中填充 Payload 并调用发送函数即可。
CAN 总线分析
CAN 模块面向 CAN/CAN FD 总线调试,采用和个人工作台一致的工作区形态。用户可以创建多个 CAN 工作区,并在每个工作区内自由添加、拖动和调整接收、发送、手动发送、绘图等控件,把总线监控、DBC 信号发送和实时分析放在同一个调试上下文里。
支持的 CAN 硬件
当前 CAN 配置页支持 Kvaser、Vector、Peak / PCAN、创芯 和 ZLG 设备,并提供 Classic CAN 与 CAN FD 两种模式选择。不同硬件的驱动、通道数量、波特率范围和 FD 能力不同,实际连接前建议先确认驱动已经安装并能被系统识别。
- Kvaser:支持 Classic CAN 常用波特率;CAN FD 软件路径已接入,需要使用支持 FD 的硬件通道,FD 实物兼容性建议结合现场设备验证。
- Vector:支持 Classic CAN 和 CAN FD,Classic 模式使用仲裁域波特率,FD 模式使用仲裁域和数据域参数。
- Peak / PCAN:支持 Classic CAN 常用波特率;CAN FD 需要使用支持 FD 的 PCAN 设备,并配置 Clock、仲裁域和数据域时序参数。
- ZLG:支持 Classic USBCAN 常用波特率;USBCANFD 软件路径已接入,FD 模式建议结合具体设备进行现场验证。
- 创芯:当前按 Classic CAN 使用,适合 8 字节以内的常规 CAN 报文调试。
DBC 加载与解析
CAN 页面支持加载 DBC 文件,也可以把 DBC 文件拖入页面解析。DBC 加载后,Synex 会按报文和信号定义解析接收到的总线数据,并把信号以树形结构展示出来,方便直接查看物理值、选择信号绘图,或在发送控件里按物理量编辑报文。
- 报文树:按 DBC 中的 Message 和 Signal 组织层级,便于快速定位某个控制器或某个信号。
- 物理值解析:按 DBC 的位偏移、长度、字节序、缩放系数、偏移量和单位把原始字节转换为可读信号。
- 跨控件复用:同一份 DBC 可同时用于接收解码、信号发送和实时绘图,减少重复配置。
CAN 接收控件
CAN 接收控件用于观察实时总线报文。加载 DBC 后,接收控件会把报文按照 DBC 结构展开,既可以看原始报文,也可以直接看解码后的信号值,适合做联调时的总线状态看板。
- 实时接收:连接 CAN 设备后持续接收总线报文,并刷新当前报文状态。
- DBC 树形展示:按报文和信号层级展示解码结果,便于在大量 ID 中快速找到目标信号。
- 信号观测:适合观察电机控制器状态、BMS 状态、车身节点状态和传感器物理量。
CAN 发送控件
CAN 发送控件用于按 DBC 组织报文发送。用户选择要发送的 DBC 报文后,可以在信号级别编辑物理值,由 Synex 根据 DBC 自动打包为 CAN 数据帧,避免手工计算位域、大小端和缩放系数。
- DBC 报文发送:按 DBC 报文定义选择发送对象,编辑信号物理值后自动生成数据帧。
- 周期触发:适合发送心跳、控制命令、状态保持类报文。
- 按键触发:适合临时发送启动、停止、清故障、标定切换等离散命令。
- 变化触发:当信号值被修改时立即发送,适合调参和交互式控制。
- 状态恢复:重新加载或切换页面时,可以恢复常用发送任务的配置状态。
发送信号生成器
信号生成器用于让某个发送信号按规则自动变化,适合做阶跃响应、扫值测试、边界测试和控制链路验证。配置完成后,CAN 发送控件会在发送任务运行时实时计算信号值,并按 DBC 打包到对应报文里。
- 自动激励:把手动输入信号变成随时间变化的测试输入,减少重复调参操作。
- 和周期发送联动:生成器值会跟随发送周期更新,适合构造连续变化的目标转速、电流指令、扭矩指令等。
- 保留人工覆盖:不需要自动变化的信号仍可保持手动输入值,只让指定信号启用生成器。
CAN 手动发送控件
CAN 手动发送控件不依赖 DBC,适合快速验证硬件连接、发送临时原始帧,或调试还没有整理成 DBC 的私有协议。用户可以直接填写 ID、DLC 和数据字节,并选择单次、周期或按键触发发送。
- 原始帧发送:直接编辑 CAN ID、帧格式、DLC 和数据内容。
- Classic / FD 场景:Classic CAN 使用常规 8 字节以内数据;CAN FD 场景可按设备能力配置更长 DLC。
- 临时调试:适合驱动刚接入、DBC 尚未准备好,或需要快速复现某个原始报文时使用。
CAN 绘图控件
CAN 绘图控件用于把 DBC 信号直接送入实时绘图区。它适合观察控制目标、反馈量、状态量之间的动态关系,也可以把多个信号放在同一工作区中和接收、发送控件一起联动分析。
- 信号选择:从 DBC 信号树中选择要绘制的物理量,不需要手动换算原始字节。
- 多图观察:支持多图、多信号组合观察,适合同时看目标值、反馈值和状态标志。
- 暂停与游标:暂停后可结合游标读取关键时刻的信号值,方便定位瞬态问题。
- X 轴单位切换:可按分析习惯在时间或采样序列视角下观察 CAN 信号变化。
CAN 报文录制为 MDF
CAN 页面支持把总线数据录制为 MDF,适合把实车、台架或长时间联调过程保存下来,再进入 MDF 离线回放流程做复盘、截图和报告整理。录制前建议确认 DBC、硬件通道和目标保存路径,避免长时间测试结束后发现信号上下文不完整。
MDF 离线回放
MDF/MF4 模块用于离线分析标定和测试数据。你可以加载文件、选择信号、分组显示,并将关键波形截图用于报告。
AI 助手连接 / MCP
Synex 支持通过 MCP 让外部 AI 连接正在运行的应用。开启后,AI 会通过 SynexMcpServer.exe 连接本机 Synex,并访问当前 UI 中的真实指令面板、协议编辑器和个人工作台;关闭后,本机发现文件会被删除,外部 AI 无法继续连接。
当前 MCP 能力
MCP 开启后,外部 AI 不是简单读取静态文件,而是连接正在运行的 Synex UI。它可以读取当前界面状态,也可以在你确认后修改真实工作区配置。
- 连接诊断:调用
app_ping检查 Synex MCP 是否连通。Synex 重启、AI 助手连接被关闭,或 token 刷新后,需要重新启动 MCP server 再连接。 - 指令面板读取:读取完整命令树,或按 id 读取单个命令、命令组,用于让 AI 理解当前已有控制指令。
- 指令面板编辑:校验即将导入的 JSON,预览新增、修改、删除、移动等修改内容,并在确认后应用到正在运行的指令面板。
- 协议编辑器读取:读取协议库、协议行和字段,查询字段角色、字段属性、校验类型和可用配置项。
- 协议编辑器修改:新增、删除、修改协议和字段,调整字段顺序,导入协议 JSON,发布协议,或删除已经发布的协议。
- 协议辅助生成:分析协议帧布局,生成示例帧 hex,并根据当前协议生成下位机侧 C 代码。
- 个人工作台读取:读取页面列表、控件布局、单个控件配置、控件类型和最小尺寸,方便 AI 理解当前调试面板结构。
- 个人工作台编辑:新增或重命名页面,调整页面顺序,新增、复制、删除、移动控件,修改控件尺寸、配置和层级。
- 自动构建页面:根据结构化描述自动创建一个新的个人工作台页面,适合快速生成某个设备或实验项目的调试面板草稿。
Claude Code 接入
如果使用 Claude Code,可以把发布包中的 SynexMcpServer.exe 注册为 stdio server。下面路径按安装目录举例,实际使用时替换为你本机的 Synex 安装路径。
claude mcp add --scope user --transport stdio synex -- "D:\Synex_v3.0.5\mcp\SynexMcpServer.exe"
claude mcp list
claude mcp get synex
如果后续不再需要让 Claude Code 连接 Synex,可以单独执行卸载命令。
claude mcp remove synex --scope user
Codex 接入
Codex CLI 和 Codex IDE 扩展共用 MCP 配置。你可以用命令行添加,也可以把同等配置写入 ~/.codex/config.toml 或项目内受信任的 .codex/config.toml。
codex mcp add synex -- "D:\Synex_v3.0.5\mcp\SynexMcpServer.exe"
[mcp_servers.synex]
command = 'D:\Synex_v3.0.5\mcp\SynexMcpServer.exe'
startup_timeout_sec = 10
tool_timeout_sec = 60
如果使用 Codex 桌面端,验证时不需要再打开命令行。先重启 Codex 或刷新当前会话,让它重新读取 MCP 配置;然后在 Codex 的 MCP/工具列表里确认能看到 synex,最后让 Codex 调用 app_ping。
1. 确认 Synex 顶部工具栏已经开启“AI 助手连接”。
2. 重启 Codex 桌面端,或刷新当前 Codex 会话。
3. 打开 Codex 的 MCP/工具列表,确认能看到 synex。
4. 对 Codex 说:请调用 Synex MCP 的 app_ping 检查连接。
VS Code Copilot 接入
VS Code 的 Copilot Agent 模式可以读取 MCP server。建议使用用户级配置:在命令面板运行 MCP: Open User Configuration,把下面内容写入 VS Code 打开的用户配置文件。
{
"servers": {
"synex": {
"command": "D:\\Synex_v3.0.5\\mcp\\SynexMcpServer.exe"
}
}
}
验证 VS Code Copilot 是否安装成功时,先从命令面板查看 MCP server 状态,再在 Copilot Chat 的工具选择里确认 Synex 工具可用。最后同样调用 app_ping,用它确认当前运行中的 Synex 已经开启 AI 助手连接。
1. 打开命令面板,运行 MCP: List Servers。
2. 找到 synex,确认它可以启动且没有报错。
3. 打开 Copilot Chat 的 Agent 模式,进入 Configure Tools,确认能看到 synex 的工具。
4. 对 Copilot 说:请调用 Synex MCP 的 app_ping 检查连接。
配置完成后,先在 Synex 顶部工具栏开启“AI 助手连接”,再让外部 AI 调用 app_ping 检查连接。若 Synex 重启或重新开启连接,token 会重新生成;长期运行的 AI 客户端遇到连接失败时,重启 MCP server 通常即可恢复。
校验算法说明
Synex 中的指令台、连接页发送、协议编辑器和 CustomBinary 解析共用同一套校验算法。下位机如果需要解析 Synex 下发的指令,或者要手写与上位机一致的协议收发代码,可以按本节规则实现。
支持的算法
| 名称 | 长度 | 计算规则 |
|---|---|---|
sum8 |
1 字节 | 参与字节逐字节相加,结果保留低 8 位。 |
sum16 |
2 字节 | 参与字节逐字节相加,结果保留低 16 位。 |
xor8 |
1 字节 | 初值 0x00,参与字节逐字节异或。 |
crc8 |
1 字节 | CRC-8,非反射,高位先算,初值 0x00,多项式 0x07。 |
crc8-maxim |
1 字节 | CRC-8/MAXIM,反射算法,初值 0x00,反射多项式 0x8C。 |
crc16-modbus |
2 字节 | CRC-16/MODBUS,反射算法,初值 0xFFFF,反射多项式 0xA001。 |
crc16-ccitt |
2 字节 | CRC-16/CCITT-FALSE 风格,非反射,高位先算,初值 0xFFFF,多项式 0x1021。 |
crc16-xmodem |
2 字节 | CRC-16/XMODEM,非反射,高位先算,初值 0x0000,多项式 0x1021。 |
参与校验的数据范围
- 连接页和普通发送:
payload参与校验,校验值紧跟payload,最后再追加tail,整体顺序是payload + checksum + tail。 - 指令台:只有发送内容里写了
[crc]才会插入校验。校验范围可以选择“校验占位前”,也可以选择“全帧去校验”。 - CustomBinary:校验范围由协议编辑器中 Checksum 字段的“校验起点”和“校验终点”决定,Checksum 字段自身不参与计算。
- 文本命令解析:如果一行文本末尾 2 个字符可以作为 CRC8 HEX,Synex 会把前面的文本作为数据区计算
crc8。
校验结果写入方式
- 1 字节校验:写入校验值低 8 位。
- 2 字节二进制校验:小端时低字节在前,大端时高字节在前。
- 文本模式校验:写入大写 ASCII HEX 文本。例如校验字节
0xA5会发送两个字符A5。 - 指令台 Abc / HEX:Abc 模式中的
[crc]插入可打印 HEX 文本;HEX 模式中的[crc]插入原始校验字节。
下位机 C 参考实现
下面的实现按 Synex 固件代码生成器中的算法整理。若你使用协议编辑器直接生成 CustomBinary 发送代码,生成文件里已经包含对应校验函数;只有在下位机需要手写解析 Synex 下发指令或自定义接收逻辑时,才需要复制这些函数。
#include <stdint.h>
static uint16_t Synex_CheckSum8(const uint8_t *data, uint16_t length)
{
uint8_t sum = 0u;
for (uint16_t index = 0u; index < length; ++index)
{
sum = (uint8_t)(sum + data[index]);
}
return sum;
}
static uint16_t Synex_CheckSum16(const uint8_t *data, uint16_t length)
{
uint16_t sum = 0u;
for (uint16_t index = 0u; index < length; ++index)
{
sum = (uint16_t)(sum + data[index]);
}
return sum;
}
static uint16_t Synex_CheckXor8(const uint8_t *data, uint16_t length)
{
uint8_t value = 0u;
for (uint16_t index = 0u; index < length; ++index)
{
value ^= data[index];
}
return value;
}
static uint16_t Synex_CheckCrc8(const uint8_t *data, uint16_t length)
{
uint8_t crc = 0x00u;
for (uint16_t index = 0u; index < length; ++index)
{
crc ^= data[index];
for (uint8_t bit = 0u; bit < 8u; ++bit)
{
crc = (crc & 0x80u) ? (uint8_t)((crc << 1) ^ 0x07u) : (uint8_t)(crc << 1);
}
}
return crc;
}
static uint16_t Synex_CheckCrc8Maxim(const uint8_t *data, uint16_t length)
{
uint8_t crc = 0x00u;
for (uint16_t index = 0u; index < length; ++index)
{
crc ^= data[index];
for (uint8_t bit = 0u; bit < 8u; ++bit)
{
crc = (crc & 0x01u) ? (uint8_t)((crc >> 1) ^ 0x8Cu) : (uint8_t)(crc >> 1);
}
}
return crc;
}
static uint16_t Synex_CheckCrc16Modbus(const uint8_t *data, uint16_t length)
{
uint16_t crc = 0xFFFFu;
for (uint16_t index = 0u; index < length; ++index)
{
crc ^= data[index];
for (uint8_t bit = 0u; bit < 8u; ++bit)
{
crc = (crc & 0x0001u) ? (uint16_t)((crc >> 1) ^ 0xA001u) : (uint16_t)(crc >> 1);
}
}
return crc;
}
static uint16_t Synex_CheckCrc16Ccitt(const uint8_t *data, uint16_t length)
{
uint16_t crc = 0xFFFFu;
for (uint16_t index = 0u; index < length; ++index)
{
crc ^= (uint16_t)(data[index] << 8);
for (uint8_t bit = 0u; bit < 8u; ++bit)
{
crc = (crc & 0x8000u) ? (uint16_t)((crc << 1) ^ 0x1021u) : (uint16_t)(crc << 1);
}
}
return crc;
}
static uint16_t Synex_CheckCrc16Xmodem(const uint8_t *data, uint16_t length)
{
uint16_t crc = 0x0000u;
for (uint16_t index = 0u; index < length; ++index)
{
crc ^= (uint16_t)(data[index] << 8);
for (uint8_t bit = 0u; bit < 8u; ++bit)
{
crc = (crc & 0x8000u) ? (uint16_t)((crc << 1) ^ 0x1021u) : (uint16_t)(crc << 1);
}
}
return crc;
}
static void Synex_WriteU16Le(uint8_t *dest, uint16_t value)
{
dest[0] = (uint8_t)(value & 0x00FFu);
dest[1] = (uint8_t)((value >> 8) & 0x00FFu);
}
static void Synex_WriteU16Be(uint8_t *dest, uint16_t value)
{
dest[0] = (uint8_t)((value >> 8) & 0x00FFu);
dest[1] = (uint8_t)(value & 0x00FFu);
}
常见问题
连接成功但没有数据显示
先确认设备确实在发送数据,再检查协议类型、波特率或网络端口。若协议不确定,可先切换到 RawData 观察原始数据。
波形刷新卡顿
降低绘图刷新频率、减少同时显示通道数,或开启更适合当前机器的降采样策略。高吞吐场景也建议使用二进制协议。
自定义协议解析失败
重点检查帧头帧尾、字节序、字段长度、缩放系数和校验算法。协议编辑完成后建议用固定样本帧先验证。
反馈与支持
如果你希望补充新的硬件适配、协议模板或示例工程,可以在项目页面提交反馈。反馈时请尽量附带软件版本、连接方式、协议配置和复现步骤。