背景故事
上大学一直在划水,刚毕业时几乎啥也不会,是大佬的这个库拯救了我。
SCPI 是一种字符串解析协议。刚工作时,点完灯开完串口,就让我实现 SCPI 协议。那时还很菜,花了两周时间才把这个协议库开起来。
这个库中的内容真的特别丰富,也没有很动态的指针,基本上都是绑定性质的"静态"指针,哪怕 C 语言不怎么样的我也可以慢慢看得懂。
在慢慢使用大约两个月后,其中的大部分内容都浏览过,C 语言也正式入门了,
而且后续的应届生,我也是让他们先看这个库。
源码地址在这里
这个代码库的优势
Note
- 这是一个纯粹的协议解析库,与硬件并非强关联,需要关注的 port 也仅仅是数据流入和数据流出。非常迅速就可以使用起来(哪怕是 CodeBlocks 或 DEV-C++ 这样的学习环境)。
- 这是一个能胜任业务功能的库,SCPI 协议解析所需的所有功能或机制它都可以胜任,学习后的应用场景非常广,不会白白学习。
- 这是一个稳健的库,我目前还没有在这个库中发现致命 bug。举个反例,最近期望移植和修改的 freemodbus 库,其中就存在致命 bug 以及大大小小的设计缺陷。
- 这是一个相对简单的库,比起 rtos 内核、网络库、文件系统库等等,这个库几乎可以称得上非常易懂了,只要花时间,就能从其中学到 面向对象、宏翻译、宏条件编译、回调绑定、字符处理 等等 C 语言的常用语法及设计。
应该看什么
由于是要写给 C 语言入门级选手的,哪怕这个库的结构如此简单,也依然需要介绍一下。整个库只有两个文件夹如下
examples其中是一些示例,也是我们期望将库用起来首先要看的。libscpi其中就是所有的库源码。在这个文件夹下有test文件夹,是带有 main 入口的单元测试,实际工程中不必引入libscpi/test文件夹的源码。

image-20241205131859389
在examples 中建议重点查看如下两个文件夹
examples/common 下是例程所支持的指令表,以及对应指令的回调,其中可以学习一些库 API 的用法
examples/test-parser 下是最简单例程的 main 入口,以及如 SCPI_Write()、SCPI_Error()等接口函数的定义,还有少量指令的回调,在指令表中都可以找到绑定。

image-20241205132043166
大致使用流程如下
- 使用
SCPI_Init()函数绑定对象、设备 ID、各种 port 函数 - 使用
SCPI_Input()函数输入一条所支持的完整指令,库自动触发指令回调,自动使用 port 函数发送信息
优秀的库,使用就是如此简单。
一些库 API 介绍
在官方文档中实际上也有 API 介绍 ,但是几乎没有有效信息,毕竟官方也只有一个人,可参考。
About · SCPI parser (jaybee.cz)
Scpi-Def.c 中声明了整个 SCPI 处理过程中用到的接口参数 scpi interface
指令参数处理 API
scpi_bool_t SCPI_ParamErrorOccurred(scpi_t* context);
用于处理函数中,检测处理函数时是否产生错误,若存在错误则应立即停止处理函数。
scpi_bool_t SCPI_ParamInt32(
scpi_t* context,
int32_t* value,
scpi_bool_t mandatory);
从 context 取出32位有符号参数,赋值给 value,若 mandatory 为 ture 且没有参数,则生成-109错误(无参数错
误);若 mandatory 为 false(通常不使用),则参数应为表达式字符串,否则产生-151错误(无效字符串错误)
scpi_bool_t SCPI_ParamInt64(
scpi_t* context,
int64_t* value,
scpi_bool_t mandatory);
同上述取32位有符号参数逻辑,取出64位有符号参数
与上述两个函数相同逻辑的还有如下 API 函数
SCPI_ParamUInt32() 取无符号32位数据
SCPI_ParamUInt64()取无符号64位数据
SCPI_ParamDouble()取 double 类型数据
SCPI_ParamFloat()取 float 类型数据
SCPI_ParamBool()取 bool 类型数据
产生回传 API
经结果生成处理 API,产生的回传参数会存入接口参数 scpi interface 中,并最终均会调用 SCPI_Write() 函
数,目前该函数为:将回传参数经 uart4口发出
以数组形式产生回传 API
与上一部分产生回传的 API 类似,本部分 API 产生数组存入接口参数 scpi interface 的结果存储中,并触发 SCPI_Write() 函数
数据转字符串的 API
默认不对接口参数的回传值进行操作