PynectDirect SDK用户手册(Python版)
PynectDirect SDK Python 用户手册
适用对象:第一次使用 PynectDirect 光谱仪的学生、教师和应用开发人员
运行环境:64 位 Windows、64 位 Python 3
文档范围:设备使用、Python 调用、数据采集、API 查询和故障排查
1. 阅读本手册
1.1 学习目标
完成本手册后,你应当能够:
- 正确放置运行文件并完成只读设备检查。
- 使用 Python 扫描、打开和关闭光谱仪。
- 读取设备信息、波长数组和光谱强度数组。
- 设置积分时间、平均次数和采集波段。
- 将测量结果保存为 CSV,并绘制光谱曲线。
- 根据错误码定位常见问题。
- 在需要时查询全部 55 个公开 API。
1.2 支持的设备
PynectDirect 使用同一套 Python 调用方式支持两类设备:
- UV/VIS:紫外可见光谱仪。
- NIR:近红外光谱仪。
打开设备后会自动识别类型。两类设备的基础采谱流程相同,但氙灯、外触发、DAC 和固化配置等功能可能只在特定设备上可用。调用进阶功能前,应先读取设备能力。
1.3 常用术语
| 术语 | 含义 |
|---|---|
| DLL | Python 实际加载的 PynectDirect 功能库 |
| API | Python 可以调用的设备功能 |
| 设备索引 | 扫描结果中的编号,从 0 开始 |
| 芯片序列号 | USB 芯片的唯一编号,适合区分多台设备 |
| 设备序列号 | 光谱仪自身的业务编号 |
| 波长点数 | 一次光谱中包含的数据点数量 |
| nm | 纳米,波长单位 |
| 积分时间 | 探测器累计信号的时间,单位为微秒 |
| 平均次数 | 多次采集后求平均的次数 |
1.4 风险等级
本手册对接口使用以下风险标记:
| 等级 | 含义 |
|---|---|
| 只读 | 不改变设备参数,适合初次测试 |
| 临时设置 | 改变当前运行参数,关闭或恢复后不应长期保留 |
| 需谨慎 | 会影响外部电路、光源或触发行为,只能在实验方案明确时使用 |
| 高风险 | 可能修改持久数据、复位设备或影响标定,不用于课堂自由实验 |
2. 五分钟快速开始
2.1 准备文件
推荐将文件整理为以下形式:
PynectDirect_User/
|-- minimal_test.py
|-- python_ctypes_example.py
`-- dll/
|-- PynectDirect.dll
`-- ftd2xx.dll
dll 文件夹与 minimal_test.py 位于同一级。两个 DLL 必须放在同一个 dll 文件夹中。
脚本也支持把 PynectDirect.dll 直接放在 minimal_test.py 旁边,但为了保持目录整洁,建议使用上面的布局。
2.2 检查 Python 位数
在文件夹空白处打开 PowerShell,然后运行:
python -c "import struct; print(8 * struct.calcsize('P'))"
正确输出为:
64
如果输出 32,需要安装 64 位 Python。32 位 Python 无法加载本 SDK 的 64 位 DLL。
2.3 连接设备
- 将光谱仪连接到电脑 USB 接口。
- 等待 Windows 完成设备识别。
- 关闭其他可能正在使用光谱仪的软件。
- 不要同时启动两个采集程序访问同一台设备。
2.4 运行只读测试
在 minimal_test.py 所在目录运行:
python .\minimal_test.py --read-only
典型输出如下。设备型号、序列号、波长范围和强度值会因设备而不同。
[PASS] DLL load: ...\dll\PynectDirect.dll
[PASS] API exports: 55 functions
[PASS] Device scan: found 1 device(s)
[PASS] Open device: 0
[PASS] Device information
[PASS] Wavelength count: 2048
[PASS] Full wavelength data: points=2048 ...
[PASS] Full spectrum: points=2048 ...
[PASS] Close device: closed
Summary: PASS=17 SKIP=2 FAIL=0
满足以下条件即可认为基础环境可用:
DLL load为PASS,且路径指向预期的 DLL。API exports显示55 functions。Device scan至少发现一台设备。Full spectrum为PASS。- 最终汇总中的
FAIL=0。
SKIP 不等于失败。只读模式会主动跳过参数写入和指定波段设置,因此通常会出现 SKIP。
3. 使用最小测试工具
3.1 输出状态
| 状态 | 含义 | 处理方式 |
|---|---|---|
PASS |
该检查成功 | 无需处理 |
SKIP |
当前模式或设备能力不适用 | 查看同一行原因 |
FAIL |
加载、参数、通信或数据检查失败 | 按第 14 章排查 |
3.2 测试项目说明
| 项目 | 检查内容 |
|---|---|
DLL load |
是否找到并加载 PynectDirect.dll 及其依赖 |
API exports |
DLL 是否包含全部 55 个公开函数 |
Device scan |
当前可访问的设备数量 |
FTDI chip serial |
USB 芯片序列号 |
Open device |
是否成功打开指定设备 |
Capabilities |
当前设备支持的功能集合 |
Device identity |
协议、型号、设备序列号和硬件版本 |
Wavelength count |
光谱数据点数量 |
Full wavelength data |
完整波长数组是否可读 |
Full spectrum |
是否成功采集强度数组 |
Close device |
是否可靠释放设备 |
3.3 命令参数
python .\minimal_test.py --help
| 参数 | 默认值 | 用途 |
|---|---|---|
--dll PATH |
自动查找 | 指定 PynectDirect.dll 的完整路径 |
--device-index N |
0 |
测试扫描结果中的第 N 台设备 |
--read-only |
关闭 | 只读测试,不改变当前参数 |
--integration-us N |
50000 |
普通测试使用的临时积分时间,单位微秒 |
--average N |
1 |
普通测试使用的临时平均次数,范围 1-255 |
常用命令:
# 第一次连接时推荐
python .\minimal_test.py --read-only
# 测试第二台设备
python .\minimal_test.py --read-only --device-index 1
# 临时使用 100 ms 积分时间和 3 次平均
python .\minimal_test.py --integration-us 100000 --average 3
# 明确指定 DLL
python .\minimal_test.py --dll .\dll\PynectDirect.dll --read-only
不带 --read-only 时,工具会先保存当前积分时间、平均次数和触发设置,再使用测试值,结束时恢复原值。发生异常时也会尝试恢复并关闭设备。该工具不会默认执行 Flash 写入、设备复位、固化参数、DAC 输出或氙灯控制。
4. 第一次连接设备
4.1 Python 文件布局
在 minimal_test.py 旁边新建 device_info.py:
PynectDirect_User/
|-- minimal_test.py
|-- device_info.py
`-- dll/
|-- PynectDirect.dll
`-- ftd2xx.dll
minimal_test.py 已包含全部 API 的 Python 类型绑定。自己的程序可以直接复用这些经过验证的加载和绑定功能。
4.2 读取设备信息
将以下内容写入 device_info.py:
import ctypes
from minimal_test import (
PROTOCOL_AUTO,
PynectDirectDeviceInfo,
bind_api,
decode_char_array,
find_dll,
load_library,
)
SUCCESS = 0
def require_success(code, operation):
if code != SUCCESS:
raise RuntimeError(f"{operation} failed, return code={code}")
sdk = load_library(find_dll())
bind_api(sdk)
opened = False
try:
device_count = sdk.pynect_direct_scan_devices()
if device_count <= 0:
raise RuntimeError("没有发现可用设备")
require_success(
sdk.pynect_direct_set_protocol_preference(PROTOCOL_AUTO),
"设置自动识别",
)
require_success(sdk.pynect_direct_open_device(0), "打开设备")
opened = True
info = PynectDirectDeviceInfo()
require_success(
sdk.pynect_direct_get_device_info(ctypes.byref(info)),
"读取设备信息",
)
print("协议:", decode_char_array(info.protocol_name))
print("型号:", decode_char_array(info.model))
print("序列号:", decode_char_array(info.serial_number))
print("硬件版本:", decode_char_array(info.hardware_version))
print(f"能力值: 0x{info.capabilities:08X}")
finally:
if opened:
sdk.pynect_direct_close_device()
运行:
python .\device_info.py
预期会显示设备协议、型号、序列号、硬件版本和能力值。无论读取是否成功,finally 都会执行关闭操作。
4.3 基本调用顺序
所有常规程序都应遵循以下顺序:
- 加载 DLL 并绑定 API。
- 扫描设备。
- 选择设备索引或芯片序列号。
- 打开设备。
- 读取能力和设备信息。
- 设置临时参数并采集数据。
- 在
finally中关闭设备。
5. 第一次采集完整光谱
5.1 完整采集示例
SDK 已附带可直接运行的只读例程:
python .\python_ctypes_example.py
例程中的 read_full_spectrum(device_index=0) 返回两个普通 Python 列表:
from python_ctypes_example import read_full_spectrum
wavelengths, intensities = read_full_spectrum(device_index=0)
print(len(wavelengths), len(intensities))
该函数不会修改积分时间、平均次数或其他设备参数。下面给出相同流程的展开版本,便于学习每一步的调用方式。
在同一目录新建 capture_spectrum.py:
import ctypes
from minimal_test import bind_api, find_dll, load_library
SUCCESS = 0
def require_success(code, operation):
if code != SUCCESS:
raise RuntimeError(f"{operation} failed, return code={code}")
sdk = load_library(find_dll())
bind_api(sdk)
opened = False
try:
device_count = sdk.pynect_direct_scan_devices()
if device_count <= 0:
raise RuntimeError("没有发现可用设备")
require_success(sdk.pynect_direct_open_device(0), "打开设备")
opened = True
point_count = ctypes.c_uint16()
require_success(
sdk.pynect_direct_get_wavelength_count(ctypes.byref(point_count)),
"读取波长点数",
)
if point_count.value == 0:
raise RuntimeError("设备返回的波长点数为 0")
wavelengths = (ctypes.c_double * point_count.value)()
intensities = (ctypes.c_uint16 * point_count.value)()
require_success(
sdk.pynect_direct_get_full_wavelength_data(
wavelengths, point_count.value
),
"读取波长数组",
)
require_success(
sdk.pynect_direct_get_full_spectrum_data(
intensities, point_count.value
),
"采集光谱强度",
)
print("点数:", point_count.value)
print(f"波长范围: {wavelengths[0]:.3f} - {wavelengths[-1]:.3f} nm")
print("强度范围:", min(intensities), "-", max(intensities))
print("前 5 个数据点:")
for index in range(min(5, point_count.value)):
print(f" {wavelengths[index]:.3f} nm, {intensities[index]}")
finally:
if opened:
sdk.pynect_direct_close_device()
运行:
python .\capture_spectrum.py
典型结果:
点数: 2048
波长范围: 780.294 - 1002.186 nm
强度范围: 90 - 319
前 5 个数据点:
780.294 nm, 116
...
具体数字取决于设备、光源、样品、积分时间和环境。
5.2 为什么先读取点数
不同型号可能返回不同的数据点数量。必须先调用 pynect_direct_get_wavelength_count,再按该数量分配波长和强度数组。数组过小会返回参数错误,写死 2048 会导致程序无法兼容其他型号。
5.3 一次采集得到什么
wavelengths[index]:第index个数据点对应的波长,单位 nm。intensities[index]:同一位置的原始强度值。- 两个数组长度必须相同。
pynect_direct_get_full_spectrum_data会取得一次新的光谱数据。
6. 理解光谱数据
6.1 波长和强度必须按索引配对
第 N 个波长只对应第 N 个强度:
wavelengths[0] <-> intensities[0]
wavelengths[1] <-> intensities[1]
...
wavelengths[N] <-> intensities[N]
不要分别排序两个数组,也不要删除其中一个数组的单独数据点。
6.2 强度值的含义
光谱强度为无符号 16 位原始数值,理论存储范围为 0-65535。实际有效范围、饱和位置和暗信号水平由设备及测量条件决定。
原始强度不是透过率、吸光度或反射率。得到这些物理量通常还需要暗背景、参考光谱和相应计算流程。
6.3 数据质量检查
每次采集后至少检查:
- 点数是否大于 0。
- 波长是否从小到大排列。
- 结束波长是否大于起始波长。
- 强度是否全部接近 0。
- 是否出现大量相同的最大值,可能表示饱和。
- 多次测量的峰位置是否稳定。
7. 设置测量参数和波长范围
7.1 积分时间
积分时间单位为微秒。50000 表示 50 ms,100000 表示 100 ms。
import ctypes
old_integration = ctypes.c_uint()
require_success(
sdk.pynect_direct_get_integration_time(ctypes.byref(old_integration)),
"读取积分时间",
)
require_success(
sdk.pynect_direct_set_integration_time(100000),
"设置积分时间",
)
print("原积分时间:", old_integration.value, "us")
一般规律:
- 信号过弱时,可逐步增加积分时间。
- 信号饱和时,应减小积分时间。
- 积分时间越长,单次测量等待时间通常越长。
- 可用范围以具体设备说明为准;参数必须为正数。
该设置属于临时设置。实验结束前建议恢复原值。
7.2 平均次数
平均次数通常使用 1-255:
import ctypes
old_average = ctypes.c_uint8()
require_success(
sdk.pynect_direct_get_average_number(ctypes.byref(old_average)),
"读取平均次数",
)
require_success(
sdk.pynect_direct_set_average_number(3),
"设置平均次数",
)
print("原平均次数:", old_average.value)
增加平均次数通常可以降低随机波动,但会增加采集时间。课堂实验可依次比较 1、3、5 次平均的差异。
7.3 恢复临时参数
修改参数前先读取旧值,并在 finally 中恢复:
old_integration = ctypes.c_uint()
old_average = ctypes.c_uint8()
require_success(
sdk.pynect_direct_get_integration_time(ctypes.byref(old_integration)),
"读取积分时间",
)
require_success(
sdk.pynect_direct_get_average_number(ctypes.byref(old_average)),
"读取平均次数",
)
try:
require_success(
sdk.pynect_direct_set_integration_time(100000),
"设置积分时间",
)
require_success(
sdk.pynect_direct_set_average_number(3),
"设置平均次数",
)
# 在这里完成测量
finally:
sdk.pynect_direct_set_average_number(old_average.value)
sdk.pynect_direct_set_integration_time(old_integration.value)
7.4 指定波长范围
指定波段只改变本次程序返回的数据窗口,不改变设备的物理波长范围。
import ctypes
from minimal_test import PynectDirectSelectedWavelengthRange
request_start_nm = 900.0
request_end_nm = 950.0
full_start = ctypes.c_double()
full_end = ctypes.c_double()
require_success(
sdk.pynect_direct_get_full_wavelength_range(
ctypes.byref(full_start), ctypes.byref(full_end)
),
"读取完整波长范围",
)
if not (
full_start.value <= request_start_nm
< request_end_nm <= full_end.value
):
raise ValueError(
f"请求范围必须位于 {full_start.value:.3f} - "
f"{full_end.value:.3f} nm 内"
)
require_success(
sdk.pynect_direct_set_selected_wavelength_range(
request_start_nm, request_end_nm
),
"设置波长范围",
)
selected = PynectDirectSelectedWavelengthRange()
require_success(
sdk.pynect_direct_get_selected_wavelength_range(
ctypes.byref(selected)
),
"读取实际波长范围",
)
wavelengths = (ctypes.c_double * selected.count)()
intensities = (ctypes.c_uint16 * selected.count)()
require_success(
sdk.pynect_direct_get_selected_wavelength_data(
wavelengths, selected.count
),
"读取波段波长",
)
require_success(
sdk.pynect_direct_get_selected_spectrum_data(
intensities, selected.count
),
"读取波段光谱",
)
print(
f"请求范围: {selected.request_start_nm:.3f} - "
f"{selected.request_end_nm:.3f} nm"
)
print(
f"实际范围: {selected.actual_start_nm:.3f} - "
f"{selected.actual_end_nm:.3f} nm"
)
print("点数:", selected.count)
实际范围可能与请求值略有差异,因为设备只能选择已有像素对应的波长点。后续数组长度必须使用 selected.count。
8. 保存 CSV 数据
采集完成后,可使用 Python 自带的 csv 模块保存数据:
import csv
from datetime import datetime
from pathlib import Path
output_path = Path(__file__).resolve().parent / "spectrum.csv"
measured_at = datetime.now().isoformat(timespec="seconds")
with output_path.open("w", newline="", encoding="utf-8-sig") as file:
writer = csv.writer(file)
writer.writerow(["measured_at", measured_at])
writer.writerow(["wavelength_nm", "intensity"])
writer.writerows(zip(wavelengths, intensities))
print("数据已保存:", output_path)
生成的文件结构如下:
measured_at,2026-07-31T17:10:00
wavelength_nm,intensity
780.294,116
780.402,121
...
建议同时记录:
- 设备型号和序列号。
- 积分时间。
- 平均次数。
- 样品名称。
- 暗背景或参考光谱信息。
- 测量时间。
utf-8-sig 便于 Windows 表格软件正确识别中文。保存完成后再关闭设备,不要在采集过程中移动或断开 USB。
9. 绘制光谱曲线
9.1 安装绘图库
首次使用时运行:
python -m pip install matplotlib
9.2 从 CSV 绘图
在 spectrum.csv 旁边新建 plot_spectrum.py:
import csv
from pathlib import Path
import matplotlib.pyplot as plt
csv_path = Path(__file__).resolve().parent / "spectrum.csv"
wavelengths = []
intensities = []
with csv_path.open("r", encoding="utf-8-sig", newline="") as file:
reader = csv.reader(file)
next(reader) # 测量时间
next(reader) # 列标题
for wavelength_nm, intensity in reader:
wavelengths.append(float(wavelength_nm))
intensities.append(int(intensity))
plt.figure(figsize=(9, 5))
plt.plot(wavelengths, intensities, color="#1261A0", linewidth=1.2)
plt.xlabel("Wavelength (nm)")
plt.ylabel("Intensity")
plt.title("PynectDirect Spectrum")
plt.grid(True, alpha=0.25)
plt.tight_layout()
plt.show()
运行:
python .\plot_spectrum.py
如果图形为空,先检查 CSV 是否包含数据、两列长度是否相同,以及波长列能否转换为数字。
10. 多设备使用
10.1 索引与芯片序列号
设备索引由当前扫描顺序决定,重新插拔后可能改变。长期绑定某台设备时,应记录芯片序列号,并按序列号打开。
import ctypes
device_count = sdk.pynect_direct_scan_devices()
if device_count <= 0:
raise RuntimeError("没有发现设备")
chip_serials = []
for index in range(device_count):
serial_buffer = ctypes.create_string_buffer(64)
require_success(
sdk.pynect_direct_get_chip_serial_by_index(
index, serial_buffer, len(serial_buffer)
),
f"读取设备 {index} 的芯片序列号",
)
chip_serial = serial_buffer.value.decode(
"utf-8", errors="replace"
)
chip_serials.append(chip_serial)
print(index, chip_serial)
target_serial = chip_serials[0]
require_success(
sdk.pynect_direct_open_device_by_chip_serial(
target_serial.encode("utf-8")
),
"按芯片序列号打开设备",
)
10.2 多台设备的推荐顺序
同一个 Python 进程一次只操作一台当前设备:
- 扫描并保存全部芯片序列号。
- 按第一个序列号打开、采集、关闭。
- 按下一个序列号打开、采集、关闭。
- 每台设备的数据文件中记录对应芯片序列号和设备序列号。
不要在多个线程中同时调用同一个 DLL 实例。确需并行采集时,应先与设备供应方确认支持方式。
11. 识别设备能力
11.1 为什么要检查能力
不同设备支持的功能不同。基础采谱通常可用,但 UV/VIS 专用功能在 NIR 设备上可能返回 -11。正确做法是打开设备后读取能力值,再决定是否调用某项功能。
11.2 能力表
| 能力名称 | 数值 | 说明 |
|---|---|---|
PYNECT_DIRECT_CAP_INTEGRATION_TIME |
0x00000001 |
积分时间 |
PYNECT_DIRECT_CAP_AVERAGE_NUMBER |
0x00000002 |
平均次数 |
PYNECT_DIRECT_CAP_LEVEL_OUTPUT |
0x00000004 |
电平输出 |
PYNECT_DIRECT_CAP_FLASH |
0x00000008 |
Flash/FLS |
PYNECT_DIRECT_CAP_WAVELENGTH_DATA |
0x00000010 |
波长数据 |
PYNECT_DIRECT_CAP_SPECTRUM_DATA |
0x00000020 |
光谱数据 |
PYNECT_DIRECT_CAP_TEMPERATURE |
0x00000040 |
温度 |
PYNECT_DIRECT_CAP_HARDWARE_VERSION |
0x00000080 |
硬件版本 |
PYNECT_DIRECT_CAP_CALIBRATION |
0x00000100 |
标定系数 |
PYNECT_DIRECT_CAP_XENON |
0x00000200 |
氙灯控制 |
PYNECT_DIRECT_CAP_USB_STATUS |
0x00000400 |
USB 状态和速率参数 |
PYNECT_DIRECT_CAP_EXTERNAL_TRIGGER |
0x00000800 |
外触发 |
PYNECT_DIRECT_CAP_DAC |
0x00001000 |
DAC 输出 |
PYNECT_DIRECT_CAP_STORED_CONFIG |
0x00002000 |
固化配置 |
PYNECT_DIRECT_CAP_SLIT_WIDTH |
0x00004000 |
狭缝宽度 |
11.3 Python 检查方式
import ctypes
CAP_EXTERNAL_TRIGGER = 0x00000800
capabilities = ctypes.c_uint32()
require_success(
sdk.pynect_direct_get_capabilities(ctypes.byref(capabilities)),
"读取设备能力",
)
if capabilities.value & CAP_EXTERNAL_TRIGGER:
print("设备支持外触发")
else:
print("设备不支持外触发")
12. 高级功能与安全
12.1 功能风险速查
| 功能 | 代表 API | 风险 | 使用要求 |
|---|---|---|---|
| 设备信息和光谱读取 | pynect_direct_get_* |
只读 | 打开设备后使用 |
| 积分时间和平均次数 | pynect_direct_set_integration_time 等 |
临时设置 | 先保存旧值,结束时恢复 |
| GPIO 电平 | pynect_direct_set_level_output |
需谨慎 | 明确外部接线和位定义 |
| 氙灯 | pynect_direct_set_xenon_* |
需谨慎 | 确认光源、电源和散热条件 |
| 外触发 | pynect_direct_set_external_trigger_config |
需谨慎 | 确认触发电平和时序 |
| DAC | pynect_direct_set_dac_voltage |
需谨慎 | 确认输出连接和允许码值 |
| Flash 写入 | pynect_direct_flash_write |
高风险 | 备份数据并获得教师或供应方授权 |
| 固化配置 | pynect_direct_set_stored_* |
高风险 | 记录原值,确认设备型号和参数范围 |
| 设备复位 | pynect_direct_reset_device |
高风险 | 停止采集,准备重新初始化 |
12.2 氙灯控制
氙灯功能通常只在支持 PYNECT_DIRECT_CAP_XENON 的 UV/VIS 设备上可用。周期和高电平宽度的单位都是 10 ns。设置前必须确认:
- 高电平宽度不大于周期。
- 光源和设备允许连续或单次模式。
- 实验现场具备必要的防护措施。
- 异常退出时能够关闭光源。
不要把氙灯写操作放入自动启动程序。
12.3 外触发
推荐流程:
- 读取并记录原触发配置。
- 根据设备说明设置触发开关、类型和帧数。
- 由外部信号触发采集。
- 查询采集状态。
- 读取指定帧数据。
- 恢复原触发配置。
触发电平、接线和时序错误可能造成无数据或持续等待。课堂基础实验应保持触发关闭,使用普通光谱读取接口。
12.4 Flash 和固化配置
Flash 和固化参数会影响设备长期状态,不属于基础采谱操作。使用前必须:
- 确认设备型号和目标扇区。
- 备份原始数据并校验备份可读。
- 明确写入数据长度和格式。
- 获得教师、实验室管理员或设备供应方授权。
- 写入后重新读取并核对结果。
学生练习不得执行 Flash 写入、固化配置或设备复位。
13. 错误处理与安全关闭
13.1 错误码
多数函数成功时返回 0,失败时返回负数:
| 返回值 | 名称 | 用户含义 |
|---|---|---|
0 |
PYNECT_DIRECT_SUCCESS |
操作成功 |
-1 |
PYNECT_DIRECT_ERR_NOT_INITIALIZED |
所需状态尚未建立,例如未设置指定波段 |
-2 |
PYNECT_DIRECT_ERR_DEVICE_NOT_FOUND |
未找到目标设备 |
-3 |
PYNECT_DIRECT_ERR_DEVICE_NOT_OPEN |
尚未打开设备 |
-4 |
PYNECT_DIRECT_ERR_COMM_FAIL |
设备通信或返回数据异常 |
-5 |
PYNECT_DIRECT_ERR_INVALID_PARAM |
参数、范围或缓冲区长度错误 |
-6 |
PYNECT_DIRECT_ERR_OPEN_FAILED |
设备打开失败 |
-7 |
PYNECT_DIRECT_ERR_CRC |
数据校验失败 |
-8 |
PYNECT_DIRECT_ERR_PREAMBLE |
接收数据格式异常 |
-9 |
PYNECT_DIRECT_ERR_TIMEOUT |
等待设备响应超时 |
-10 |
PYNECT_DIRECT_ERR_WPROT |
写入条件或写保护状态不满足 |
-11 |
PYNECT_DIRECT_ERR_UNSUPPORTED |
当前设备不支持该功能 |
注意以下例外:
pynect_direct_scan_devices成功时返回设备数量,0表示未发现设备。pynect_direct_is_open返回1或0表示状态。pynect_direct_flash_read成功时返回读取的字节数。pynect_direct_external_spectrum_control成功时返回数据字节数。pynect_direct_close_device没有返回值。
13.2 统一检查返回值
ERROR_NAMES = {
-1: "状态未初始化",
-2: "未找到设备",
-3: "设备未打开",
-4: "通信失败",
-5: "参数错误",
-6: "打开失败",
-7: "数据校验失败",
-8: "数据格式异常",
-9: "设备响应超时",
-10: "写保护状态不满足",
-11: "设备不支持该功能",
}
def require_success(code, operation):
if code != 0:
reason = ERROR_NAMES.get(code, "未知错误")
raise RuntimeError(
f"{operation}失败: {reason}, return code={code}"
)
13.3 始终关闭设备
设备成功打开后,后续代码必须使用 try/finally:
opened = False
try:
require_success(sdk.pynect_direct_open_device(0), "打开设备")
opened = True
# 读取或采集
finally:
if opened:
sdk.pynect_direct_close_device()
不要依赖程序自然退出释放设备。异常退出后,如果其他软件无法打开设备,先关闭残留的 Python 进程,再重新插拔 USB。
14. 故障排查
14.1 提示无法加载 DLL
依次检查:
- Python 位数检查结果是否为
64。 - 文件名是否严格为
PynectDirect.dll。 ftd2xx.dll是否与PynectDirect.dll在同一文件夹。dll文件夹是否与minimal_test.py同级。- 是否误把 DLL 放入多一层同名文件夹。
- 使用
--dll指定路径后是否仍然失败。
测试命令:
python .\minimal_test.py --dll .\dll\PynectDirect.dll --read-only
14.2 Device scan 显示 0
- 确认 USB 线支持数据传输,而不是仅供电。
- 更换电脑 USB 接口,避免无供电的扩展接口。
- 在 Windows 设备管理器中确认设备已识别。
- 关闭其他光谱软件和残留的 Python 进程。
- 重新插拔设备后再运行只读测试。
14.3 返回 -6,设备打开失败
最常见原因是设备已被另一个程序占用。关闭其他采集程序后重试。如果多台设备同时连接,先运行只读测试确认索引,再使用正确的 --device-index。
14.4 返回 -9,设备响应超时
- 检查 USB 连接是否松动。
- 降低程序连续调用频率。
- 确认外触发没有处于等待状态。
- 关闭设备并重新打开;仍无效时重新插拔 USB。
14.5 返回 -11,设备不支持该功能
这通常不是故障。读取能力值,只调用当前设备明确支持的功能。NIR 设备不一定支持 UV/VIS 的氙灯、外触发、DAC 或固化配置。
14.6 返回 -5,参数错误
重点检查:
- 平均次数是否在
1-255。 - 积分时间是否为正数并符合设备范围。
- 起始波长是否小于结束波长。
- 请求波段是否位于完整波长范围内。
- 数组长度是否至少等于设备返回的点数。
- 字符串缓冲区和数据缓冲区是否足够大。
14.7 指定波段返回 -1
必须先调用 pynect_direct_set_selected_wavelength_range,成功后再读取指定波段信息和数据。设备复位或重新打开后,应重新设置波段。
14.8 光谱全为低值、噪声大或饱和
- 确认光源、光纤和样品位置。
- 信号过低时逐步增加积分时间。
- 噪声较大时适当增加平均次数。
- 大量数据接近上限时减小积分时间。
- 保持测量条件稳定,多采几次比较。
14.9 向技术支持提供什么
请准备:
minimal_test.py --read-only的完整输出。- Python 版本和 64 位检查结果。
- DLL 实际加载路径。
- 设备型号、芯片序列号和设备序列号。
- 出错 API 名称和返回值。
- 能否被其他设备软件正常识别。
15. 完整 API 参考
本章所有 Python 示例均假定:已经使用 load_library() 加载 DLL,已经使用 bind_api(sdk) 设置函数类型,并已定义第 13.2 节中的 require_success()。需要设备连接的接口还假定设备已经成功打开。示例中的 ctypes 来自 Python 标准库。
参数表中的“输入”表示 Python 向 DLL 提供值;“输出”表示 DLL 将结果写入 Python 创建的变量或数组;“输入/输出”表示调用前需要提供容量,调用后从同一对象读取结果。
15.1 设备发现、打开和识别
pynect_direct_scan_devices
功能说明
刷新当前 USB 设备列表,在控制台打印每台设备的索引、描述和芯片序列号,并返回本次发现的设备数量。该函数不打开设备。
适用范围
UV/VIS、NIR;只读;不要求任何 capability 位。
调用前提
设备已连接并被 Windows 识别。其他程序不应独占目标设备。扫描可以在设备未打开时调用。
输入参数
无。
输出参数
无输出容器;设备列表直接打印到控制台。
返回值
| 返回值 | 含义 |
|---|---|
1-64 |
本次发现的设备数量;每台设备可用索引为 0 到 count - 1 |
0 |
未发现设备,或底层 USB 枚举失败;该函数不返回负错误码 |
Python 示例
device_count = sdk.pynect_direct_scan_devices()
if device_count == 0:
print("No PynectDirect device found")
else:
print(f"Found {device_count} device(s)")
常见错误
把 0 当作成功状态码。此函数与多数 API 不同,0 表示没有可用设备。关联 API:pynect_direct_get_chip_serial_by_index、pynect_direct_open_device。
pynect_direct_get_chip_serial_by_index
功能说明
根据扫描索引读取 USB 芯片序列号。该序列号用于稳定区分多台设备,与光谱仪业务序列号不是同一个字段。
适用范围
UV/VIS、NIR;只读;不要求设备已经打开。
调用前提
建议先调用 pynect_direct_scan_devices,并确保 index 小于扫描返回数量。
输入参数
| 参数 | Python 类型 | 方向 | 范围/容量 | 说明 |
|---|---|---|---|---|
index |
int |
输入 | 0 到 device_count - 1 |
扫描列表索引 |
chip_serial |
ctypes.create_string_buffer |
输入/输出 | 建议 64 字节 | 接收以 \0 结尾的芯片序列号 |
max_len |
int |
输入 | 至少 2;通常传 len(buffer) |
缓冲区总字节数,包含结尾字符空间 |
输出参数
成功后从 chip_serial.value 取得字节串,再按 UTF-8 解码。若缓冲区较小,字符串会被截断,因此建议分配 64 字节。
返回值
| 返回值 | 含义 |
|---|---|
0 |
读取成功 |
-2 |
未发现设备或索引超出当前设备数量 |
-5 |
索引为负、缓冲区无效或 max_len <= 1 |
Python 示例
import ctypes
device_count = sdk.pynect_direct_scan_devices()
if device_count > 0:
serial_buffer = ctypes.create_string_buffer(64)
code = sdk.pynect_direct_get_chip_serial_by_index(
0, serial_buffer, len(serial_buffer)
)
require_success(code, "Get chip serial")
chip_serial = serial_buffer.value.decode("utf-8", errors="replace")
print(chip_serial)
常见错误
传入业务序列号接口的缓冲区结果作为芯片序列号,或在重新插拔设备后继续使用旧索引。关联 API:pynect_direct_open_device_by_chip_serial、pynect_direct_get_serial_number。
pynect_direct_open_device
功能说明
按当前扫描索引打开一台设备,并识别设备协议和 capability。若当前已有设备打开,函数会先关闭旧设备,再尝试打开新索引。
适用范围
UV/VIS、NIR;连接操作;成功后建立 DLL 的当前设备状态。
调用前提
先扫描设备并选择有效索引。目标设备不能被其他进程独占。需要强制协议时,应在打开前调用 pynect_direct_set_protocol_preference。
输入参数
| 参数 | Python 类型 | 方向 | 范围 | 说明 |
|---|---|---|---|---|
index |
int |
输入 | 0 到 device_count - 1 |
当前 USB 枚举列表中的设备索引 |
输出参数
无。成功后可通过 pynect_direct_is_open、pynect_direct_get_device_protocol 和 pynect_direct_get_capabilities 查询连接状态。
返回值
| 返回值 | 含义 |
|---|---|
0 |
打开成功 |
-6 |
索引无效、设备被占用或 USB 打开失败 |
Python 示例
device_count = sdk.pynect_direct_scan_devices()
if device_count <= 0:
raise RuntimeError("No device found")
require_success(sdk.pynect_direct_open_device(0), "Open device")
print("Device opened")
常见错误
直接写死索引而不先扫描;多台设备重新插拔后索引可能变化。打开新设备会关闭旧设备,因此不要假设两个索引可以在同一 DLL 实例中同时保持打开。关联 API:pynect_direct_scan_devices、pynect_direct_close_device。
pynect_direct_open_device_by_chip_serial
功能说明
遍历当前 USB 设备,找到芯片序列号完全匹配的设备并打开。适合设备索引可能变化的多设备系统。
适用范围
UV/VIS、NIR;连接操作。
调用前提
已通过 pynect_direct_get_chip_serial_by_index 取得非空芯片序列号。目标设备没有被其他程序占用。
输入参数
| 参数 | Python 类型 | 方向 | 格式 | 说明 |
|---|---|---|---|---|
chip_serial |
bytes / ctypes.c_char_p |
输入 | 非空、以 \0 终止 |
USB 芯片序列号;Python 字符串需先编码为字节串 |
输出参数
无。成功后建立当前设备连接。
返回值
| 返回值 | 含义 |
|---|---|
0 |
找到匹配设备并打开成功 |
-2 |
没有设备或没有匹配序列号 |
-5 |
chip_serial 为空 |
-6 |
找到设备但打开失败或设备被占用 |
Python 示例
chip_serial = "B002P00S"
code = sdk.pynect_direct_open_device_by_chip_serial(
chip_serial.encode("utf-8")
)
require_success(code, "Open device by chip serial")
常见错误
传入光谱仪业务序列号而不是 USB 芯片序列号,或直接传 Python str 而未编码。关联 API:pynect_direct_get_chip_serial_by_index、pynect_direct_get_serial_number。
pynect_direct_close_device
功能说明
关闭当前设备句柄,清除协议、能力和指定波段状态。重复调用是允许的。
适用范围
UV/VIS、NIR;资源清理操作。
调用前提
无。建议只要设备曾成功打开,就在 finally 中调用。
输入参数
无。
输出参数
无。
返回值
没有返回值,Python 中结果为 None。无法通过返回值判断底层关闭状态,可在关闭后调用 pynect_direct_is_open 验证。
Python 示例
opened = False
try:
require_success(sdk.pynect_direct_open_device(0), "Open device")
opened = True
# Perform read-only operations here.
finally:
if opened:
sdk.pynect_direct_close_device()
常见错误
只在正常路径关闭设备,异常时遗漏清理;这会导致下一次程序无法打开设备。关联 API:pynect_direct_open_device、pynect_direct_is_open。
pynect_direct_is_open
功能说明
读取 DLL 当前设备状态,不与设备通信。
适用范围
UV/VIS、NIR;只读状态查询。
调用前提
无。
输入参数
无。
输出参数
无输出容器;状态直接通过函数返回值给出。
返回值
| 返回值 | 含义 |
|---|---|
1 |
DLL 当前记录为设备已打开 |
0 |
当前没有打开的设备 |
Python 示例
if sdk.pynect_direct_is_open() == 1:
print("Device is open")
else:
print("Device is closed")
常见错误
把返回值当作标准错误码,认为 0 表示成功。此函数的 0 表示“未打开”。关联 API:pynect_direct_open_device、pynect_direct_close_device。
pynect_direct_set_protocol_preference
功能说明
设置下一次打开设备时使用的协议偏好。AUTO 会自动识别设备;强制模式用于已确认型号但自动识别异常的现场。
适用范围
UV/VIS、NIR;临时连接设置;不写入设备。
调用前提
当前必须没有打开的设备。正常使用推荐自动模式。
输入参数
| 参数 | Python 类型 | 方向 | 允许值 | 说明 |
|---|---|---|---|---|
protocol |
int / ctypes.c_int |
输入 | 0、1、2 |
0=AUTO,1=UVVIS_CM2,2=NIR_LEGACY |
输出参数
无。设置只影响后续打开操作。
返回值
| 返回值 | 含义 |
|---|---|
0 |
偏好设置成功 |
-3 |
当前已有设备打开;应先关闭设备 |
-5 |
protocol 不是 0、1 或 2 |
Python 示例
PROTOCOL_AUTO = 0
if sdk.pynect_direct_is_open():
sdk.pynect_direct_close_device()
require_success(
sdk.pynect_direct_set_protocol_preference(PROTOCOL_AUTO),
"Set protocol preference",
)
常见错误
在设备已打开后设置偏好,或无依据地强制错误协议。关联 API:pynect_direct_open_device、pynect_direct_get_device_protocol。
pynect_direct_get_device_protocol
功能说明
读取当前已打开设备实际采用的协议类型,而不是打开前设置的偏好值。
适用范围
UV/VIS、NIR;只读。
调用前提
设备已成功打开。
输入参数
无普通输入值。
输出参数
| 参数 | Python 类型 | 方向 | 输出值 | 说明 |
|---|---|---|---|---|
protocol |
ctypes.c_int() + ctypes.byref() |
输出 | 1、2、可能的 255 |
1=UVVIS_CM2,2=NIR_LEGACY,255=UNKNOWN |
返回值
| 返回值 | 含义 |
|---|---|
0 |
输出变量已写入协议值 |
-3 |
设备未打开 |
-5 |
输出变量无效 |
Python 示例
import ctypes
protocol = ctypes.c_int()
require_success(
sdk.pynect_direct_get_device_protocol(ctypes.byref(protocol)),
"Get device protocol",
)
print("Protocol value:", protocol.value)
常见错误
忘记使用 ctypes.byref(protocol),或在打开设备前查询。关联 API:pynect_direct_set_protocol_preference、pynect_direct_get_device_info。
pynect_direct_get_capabilities
功能说明
读取当前设备的 32 位 capability 位掩码。每一位表示一类功能是否可用。
适用范围
UV/VIS、NIR;只读;调用任何设备专用功能前都应执行。
调用前提
设备已成功打开并完成协议识别。
输入参数
无普通输入值。
输出参数
| 参数 | Python 类型 | 方向 | 宽度 | 说明 |
|---|---|---|---|---|
capabilities |
ctypes.c_uint32() + ctypes.byref() |
输出 | 32 位无符号整数 | 按第 11.2 节列出的位值进行按位与检查 |
返回值
| 返回值 | 含义 |
|---|---|
0 |
capability 值读取成功 |
-3 |
设备未打开 |
-5 |
输出变量无效 |
Python 示例
import ctypes
CAP_SPECTRUM_DATA = 0x00000020
capabilities = ctypes.c_uint32()
require_success(
sdk.pynect_direct_get_capabilities(ctypes.byref(capabilities)),
"Get capabilities",
)
if capabilities.value & CAP_SPECTRUM_DATA:
print("Spectrum acquisition is supported")
常见错误
直接比较整个值是否等于某个 capability,而不是使用按位与;一台设备通常同时设置多个能力位。关联 API:pynect_direct_get_device_info 以及所有返回 -11 的设备专用接口。
pynect_direct_get_device_info
功能说明
一次读取协议、capability、设备型号、业务序列号和硬件版本。个别字符串读取失败时,对应字段可能为空,但函数仍可返回成功,因此应用应检查必要字段。
适用范围
UV/VIS、NIR;只读。
调用前提
设备已成功打开。Python 结构定义必须与 minimal_test.py 中的 PynectDirectDeviceInfo 一致。
输入参数
无普通输入值。
输出参数
| 参数 | Python 类型 | 方向 | 字段 | 说明 |
|---|---|---|---|---|
info |
PynectDirectDeviceInfo() + ctypes.byref() |
输出 | protocol |
协议整数值 |
info.capabilities |
ctypes.c_uint32 字段 |
输出 | capability 位掩码 | 功能支持集合 |
info.protocol_name |
32 字节字符数组 | 输出 | 协议名称 | 使用 decode_char_array 解码 |
info.model |
32 字节字符数组 | 输出 | 设备型号 | 读取失败时可能为空 |
info.serial_number |
32 字节字符数组 | 输出 | 业务序列号 | NIR 可能返回通用标识 |
info.hardware_version |
64 字节字符数组 | 输出 | 硬件版本 | 读取失败时可能为空 |
返回值
| 返回值 | 含义 |
|---|---|
0 |
基本信息对象已写入;仍应检查字符串字段是否为空 |
-3 |
设备未打开 |
-5 |
info 输出对象无效 |
Python 示例
import ctypes
from minimal_test import PynectDirectDeviceInfo, decode_char_array
info = PynectDirectDeviceInfo()
require_success(
sdk.pynect_direct_get_device_info(ctypes.byref(info)),
"Get device info",
)
print("Protocol:", decode_char_array(info.protocol_name))
print("Model:", decode_char_array(info.model))
print("Serial:", decode_char_array(info.serial_number))
print(f"Capabilities: 0x{info.capabilities:08X}")
常见错误
结构字段顺序或字符数组长度定义错误会导致错误数据;不要自行缩短结构定义。关联 API:pynect_direct_get_device_protocol、pynect_direct_get_capabilities、各单项身份接口。
15.2 临时测量参数
pynect_direct_set_integration_time
功能说明
设置当前会话的探测器积分时间。该值直接影响信号强度和单次采集耗时,不写入设备的默认固化配置。
适用范围
UV/VIS、NIR;要求 PYNECT_DIRECT_CAP_INTEGRATION_TIME;临时设置。
调用前提
设备已打开。先读取并记录原积分时间,确认目标值符合具体设备允许范围。
输入参数
| 参数 | Python 类型 | 方向 | 单位/范围 | 说明 |
|---|---|---|---|---|
us |
int / ctypes.c_uint |
输入 | 微秒;建议大于 0,上限以设备资料为准 |
50000 表示 50 ms;过大可能导致饱和和长时间等待 |
输出参数
无。成功后后续采谱使用新的积分时间。
返回值
| 返回值 | 含义 |
|---|---|
0 |
设置成功 |
-3 |
设备未打开 |
-4/-7/-8/-9 |
通信、校验、数据格式或超时错误 |
Python 示例
integration_us = 100_000
require_success(
sdk.pynect_direct_set_integration_time(integration_us),
"Set integration time",
)
常见错误
把毫秒值直接当微秒传入,例如希望 100 ms 却传 100;正确值是 100000。修改前不保存旧值也会影响后续实验。关联 API:pynect_direct_get_integration_time、pynect_direct_set_stored_integration_time。
pynect_direct_get_integration_time
功能说明
读取当前会话实际使用的积分时间。
适用范围
UV/VIS、NIR;要求积分时间能力;只读。
调用前提
设备已打开。
输入参数
无普通输入值。
输出参数
| 参数 | Python 类型 | 方向 | 单位 | 说明 |
|---|---|---|---|---|
us |
ctypes.c_uint() + ctypes.byref() |
输出 | 微秒 | 32 位无符号积分时间值 |
返回值
| 返回值 | 含义 |
|---|---|
0 |
输出变量已写入当前积分时间 |
-3 |
设备未打开 |
-5 |
输出变量无效 |
-4/-7/-8/-9 |
设备返回异常或通信超时 |
Python 示例
import ctypes
integration_us = ctypes.c_uint()
require_success(
sdk.pynect_direct_get_integration_time(
ctypes.byref(integration_us)
),
"Get integration time",
)
print(f"Integration: {integration_us.value} us")
常见错误
传入整数而不是 ctypes 输出变量,或忘记 ctypes.byref()。该值是当前运行参数,不是固化默认值。关联 API:pynect_direct_set_integration_time、pynect_direct_get_stored_integration_time。
pynect_direct_set_average_number
功能说明
设置当前会话一次结果所使用的光谱平均次数。增加平均次数通常降低随机波动,同时增加采集时间。
适用范围
UV/VIS、NIR;要求 PYNECT_DIRECT_CAP_AVERAGE_NUMBER;临时设置。
调用前提
设备已打开。先读取原值,并评估积分时间与平均次数共同造成的总等待时间。
输入参数
| 参数 | Python 类型 | 方向 | 范围 | 说明 |
|---|---|---|---|---|
count |
int / ctypes.c_uint8 |
输入 | 推荐 1-255 |
1 表示不做多次平均;不要使用 0,不同设备对 0 的处理可能不同 |
输出参数
无。成功后后续采谱使用新的平均次数。
返回值
| 返回值 | 含义 |
|---|---|
0 |
设置成功 |
-3 |
设备未打开 |
-4/-7/-8/-9 |
通信或响应错误 |
Python 示例
average_count = 3
require_success(
sdk.pynect_direct_set_average_number(average_count),
"Set average number",
)
常见错误
将平均次数设置为 0,或在长积分时间下使用很大的平均次数导致程序看似无响应。关联 API:pynect_direct_get_average_number、pynect_direct_set_stored_average_number。
pynect_direct_get_average_number
功能说明
读取当前会话的光谱平均次数。
适用范围
UV/VIS、NIR;要求平均次数能力;只读。
调用前提
设备已打开。
输入参数
无普通输入值。
输出参数
| 参数 | Python 类型 | 方向 | 范围 | 说明 |
|---|---|---|---|---|
count |
ctypes.c_uint8() + ctypes.byref() |
输出 | 0-255 |
当前设备报告的平均次数;正常应用通常应为 1-255 |
返回值
| 返回值 | 含义 |
|---|---|
0 |
输出变量已写入平均次数 |
-3 |
设备未打开 |
-5 |
输出变量无效 |
-4/-7/-8/-9 |
通信或响应错误 |
Python 示例
import ctypes
average_count = ctypes.c_uint8()
require_success(
sdk.pynect_direct_get_average_number(
ctypes.byref(average_count)
),
"Get average number",
)
print("Average count:", average_count.value)
常见错误
使用 ctypes.c_uint 接收 8 位结果,或把运行时平均次数与固化默认值混淆。关联 API:pynect_direct_set_average_number、pynect_direct_get_stored_average_number。
pynect_direct_set_level_output
功能说明
设置设备数字电平输出位掩码。每一位对应的物理输出由具体设备定义。
适用范围
UV/VIS、NIR;要求 PYNECT_DIRECT_CAP_LEVEL_OUTPUT;需谨慎,可能驱动外部电路。
调用前提
设备已打开,已确认接线、电平标准和每一位的用途。先读取原值以便恢复。
输入参数
| 参数 | Python 类型 | 方向 | 范围 | 说明 |
|---|---|---|---|---|
level |
int / ctypes.c_uint8 |
输入 | 0x00-0xFF |
8 位输出掩码;每一位的含义以设备资料为准 |
输出参数
无。成功后物理输出可能立即变化。
返回值
| 返回值 | 含义 |
|---|---|
0 |
输出位设置成功 |
-3 |
设备未打开 |
-4/-7/-8/-9 |
通信或设备响应错误 |
Python 示例
ALLOW_LEVEL_OUTPUT = False
target_level = 0x01
if ALLOW_LEVEL_OUTPUT:
require_success(
sdk.pynect_direct_set_level_output(target_level),
"Set level output",
)
else:
print("Level output skipped; enable only after checking wiring")
常见错误
把 level 当作单个逻辑值而忽略它是位掩码,或未确认外部负载就执行示例。关联 API:pynect_direct_get_level_output、设备接线说明。
pynect_direct_get_level_output
功能说明
读取当前数字电平输出位掩码。
适用范围
UV/VIS、NIR;要求电平输出能力;只读。
调用前提
设备已打开。
输入参数
无普通输入值。
输出参数
| 参数 | Python 类型 | 方向 | 范围 | 说明 |
|---|---|---|---|---|
level |
ctypes.c_uint8() + ctypes.byref() |
输出 | 0x00-0xFF |
当前 8 位输出掩码 |
返回值
| 返回值 | 含义 |
|---|---|
0 |
输出变量已写入当前位掩码 |
-3 |
设备未打开 |
-5 |
输出变量无效 |
-4/-7/-8/-9 |
通信或响应错误 |
Python 示例
import ctypes
level = ctypes.c_uint8()
require_success(
sdk.pynect_direct_get_level_output(ctypes.byref(level)),
"Get level output",
)
print(f"Level mask: 0x{level.value:02X}")
常见错误
将返回的十进制数直接理解成某一路电平而不做按位检查。关联 API:pynect_direct_set_level_output。
15.3 波长与光谱
pynect_direct_get_wavelength_count
功能说明
读取当前设备完整光谱包含的数据点数量。该点数决定波长数组和强度数组的最小容量。
适用范围
UV/VIS、NIR;要求波长数据能力;只读。
调用前提
设备已打开。每次更换设备后都应重新读取,不能写死为某个型号的固定点数。
输入参数
无普通输入值。
输出参数
| 参数 | Python 类型 | 方向 | 单位/范围 | 说明 |
|---|---|---|---|---|
count |
ctypes.c_uint16() + ctypes.byref() |
输出 | 数据点;0-65535 |
成功后保存完整波长和完整强度的点数 |
返回值
| 返回值 | 含义 |
|---|---|
0 |
点数读取成功;仍应检查 count.value > 0 |
-3 |
设备未打开 |
-5 |
输出变量无效或内存分配失败 |
-4/-7/-8/-9 |
数据长度异常、通信或超时错误 |
Python 示例
import ctypes
point_count = ctypes.c_uint16()
require_success(
sdk.pynect_direct_get_wavelength_count(ctypes.byref(point_count)),
"Get wavelength count",
)
if point_count.value == 0:
raise RuntimeError("Device returned zero wavelength points")
print("Points:", point_count.value)
常见错误
把函数返回值 0 当作点数;真正点数位于 count.value。关联 API:pynect_direct_get_full_wavelength_data、pynect_direct_get_full_spectrum_data。
pynect_direct_get_full_wavelength_range
功能说明
读取设备完整数据集的起始波长和结束波长,结果按从小到大返回。
适用范围
UV/VIS、NIR;要求波长数据能力;只读。
调用前提
设备已打开。结果用于验证用户请求波段是否合法。
输入参数
无普通输入值。
输出参数
| 参数 | Python 类型 | 方向 | 单位 | 说明 |
|---|---|---|---|---|
start_nm |
ctypes.c_double() + ctypes.byref() |
输出 | nm | 完整范围的最小波长 |
end_nm |
ctypes.c_double() + ctypes.byref() |
输出 | nm | 完整范围的最大波长,应大于 start_nm |
返回值
| 返回值 | 含义 |
|---|---|
0 |
两个输出变量已写入 |
-3 |
设备未打开 |
-5 |
任一输出变量无效或内部数据分配失败 |
-4/-7/-8/-9 |
波长数据或通信异常 |
Python 示例
import ctypes
start_nm = ctypes.c_double()
end_nm = ctypes.c_double()
require_success(
sdk.pynect_direct_get_full_wavelength_range(
ctypes.byref(start_nm), ctypes.byref(end_nm)
),
"Get full wavelength range",
)
print(f"Range: {start_nm.value:.3f}-{end_nm.value:.3f} nm")
常见错误
将输出变量顺序写反,或把 nm 当作像素索引。关联 API:pynect_direct_set_selected_wavelength_range、pynect_direct_get_full_wavelength_data。
pynect_direct_get_full_wavelength_data
功能说明
读取每个探测器数据点对应的完整波长数组。该接口只读取波长坐标,不采集强度。
适用范围
UV/VIS、NIR;要求 PYNECT_DIRECT_CAP_WAVELENGTH_DATA;只读。
调用前提
设备已打开;先调用 pynect_direct_get_wavelength_count,按返回点数创建 ctypes.c_double 数组。
输入参数
| 参数 | Python 类型 | 方向 | 单位/容量 | 说明 |
|---|---|---|---|---|
buffer |
(ctypes.c_double * count)() |
输入/输出 | count 个 double 元素 |
DLL 将波长依次写入该数组 |
max_len |
int |
输入 | 数据点,不是字节数 | 必须至少等于完整波长点数 |
输出参数
成功后 buffer[0:max_len] 中的有效部分为波长值,单位 nm。实际有效元素数等于 pynect_direct_get_wavelength_count 返回值。
返回值
| 返回值 | 含义 |
|---|---|
0 |
波长数组读取成功 |
-3 |
设备未打开 |
-5 |
缓冲区无效、max_len <= 0 或容量小于实际点数 |
-4/-7/-8/-9 |
返回数据长度异常、通信或超时错误 |
Python 示例
import ctypes
count = ctypes.c_uint16()
require_success(
sdk.pynect_direct_get_wavelength_count(ctypes.byref(count)),
"Get wavelength count",
)
wavelengths = (ctypes.c_double * count.value)()
require_success(
sdk.pynect_direct_get_full_wavelength_data(
wavelengths, count.value
),
"Get full wavelength data",
)
print(wavelengths[0], wavelengths[count.value - 1])
常见错误
把 max_len 传成数组字节数,或使用 ctypes.c_float 数组。关联 API:pynect_direct_get_wavelength_count、pynect_direct_get_full_spectrum_data。
pynect_direct_get_full_spectrum_data
功能说明
触发或读取一次完整光谱采集,将每个波长点对应的原始强度写入数组。
适用范围
UV/VIS、NIR;要求 PYNECT_DIRECT_CAP_SPECTRUM_DATA;只读采集。
调用前提
设备已打开;已按完整点数创建 ctypes.c_uint16 数组。普通软件采集时应确保外触发没有处于等待状态。
输入参数
| 参数 | Python 类型 | 方向 | 单位/容量 | 说明 |
|---|---|---|---|---|
buffer |
(ctypes.c_uint16 * count)() |
输入/输出 | count 个 16 位元素 |
接收原始光谱强度 |
max_len |
int |
输入 | 数据点,不是字节数 | 必须至少等于完整光谱点数 |
输出参数
成功后 buffer[index] 与波长数组的 wavelengths[index] 一一对应。每个强度值存储范围为 0-65535。
返回值
| 返回值 | 含义 |
|---|---|
0 |
完整强度数组采集成功 |
-3 |
设备未打开 |
-5 |
缓冲区无效、容量不足或内存分配失败 |
-4/-7/-8/-9 |
光谱格式、通信、校验或等待超时错误 |
Python 示例
import ctypes
count = ctypes.c_uint16()
require_success(
sdk.pynect_direct_get_wavelength_count(ctypes.byref(count)),
"Get wavelength count",
)
intensities = (ctypes.c_uint16 * count.value)()
require_success(
sdk.pynect_direct_get_full_spectrum_data(
intensities, count.value
),
"Get full spectrum data",
)
print("Intensity range:", min(intensities), max(intensities))
常见错误
使用字节数组接收 16 位强度,或在外触发等待状态下调用普通采谱接口。关联 API:pynect_direct_get_full_wavelength_data、积分时间和平均次数接口。
pynect_direct_set_selected_wavelength_range
功能说明
根据用户请求的波长边界选择一段连续像素窗口,供后续指定波段接口使用。该设置只保存在当前 DLL 会话中。
适用范围
UV/VIS、NIR;临时设置;不改变设备标定或物理波长范围。
调用前提
设备已打开;先读取完整波长范围。start_nm < end_nm,并且两个边界都位于完整范围内。
输入参数
| 参数 | Python 类型 | 方向 | 单位/范围 | 说明 |
|---|---|---|---|---|
start_nm |
float / ctypes.c_double |
输入 | nm;不小于完整起始波长 | 请求波段下限 |
end_nm |
float / ctypes.c_double |
输入 | nm;不大于完整结束波长 | 请求波段上限,必须大于 start_nm |
输出参数
无直接输出。实际匹配边界、像素索引和点数通过 pynect_direct_get_selected_wavelength_range 读取。
返回值
| 返回值 | 含义 |
|---|---|
0 |
已找到至少一个有效数据点并保存波段状态 |
-3 |
设备未打开 |
-5 |
边界顺序错误、超出完整范围、没有匹配点或内存分配失败 |
-4/-7/-8/-9 |
读取完整波长数据时发生通信错误 |
Python 示例
request_start_nm = 900.0
request_end_nm = 950.0
require_success(
sdk.pynect_direct_set_selected_wavelength_range(
request_start_nm, request_end_nm
),
"Set selected wavelength range",
)
常见错误
使用设备范围以外的边界,或认为设置后会永久改变硬件。设备关闭、重新打开或复位后需要重新设置。关联 API:pynect_direct_get_full_wavelength_range、pynect_direct_get_selected_wavelength_range。
pynect_direct_get_selected_wavelength_range
功能说明
读取最近一次指定波段设置的请求边界、实际像素边界、像素索引和数据点数。
适用范围
UV/VIS、NIR;只读。
调用前提
设备已打开,并已成功调用 pynect_direct_set_selected_wavelength_range。
输入参数
无普通输入值。
输出参数
| 字段 | Python 类型 | 方向 | 单位 | 说明 |
|---|---|---|---|---|
out_range.request_start_nm |
float 字段 |
输出 | nm | 用户请求的起始边界 |
out_range.request_end_nm |
float 字段 |
输出 | nm | 用户请求的结束边界 |
out_range.actual_start_nm |
float 字段 |
输出 | nm | 第一个匹配像素的实际波长 |
out_range.actual_end_nm |
float 字段 |
输出 | nm | 最后一个匹配像素的实际波长 |
start_pixel / end_pixel |
16 位整数字段 | 输出 | 像素索引 | 完整数组中的闭区间索引 |
count |
16 位整数字段 | 输出 | 数据点 | 后续指定波段数组的最小容量 |
返回值
| 返回值 | 含义 |
|---|---|
0 |
输出结构已写入 |
-1 |
当前会话尚未设置有效波段 |
-3 |
设备未打开 |
-5 |
输出对象无效 |
Python 示例
import ctypes
from minimal_test import PynectDirectSelectedWavelengthRange
selected = PynectDirectSelectedWavelengthRange()
require_success(
sdk.pynect_direct_get_selected_wavelength_range(
ctypes.byref(selected)
),
"Get selected wavelength range",
)
print(selected.actual_start_nm, selected.actual_end_nm, selected.count)
常见错误
未先设置波段,或使用请求边界计算数组长度;正确容量是 selected.count。关联 API:pynect_direct_set_selected_wavelength_range、两个指定波段数据接口。
pynect_direct_get_selected_wavelength_data
功能说明
读取当前指定波段内的波长数组。
适用范围
UV/VIS、NIR;只读。
调用前提
设备已打开,波段已设置,并已读取 selected.count。
输入参数
| 参数 | Python 类型 | 方向 | 容量 | 说明 |
|---|---|---|---|---|
buffer |
(ctypes.c_double * selected.count)() |
输入/输出 | 至少 selected.count 个元素 |
接收波段内的 nm 值 |
max_len |
int |
输入 | 数据点 | 必须大于或等于 selected.count |
输出参数
成功后数组包含从 actual_start_nm 到 actual_end_nm 的连续波长点。
返回值
| 返回值 | 含义 |
|---|---|
0 |
波段波长数组读取成功 |
-1 |
未设置有效波段 |
-3 |
设备未打开 |
-5 |
缓冲区无效或容量不足 |
-4/-7/-8/-9 |
完整波长读取或通信错误 |
Python 示例
selected_wavelengths = (ctypes.c_double * selected.count)()
require_success(
sdk.pynect_direct_get_selected_wavelength_data(
selected_wavelengths, selected.count
),
"Get selected wavelength data",
)
print(selected_wavelengths[0], selected_wavelengths[selected.count - 1])
常见错误
用完整光谱点数代替 selected.count 虽不会必然失败,但会造成含义不清;容量过小会返回 -5。关联 API:pynect_direct_get_selected_wavelength_range。
pynect_direct_get_selected_spectrum_data
功能说明
采集一次完整光谱,并把当前指定波段对应的强度区间复制到输出数组。
适用范围
UV/VIS、NIR;只读采集。
调用前提
设备已打开,波段已设置,并已按 selected.count 创建 16 位强度数组。
输入参数
| 参数 | Python 类型 | 方向 | 容量 | 说明 |
|---|---|---|---|---|
buffer |
(ctypes.c_uint16 * selected.count)() |
输入/输出 | 至少 selected.count 个元素 |
接收波段强度 |
max_len |
int |
输入 | 数据点 | 必须大于或等于 selected.count |
输出参数
成功后 buffer[index] 与 pynect_direct_get_selected_wavelength_data 返回数组的相同索引一一对应。
返回值
| 返回值 | 含义 |
|---|---|
0 |
波段强度采集成功 |
-1 |
未设置有效波段 |
-3 |
设备未打开 |
-5 |
缓冲区无效、容量不足或内存分配失败 |
-4/-7/-8/-9 |
完整光谱采集或通信错误 |
Python 示例
selected_intensities = (ctypes.c_uint16 * selected.count)()
require_success(
sdk.pynect_direct_get_selected_spectrum_data(
selected_intensities, selected.count
),
"Get selected spectrum data",
)
print(min(selected_intensities), max(selected_intensities))
常见错误
波长数组与强度数组使用了不同的波段状态,或修改波段后仍沿用旧 count。关联 API:pynect_direct_set_selected_wavelength_range、pynect_direct_get_selected_wavelength_data。
15.4 设备状态与身份信息
pynect_direct_get_calibration_coefficients
功能说明
读取设备保存的四个波长标定系数,通常按从低阶到高阶的顺序存入数组。该接口只读取系数,不修改标定。
适用范围
UV/VIS、NIR;要求 PYNECT_DIRECT_CAP_CALIBRATION;只读。
调用前提
设备已打开。应用必须分配恰当的双精度数组;系数的物理解释应遵循设备标定资料。
输入参数
| 参数 | Python 类型 | 方向 | 容量 | 说明 |
|---|---|---|---|---|
coeffs |
(ctypes.c_double * 4)() |
输入/输出 | 至少 4 个 double | 接收四个波长标定系数 |
输出参数
成功后可读取 coeffs[0] 到 coeffs[3]。本接口不返回系数数量,调用方必须固定分配 4 个元素。
返回值
| 返回值 | 含义 |
|---|---|
0 |
四个系数读取成功 |
-3 |
设备未打开 |
-5 |
输出数组无效 |
-4/-7/-8/-9 |
数据长度、校验、通信或超时错误 |
Python 示例
import ctypes
coefficients = (ctypes.c_double * 4)()
require_success(
sdk.pynect_direct_get_calibration_coefficients(coefficients),
"Get calibration coefficients",
)
print(list(coefficients))
常见错误
只分配一个 ctypes.c_double,或自行用系数替换 SDK 已返回的波长数组。关联 API:pynect_direct_get_full_wavelength_data。
pynect_direct_get_temperature
功能说明
读取设备内部温度传感器值并转换为摄氏度浮点数。
适用范围
UV/VIS、NIR;要求 PYNECT_DIRECT_CAP_TEMPERATURE;只读。
调用前提
设备已打开且能力位表明支持温度读取。
输入参数
无普通输入值。
输出参数
| 参数 | Python 类型 | 方向 | 单位 | 说明 |
|---|---|---|---|---|
temp_c |
ctypes.c_float() + ctypes.byref() |
输出 | 摄氏度 | 当前设备报告的内部温度,可为小数或负数 |
返回值
| 返回值 | 含义 |
|---|---|
0 |
温度读取成功 |
-3 |
设备未打开 |
-5 |
输出变量无效 |
-4/-7/-8/-9 |
返回长度、通信、校验或超时错误 |
Python 示例
import ctypes
temperature_c = ctypes.c_float()
require_success(
sdk.pynect_direct_get_temperature(ctypes.byref(temperature_c)),
"Get temperature",
)
print(f"Temperature: {temperature_c.value:.2f} C")
常见错误
使用 ctypes.c_double 接收单精度输出,或将某些设备报告的固定值直接认定为环境温度。关联 API:pynect_direct_get_capabilities。
pynect_direct_get_hardware_version
功能说明
读取设备硬件版本并写入以 \0 结尾的字符串缓冲区。
适用范围
UV/VIS、NIR;要求硬件版本能力;只读。
调用前提
设备已打开。准备至少 2 字节的可写字符缓冲区,推荐 64 字节以避免截断。
输入参数
| 参数 | Python 类型 | 方向 | 范围/容量 | 说明 |
|---|---|---|---|---|
version_str |
ctypes.create_string_buffer |
输入/输出 | 推荐 64 字节 | 接收硬件版本字符串 |
max_len |
int |
输入 | 至少 2 |
缓冲区总字节数,包含结尾 \0 空间 |
输出参数
成功后读取 version_str.value 并解码。UV/VIS 常见格式类似 03.4D.43.63;NIR 可能返回设备定义的版本文本。
返回值
| 返回值 | 含义 |
|---|---|
0 |
版本字符串读取成功 |
-3 |
设备未打开 |
-5 |
缓冲区无效或 max_len <= 1 |
-4/-7/-8/-9 |
返回数据或通信异常 |
Python 示例
import ctypes
version_buffer = ctypes.create_string_buffer(64)
require_success(
sdk.pynect_direct_get_hardware_version(
version_buffer, len(version_buffer)
),
"Get hardware version",
)
print(version_buffer.value.decode("utf-8", errors="replace"))
常见错误
传入不可写的 Python 字符串,或 max_len 大于实际缓冲区容量。关联 API:pynect_direct_get_device_info。
pynect_direct_get_serial_number
功能说明
读取光谱仪业务序列号。该编号由设备保存,与 USB 芯片序列号用途不同。
适用范围
UV/VIS、NIR;只读。NIR 当前可能返回通用字符串 NIR,不保证是唯一编号。
调用前提
设备已打开。需要唯一绑定时,应同时记录芯片序列号。
输入参数
| 参数 | Python 类型 | 方向 | 范围/容量 | 说明 |
|---|---|---|---|---|
sn |
ctypes.create_string_buffer |
输入/输出 | 推荐 64 字节 | 接收设备业务序列号 |
max_len |
int |
输入 | 至少 2 |
缓冲区总字节数,包含结尾空间 |
输出参数
成功后从 sn.value 读取字节串并解码。UV/VIS 最多读取设备保存的 12 字节内容;缓冲区较小时会截断。
返回值
| 返回值 | 含义 |
|---|---|
0 |
序列号或 NIR 通用标识读取成功 |
-3 |
设备未打开 |
-5 |
缓冲区无效或 max_len <= 1 |
-4/-7/-8/-9 |
UV/VIS 数据长度或通信异常 |
Python 示例
import ctypes
serial_buffer = ctypes.create_string_buffer(64)
require_success(
sdk.pynect_direct_get_serial_number(
serial_buffer, len(serial_buffer)
),
"Get device serial number",
)
print(serial_buffer.value.decode("utf-8", errors="replace"))
常见错误
把返回值用于多设备唯一绑定,而忽略 NIR 可能只返回 NIR。关联 API:pynect_direct_get_chip_serial_by_index。
pynect_direct_get_detector_serial_number
功能说明
读取 UV/VIS 设备中的探测器序列号,最多复制设备返回的 8 字节标识。
适用范围
UV/VIS;只读。NIR 返回 -11。
调用前提
设备已打开。必须提供有效可写缓冲区;推荐 16 或 64 字节。由于低层接口要求严格,禁止传空缓冲区或小于 2 的长度。
输入参数
| 参数 | Python 类型 | 方向 | 范围/容量 | 说明 |
|---|---|---|---|---|
sn |
ctypes.create_string_buffer |
输入/输出 | 推荐至少 16 字节 | 接收最多 8 字节探测器序列号及结尾字符 |
max_len |
int |
输入 | 至少 2,不得超过实际容量 |
缓冲区总字节数 |
输出参数
成功后从 sn.value 取得探测器标识并解码。内容是否可打印由设备数据决定。
返回值
| 返回值 | 含义 |
|---|---|
0 |
探测器序列号读取成功 |
-3 |
设备未打开 |
-4/-7/-8/-9 |
返回长度或通信异常 |
-11 |
当前设备不是支持该功能的 UV/VIS 设备 |
Python 示例
import ctypes
detector_serial = ctypes.create_string_buffer(16)
code = sdk.pynect_direct_get_detector_serial_number(
detector_serial, len(detector_serial)
)
if code == -11:
print("Detector serial is not supported")
else:
require_success(code, "Get detector serial")
print(detector_serial.value.decode("utf-8", errors="replace"))
常见错误
在 NIR 设备上把 -11 当作硬件故障,或传入长度为 0 的缓冲区。关联 API:pynect_direct_get_capabilities、pynect_direct_get_serial_number。
pynect_direct_get_device_model
功能说明
读取设备型号字符串。UV/VIS 返回设备保存的型号;NIR 根据可用硬件信息生成型号,信息不足时返回 NIR。
适用范围
UV/VIS、NIR;只读。
调用前提
设备已打开,并准备有效字符缓冲区。
输入参数
| 参数 | Python 类型 | 方向 | 范围/容量 | 说明 |
|---|---|---|---|---|
model |
ctypes.create_string_buffer |
输入/输出 | 推荐 64 字节 | 接收型号字符串 |
max_len |
int |
输入 | 至少 2 |
包含结尾字符空间的缓冲区容量 |
输出参数
成功后从 model.value 取得字节串。UV/VIS 最多使用设备返回的 16 字节型号内容。
返回值
| 返回值 | 含义 |
|---|---|
0 |
型号读取成功;NIR 无详细信息时也可能返回通用 NIR |
-3 |
设备未打开 |
-5 |
缓冲区无效或长度不足 |
-4/-7/-8/-9 |
UV/VIS 返回数据或通信异常 |
Python 示例
import ctypes
model_buffer = ctypes.create_string_buffer(64)
require_success(
sdk.pynect_direct_get_device_model(
model_buffer, len(model_buffer)
),
"Get device model",
)
print(model_buffer.value.decode("utf-8", errors="replace"))
常见错误
把通用 NIR 文本误认为唯一型号,或忽略字符串可能被截断。关联 API:pynect_direct_get_device_info。
pynect_direct_get_usb_status
功能说明
读取 UV/VIS 设备内部报告的 USB 连接状态。它是设备状态字段,不替代 Windows 设备枚举结果。
适用范围
UV/VIS;要求 PYNECT_DIRECT_CAP_USB_STATUS;只读。NIR 返回 -11。
调用前提
设备已打开并支持 USB 状态查询。
输入参数
无普通输入值。
输出参数
| 参数 | Python 类型 | 方向 | 输出值 | 说明 |
|---|---|---|---|---|
connected |
ctypes.c_int() + ctypes.byref() |
输出 | 1 或 0 |
1 表示设备报告已连接,0 表示未连接 |
返回值
| 返回值 | 含义 |
|---|---|
0 |
状态变量已写入;连接状态应读取 connected.value |
-3 |
设备未打开 |
-4/-7/-8/-9 |
返回数据或通信异常 |
-11 |
当前设备不支持该查询 |
Python 示例
import ctypes
connected = ctypes.c_int()
code = sdk.pynect_direct_get_usb_status(ctypes.byref(connected))
if code == -11:
print("USB status query is not supported")
else:
require_success(code, "Get USB status")
print("Connected:", bool(connected.value))
常见错误
把函数返回的 0 理解为“未连接”;连接状态位于输出变量中。关联 API:pynect_direct_scan_devices、pynect_direct_get_capabilities。
15.5 氙灯、USB 参数与 DAC
pynect_direct_set_xenon_pulse
功能说明
设置氙灯脉冲的完整周期和一个周期内的高电平宽度。该函数会改变当前光源时序,不负责打开或关闭氙灯,也不会自动检查目标时序是否适合具体灯源。
适用范围
UV/VIS;要求 PYNECT_DIRECT_CAP_XENON。NIR 返回 -11。这是光源控制接口,须由熟悉设备和光源安全要求的人员使用。
调用前提
设备已打开,capability 已确认。建议先用 pynect_direct_get_xenon_mode 确认氙灯处于关闭状态,再读取并记录原脉冲参数。目标值必须来自设备资料或实验室批准的配置。
输入参数
| 参数 | Python 类型 | 方向 | 单位/范围 | 说明 |
|---|---|---|---|---|
period_10ns |
Python int,按 ctypes.c_uint 传入 |
输入 | 10 ns;0-4294967295 |
一个完整脉冲周期的计数值 |
high_10ns |
Python int,按 ctypes.c_uint 传入 |
输入 | 10 ns;0-4294967295 |
一个周期内高电平持续时间;通常不得大于 period_10ns |
Python 传入前应自行检查设备允许范围。超出无符号 32 位范围的整数可能被截断,不能依赖 DLL 自动拒绝。
输出参数
无。
返回值
| 返回值 | 含义 |
|---|---|
0 |
脉冲参数设置成功 |
-3 |
设备未打开 |
-4/-7/-8/-9 |
设备拒绝、返回校验异常或通信超时 |
-10 |
设备报告当前写操作受保护 |
-11 |
当前设备不支持氙灯控制 |
Python 示例
ALLOW_XENON_CONFIGURATION = False
# 以下数值仅演示 10 ns 计数的写法,必须替换为设备批准值。
target_period_10ns = 10_000_000
target_high_10ns = 1_000_000
if ALLOW_XENON_CONFIGURATION:
if not (0 < target_high_10ns <= target_period_10ns <= 0xFFFFFFFF):
raise ValueError("Invalid xenon pulse timing")
require_success(
sdk.pynect_direct_set_xenon_pulse(
target_period_10ns, target_high_10ns
),
"Set xenon pulse",
)
else:
print("Skipped: xenon configuration is disabled")
常见错误
把参数单位误写成微秒或毫秒;高电平宽度大于周期;氙灯已点亮时直接改变时序;未记录原值。关联 API:pynect_direct_get_xenon_pulse、pynect_direct_get_xenon_mode、pynect_direct_set_xenon_mode。
pynect_direct_get_xenon_pulse
功能说明
读取当前氙灯脉冲周期和高电平宽度。函数只查询参数,不改变氙灯模式或输出状态。
适用范围
UV/VIS;要求 PYNECT_DIRECT_CAP_XENON;只读。NIR 返回 -11。
调用前提
设备已打开并支持氙灯控制。准备两个独立的无符号 32 位输出变量。
输入参数
无普通输入值。
输出参数
| 参数 | Python 类型 | 方向 | 单位/范围 | 说明 |
|---|---|---|---|---|
period |
ctypes.c_uint() + ctypes.byref() |
输出 | 10 ns;无符号 32 位 | 当前完整周期计数 |
high |
ctypes.c_uint() + ctypes.byref() |
输出 | 10 ns;无符号 32 位 | 当前高电平宽度计数 |
实际时间可按 计数值 * 10 ns 换算;换算为秒时乘以 1e-8。
返回值
| 返回值 | 含义 |
|---|---|
0 |
两个输出变量均已写入 |
-3 |
设备未打开 |
-4/-7/-8/-9 |
返回数据长度、校验或通信异常 |
-11 |
当前设备不支持氙灯控制 |
Python 示例
import ctypes
period = ctypes.c_uint()
high = ctypes.c_uint()
code = sdk.pynect_direct_get_xenon_pulse(
ctypes.byref(period), ctypes.byref(high)
)
if code == -11:
print("Xenon pulse query is not supported")
else:
require_success(code, "Get xenon pulse")
print("Period:", period.value, "x 10 ns")
print("High level:", high.value, "x 10 ns")
print("Period (s):", period.value * 1e-8)
常见错误
使用 ctypes.c_uint16 导致数据宽度不足;忘记 ctypes.byref();把函数返回码当成周期。关联 API:pynect_direct_set_xenon_pulse。
pynect_direct_set_xenon_mode
功能说明
设置氙灯工作模式,可关闭氙灯、进入连续模式或请求单次模式。该函数可能直接改变光源输出状态。
适用范围
UV/VIS;要求 PYNECT_DIRECT_CAP_XENON。NIR 返回 -11。除关闭模式外均属于需要现场确认的光源操作。
调用前提
设备已打开,氙灯脉冲参数已确认,光路和防护装置已就绪。应用应在 finally 清理流程或退出流程中关闭氙灯。
输入参数
| 参数 | Python 类型 | 方向 | 允许值 | 说明 |
|---|---|---|---|---|
mode |
Python int,按 ctypes.c_uint8 传入 |
输入 | 0x00 |
XENON_OFF,关闭 |
mode |
同上 | 输入 | 0x01 |
XENON_CONTINUOUS,连续模式 |
mode |
同上 | 输入 | 0x81 |
XENON_SINGLE,单次模式 |
不要传入表中未定义的模式值。
输出参数
无。
返回值
| 返回值 | 含义 |
|---|---|
0 |
模式命令执行成功 |
-3 |
设备未打开 |
-4/-7/-8/-9 |
设备返回、校验或通信异常 |
-10 |
设备报告当前写操作受保护 |
-11 |
当前设备不支持氙灯控制 |
Python 示例
XENON_OFF = 0x00
XENON_CONTINUOUS = 0x01
XENON_SINGLE = 0x81
ALLOW_XENON_OUTPUT = False
target_mode = XENON_OFF
if target_mode not in (XENON_OFF, XENON_CONTINUOUS, XENON_SINGLE):
raise ValueError("Unknown xenon mode")
if target_mode == XENON_OFF or ALLOW_XENON_OUTPUT:
require_success(
sdk.pynect_direct_set_xenon_mode(target_mode),
"Set xenon mode",
)
else:
print("Skipped: xenon output is disabled")
常见错误
把十进制 81 当作十六进制 0x81;程序异常退出后没有关闭氙灯;未先确认脉冲时序。关联 API:pynect_direct_get_xenon_mode、pynect_direct_set_xenon_pulse。
pynect_direct_get_xenon_mode
功能说明
读取当前氙灯模式。函数只查询状态,不会关闭或触发氙灯。
适用范围
UV/VIS;要求 PYNECT_DIRECT_CAP_XENON;只读。NIR 返回 -11。
调用前提
设备已打开并支持氙灯控制。准备一个 8 位无符号输出变量。
输入参数
无普通输入值。
输出参数
| 参数 | Python 类型 | 方向 | 输出值 | 说明 |
|---|---|---|---|---|
mode |
ctypes.c_uint8() + ctypes.byref() |
输出 | 0x00 |
关闭 |
mode |
同上 | 输出 | 0x01 |
连续模式 |
mode |
同上 | 输出 | 0x81 |
单次模式 |
设备若返回其他值,应用应显示原始十六进制值,而不是自行猜测含义。
返回值
| 返回值 | 含义 |
|---|---|
0 |
mode.value 已写入 |
-3 |
设备未打开 |
-4/-7/-8/-9 |
返回数据长度、校验或通信异常 |
-11 |
当前设备不支持氙灯控制 |
Python 示例
import ctypes
mode_names = {
0x00: "off",
0x01: "continuous",
0x81: "single",
}
mode = ctypes.c_uint8()
code = sdk.pynect_direct_get_xenon_mode(ctypes.byref(mode))
if code == -11:
print("Xenon mode query is not supported")
else:
require_success(code, "Get xenon mode")
print(mode_names.get(mode.value, f"unknown 0x{mode.value:02X}"))
常见错误
用 ctypes.c_int 替代 8 位输出容器,或把未知值默认当成关闭。关联 API:pynect_direct_set_xenon_mode。
pynect_direct_set_usb_baud_rate
功能说明
写入 UV/VIS 设备的 USB 通信速率参数。该参数是设备使用的无符号 16 位配置码,不保证与常见串口波特率数值一一对应。
适用范围
UV/VIS;设备专用维护接口。NIR 返回 -11。错误设置可能造成后续通信失败,不建议普通测量程序调用。
调用前提
设备已打开,已读取并保存原参数,并从设备供应方资料获得准确的目标配置码和恢复方法。仅凭常见波特率数值不得调用。
输入参数
| 参数 | Python 类型 | 方向 | 范围 | 说明 |
|---|---|---|---|---|
rate |
Python int,按 ctypes.c_uint16 传入 |
输入 | 0-65535 |
设备 USB 速率原始参数,不直接表示 bit/s |
输出参数
无。
返回值
| 返回值 | 含义 |
|---|---|
0 |
参数写入命令成功;仍需验证后续通信 |
-3 |
设备未打开 |
-4/-7/-8/-9 |
设备返回、校验或通信异常 |
-10 |
设备报告当前写操作受保护 |
-11 |
当前设备不支持该设置 |
Python 示例
ALLOW_USB_PARAMETER_WRITE = False
approved_rate_parameter = None
if ALLOW_USB_PARAMETER_WRITE:
if approved_rate_parameter is None:
raise ValueError("Set the supplier-approved USB parameter first")
if not 0 <= approved_rate_parameter <= 0xFFFF:
raise ValueError("USB parameter must fit uint16")
require_success(
sdk.pynect_direct_set_usb_baud_rate(approved_rate_parameter),
"Set USB rate parameter",
)
else:
print("Skipped: USB parameter write is disabled")
常见错误
直接传入 115200 等常见串口波特率并认为设备会自动换算;未保存原值;写入后没有立即验证设备通信。关联 API:pynect_direct_get_usb_baud_rate、pynect_direct_get_usb_status。
pynect_direct_get_usb_baud_rate
功能说明
读取 UV/VIS 设备保存的 USB 通信速率原始参数。该函数不会修改通信设置。
适用范围
UV/VIS;只读。NIR 返回 -11。
调用前提
设备已打开。准备一个无符号 16 位输出变量。
输入参数
无普通输入值。
输出参数
| 参数 | Python 类型 | 方向 | 范围 | 说明 |
|---|---|---|---|---|
rate |
ctypes.c_uint16() + ctypes.byref() |
输出 | 0-65535 |
设备 USB 速率原始参数 |
除非设备资料明确给出换算关系,否则只记录 rate.value,不要在界面中加上 bit/s、baud 等单位。
返回值
| 返回值 | 含义 |
|---|---|
0 |
rate.value 已写入 |
-3 |
设备未打开 |
-4/-7/-8/-9 |
返回数据长度、校验或通信异常 |
-11 |
当前设备不支持该查询 |
Python 示例
import ctypes
rate_parameter = ctypes.c_uint16()
code = sdk.pynect_direct_get_usb_baud_rate(
ctypes.byref(rate_parameter)
)
if code == -11:
print("USB rate parameter is not supported")
else:
require_success(code, "Get USB rate parameter")
print("Raw USB rate parameter:", rate_parameter.value)
常见错误
给原始值附加未经确认的波特率单位;把返回码 0 当成查询结果;输出变量类型错误。关联 API:pynect_direct_set_usb_baud_rate。
pynect_direct_set_dac_voltage
功能说明
设置设备 DAC 的 12 位原始输出码。函数名中的 voltage 不表示参数单位是伏特;实际电压取决于设备的基准电压、输出电路和标定关系。
适用范围
UV/VIS;要求 PYNECT_DIRECT_CAP_DAC。NIR 返回 -11。该接口会改变硬件输出,调用前必须确认外部负载和允许电压范围。
调用前提
设备已打开,DAC capability 已确认,外部连接安全,并已根据设备资料把目标电压换算成批准的原始码值。建议先读取并记录当前码值。
输入参数
| 参数 | Python 类型 | 方向 | 范围/单位 | 说明 |
|---|---|---|---|---|
dac_value |
Python int,按 ctypes.c_uint16 传入 |
输入 | 原始码 0-4095 |
12 位 DAC 码值,不是 mV 或 V |
尽管 ABI 容器可表示到 65535,应用层必须限制到 12 位范围。
输出参数
无。
返回值
| 返回值 | 含义 |
|---|---|
0 |
DAC 码值设置成功 |
-3 |
设备未打开 |
-4/-7/-8/-9 |
设备返回、校验或通信异常 |
-10 |
设备报告当前写操作受保护 |
-11 |
当前设备不支持 DAC |
Python 示例
ALLOW_DAC_OUTPUT = False
approved_dac_code = 0
if ALLOW_DAC_OUTPUT:
if not 0 <= approved_dac_code <= 4095:
raise ValueError("DAC code must be in the 12-bit range")
require_success(
sdk.pynect_direct_set_dac_voltage(approved_dac_code),
"Set DAC code",
)
else:
print("Skipped: DAC output is disabled")
常见错误
把 3.3、3300 等电压值直接传入;只按 uint16 范围检查而允许大于 4095;未确认负载。关联 API:pynect_direct_get_dac_voltage、pynect_direct_get_capabilities。
pynect_direct_get_dac_voltage
功能说明
读取当前 DAC 的 12 位原始码值。函数只返回设备码值,不执行电压换算。
适用范围
UV/VIS;要求 PYNECT_DIRECT_CAP_DAC;只读。NIR 返回 -11。
调用前提
设备已打开并支持 DAC。准备一个无符号 16 位输出变量。
输入参数
无普通输入值。
输出参数
| 参数 | Python 类型 | 方向 | 范围/单位 | 说明 |
|---|---|---|---|---|
dac_value |
ctypes.c_uint16() + ctypes.byref() |
输出 | 原始码 0-4095 |
当前 12 位 DAC 码值 |
若需要显示电压,必须使用设备资料规定的换算和标定参数,不能只按 码值 / 4095 猜测。
返回值
| 返回值 | 含义 |
|---|---|
0 |
dac_value.value 已写入 |
-3 |
设备未打开 |
-4/-7/-8/-9 |
返回数据长度、校验或通信异常 |
-11 |
当前设备不支持 DAC |
Python 示例
import ctypes
dac_code = ctypes.c_uint16()
code = sdk.pynect_direct_get_dac_voltage(ctypes.byref(dac_code))
if code == -11:
print("DAC query is not supported")
else:
require_success(code, "Get DAC code")
print("Raw 12-bit DAC code:", dac_code.value)
常见错误
把码值直接显示为伏特;使用有符号 16 位容器;把函数返回码当作 DAC 数据。关联 API:pynect_direct_set_dac_voltage。
15.6 外触发采集
pynect_direct_set_external_trigger_config
功能说明
设置外触发开关、触发类型和计划采集帧数。该函数改变当前设备的采集触发方式;配置错误时,普通采谱可能一直等待外部信号或超时。
适用范围
UV/VIS;要求 PYNECT_DIRECT_CAP_EXTERNAL_TRIGGER。NIR 返回 -11。这是临时采集配置,修改前应保存原配置并在实验结束后恢复。
调用前提
设备已打开,外部触发 capability 已确认,触发线、电平和时序符合设备资料。课堂基础实验应保持外触发关闭。
输入参数
| 参数 | Python 类型 | 方向 | 常用值/范围 | 说明 |
|---|---|---|---|---|
enable |
Python int,按 ctypes.c_uint8 传入 |
输入 | 0x00、0xAA |
0x00 为 TRIGGER_OFF;0xAA 为 SDK 定义的 TRIGGER_ON_RISE |
trig_type |
Python int,按 ctypes.c_uint8 传入 |
输入 | 常用 0xBB |
0xBB 为 TRIGGER_ON_LEVEL;其他取值必须以设备资料为准 |
scan_num |
Python int,按 ctypes.c_uint8 传入 |
输入 | 1-255 帧 |
计划采集帧数;0 的含义依设备而定,不建议使用 |
三个参数在 ABI 中都是无符号 8 位值。SDK 不替应用验证组合是否适合具体固件。
输出参数
无。
返回值
| 返回值 | 含义 |
|---|---|
0 |
外触发配置命令成功 |
-3 |
设备未打开 |
-4/-7/-8/-9 |
设备返回、校验或通信异常 |
-10 |
设备报告当前写操作受保护 |
-11 |
当前设备不支持外触发 |
Python 示例
import ctypes
TRIGGER_OFF = 0x00
TRIGGER_ON_LEVEL = 0xBB
ALLOW_TRIGGER_CONFIGURATION = False
old_enable = ctypes.c_uint8()
old_type = ctypes.c_uint8()
old_scan_num = ctypes.c_uint8()
require_success(
sdk.pynect_direct_get_external_trigger_config(
ctypes.byref(old_enable),
ctypes.byref(old_type),
ctypes.byref(old_scan_num),
),
"Read trigger configuration before changing it",
)
if ALLOW_TRIGGER_CONFIGURATION:
require_success(
sdk.pynect_direct_set_external_trigger_config(
TRIGGER_OFF, TRIGGER_ON_LEVEL, 1
),
"Disable external trigger",
)
else:
print("Skipped: trigger configuration is disabled")
常见错误
修改前未保存三个原值;把 scan_num 当成字节数;不了解接线就启用外触发;实验结束后未恢复配置。关联 API:pynect_direct_get_external_trigger_config、pynect_direct_get_spectrum_capture_status。
pynect_direct_get_external_trigger_config
功能说明
读取当前外触发开关值、触发类型值和计划采集帧数。函数只查询配置,不会启动采集。
适用范围
UV/VIS;要求 PYNECT_DIRECT_CAP_EXTERNAL_TRIGGER;只读。NIR 返回 -11。
调用前提
设备已打开并支持外触发。准备三个独立的无符号 8 位输出变量。
输入参数
无普通输入值。
输出参数
| 参数 | Python 类型 | 方向 | 输出范围 | 说明 |
|---|---|---|---|---|
enable |
ctypes.c_uint8() + ctypes.byref() |
输出 | 0-255 |
外触发开关原始值;常见 0x00 或 0xAA |
trig_type |
ctypes.c_uint8() + ctypes.byref() |
输出 | 0-255 |
触发类型原始值;常见电平类型为 0xBB |
scan_num |
ctypes.c_uint8() + ctypes.byref() |
输出 | 0-255 |
设备报告的计划帧数 |
未知原始值应以十六进制记录并查询对应设备资料。
返回值
| 返回值 | 含义 |
|---|---|
0 |
三个输出变量均已写入 |
-3 |
设备未打开 |
-4/-7/-8/-9 |
返回数据长度、校验或通信异常 |
-11 |
当前设备不支持外触发 |
Python 示例
import ctypes
enable = ctypes.c_uint8()
trigger_type = ctypes.c_uint8()
scan_num = ctypes.c_uint8()
code = sdk.pynect_direct_get_external_trigger_config(
ctypes.byref(enable),
ctypes.byref(trigger_type),
ctypes.byref(scan_num),
)
if code == -11:
print("External trigger is not supported")
else:
require_success(code, "Get external trigger configuration")
print(f"Enable: 0x{enable.value:02X}")
print(f"Type: 0x{trigger_type.value:02X}")
print("Scan frames:", scan_num.value)
常见错误
只读取一个输出变量;忘记 ctypes.byref();看到未知值后自行套用其他型号设备的含义。关联 API:pynect_direct_set_external_trigger_config。
pynect_direct_get_spectrum_capture_status
功能说明
读取外触发采集的 64 位原始状态字,用于判断设备当前采集状态或已完成情况。SDK 返回完整状态值,但不替应用解释各状态位。
适用范围
UV/VIS;要求 PYNECT_DIRECT_CAP_EXTERNAL_TRIGGER;只读。NIR 返回 -11。
调用前提
设备已打开并支持外触发。若要判断具体位含义,必须准备对应型号和固件版本的设备资料。
输入参数
无普通输入值。
输出参数
| 参数 | Python 类型 | 方向 | 范围/格式 | 说明 |
|---|---|---|---|---|
status |
ctypes.c_uint64() + ctypes.byref() |
输出 | 0-0xFFFFFFFFFFFFFFFF |
64 位原始采集状态字 |
在没有位定义资料时,可记录十六进制值用于诊断,不应仅凭某次观察给各位命名。
返回值
| 返回值 | 含义 |
|---|---|
0 |
status.value 已写入 |
-3 |
设备未打开 |
-4/-7/-8/-9 |
返回数据长度、校验或通信异常 |
-11 |
当前设备不支持外触发状态查询 |
Python 示例
import ctypes
capture_status = ctypes.c_uint64()
code = sdk.pynect_direct_get_spectrum_capture_status(
ctypes.byref(capture_status)
)
if code == -11:
print("Capture status is not supported")
else:
require_success(code, "Get capture status")
print(f"Capture status: 0x{capture_status.value:016X}")
常见错误
使用 ctypes.c_uint32 丢失高 32 位;把函数返回码当成状态值;没有设备位定义就把非零值解释为“已完成”。关联 API:pynect_direct_get_external_trigger_config、pynect_direct_external_spectrum_control。
pynect_direct_external_spectrum_control
功能说明
请求并读取指定外触发帧的原始光谱强度。缓冲区中每个数据点是无符号 16 位整数,但公开参数按字节指针传入;函数成功后返回写入的总字节数,而不是标准成功码 0。
适用范围
UV/VIS;要求 PYNECT_DIRECT_CAP_EXTERNAL_TRIGGER 和光谱数据能力;只读采集。NIR 返回 -11。
调用前提
设备已打开;外触发已按设备资料配置;目标帧已经采集完成;frame_index 的起始编号已按设备资料确认。先查询完整光谱点数,并按该点数分配 16 位数组。
输入参数
| 参数 | Python 类型 | 方向 | 单位/范围 | 说明 |
|---|---|---|---|---|
frame_index |
Python int,按 ctypes.c_uint16 传入 |
输入 | 0-65535,帧编号 |
要读取的外触发帧;是否从 0 开始以设备资料为准 |
data_out |
(ctypes.c_uint16 * point_capacity)() 后转换为 POINTER(c_uint8) |
输入/输出 | point_capacity 个 16 位元素 |
接收原始强度;虽然参数是字节指针,实际按 16 位光谱点写入 |
max_len |
Python int |
输入 | 数据点 | 缓冲区最多容纳的光谱点数,不是字节数 |
缓冲区实际字节容量必须至少为 max_len * 2。不要把 max_len 传成字节容量。
输出参数
成功时,前 返回值 / 2 个 ctypes.c_uint16 元素有效。每个元素范围为 0-65535,并应与设备的波长数组按索引对应。
返回值
| 返回值 | 含义 |
|---|---|
>= 0 |
成功读取的字节数;有效点数为 返回值 // 2,正常结果应为偶数 |
-3 |
设备未打开 |
-4 |
设备报告帧读取失败、状态异常或返回数据异常 |
-5 |
内存或缓冲区相关参数无效 |
-7/-8 |
数据校验或包头异常 |
-9 |
等待指定帧准备完成时超时 |
-11 |
当前设备不支持外触发帧读取 |
Python 示例
import ctypes
frame_index = 0
point_count = ctypes.c_uint16()
require_success(
sdk.pynect_direct_get_wavelength_count(ctypes.byref(point_count)),
"Get wavelength count",
)
intensities = (ctypes.c_uint16 * point_count.value)()
byte_pointer = ctypes.cast(
intensities, ctypes.POINTER(ctypes.c_uint8)
)
byte_count = sdk.pynect_direct_external_spectrum_control(
frame_index, byte_pointer, point_count.value
)
if byte_count < 0:
raise RuntimeError(f"Read external frame failed: {byte_count}")
if byte_count % 2 != 0:
raise RuntimeError("Device returned an odd spectrum byte count")
valid_points = byte_count // 2
values = list(intensities[:valid_points])
print("External frame points:", valid_points)
print("First intensity values:", values[:5])
常见错误
成功时仍要求返回 0;按字节数分配 c_uint8 数组后直接当 16 位强度使用;把 max_len 传成数组字节数;目标帧未完成就读取。关联 API:pynect_direct_get_wavelength_count、pynect_direct_get_spectrum_capture_status、完整波长数据接口。
15.7 Flash、写保护和设备复位
pynect_direct_set_flash_write_protect
功能说明
向设备发送 Flash/FLS 写保护流程使用的设备定义状态命令。该函数没有布尔参数,不是通用的“打开保护”或“关闭保护”开关;具体作用必须结合设备型号的维护资料理解。
适用范围
UV/VIS、NIR;要求 PYNECT_DIRECT_CAP_FLASH;高风险维护接口。普通测量、课堂实验和自动启动程序不得调用。
调用前提
设备已打开,已取得设备供应方或实验室管理员的明确维护授权,并已确认该型号对本命令的定义、当前状态和恢复流程。
输入参数
无。
输出参数
无。命令执行后的状态应另用 pynect_direct_get_flash_write_protect 查询。
返回值
| 返回值 | 含义 |
|---|---|
0 |
设备已接受状态命令;不等于任何 Flash 数据已写入 |
-3 |
设备未打开 |
-4/-7/-8/-9 |
设备拒绝、返回校验异常或通信超时 |
-10 |
设备报告写保护相关拒绝 |
Python 示例
import ctypes
ALLOW_FLASH_MAINTENANCE = False
if ALLOW_FLASH_MAINTENANCE:
before = ctypes.c_int()
require_success(
sdk.pynect_direct_get_flash_write_protect(ctypes.byref(before)),
"Read Flash state before maintenance command",
)
print("State before command:", before.value)
require_success(
sdk.pynect_direct_set_flash_write_protect(),
"Set device-defined Flash protection state",
)
else:
print("Skipped: Flash maintenance is disabled")
常见错误
根据英文函数名猜测它一定会“锁定”或“解锁”设备;未查询原状态;把返回 0 当成 Flash 写入成功。关联 API:pynect_direct_get_flash_write_protect、pynect_direct_flash_write。
pynect_direct_get_flash_write_protect
功能说明
读取设备报告的 Flash/FLS 写保护流程状态,并转换成 1 或 0。该布尔值只表示设备状态标记是否处于已启用值,不应脱离设备维护资料解释为“当前一定可写”或“当前一定不可写”。
适用范围
UV/VIS、NIR;要求 PYNECT_DIRECT_CAP_FLASH;只读。
调用前提
设备已打开。准备一个 ctypes.c_int 输出变量。
输入参数
无普通输入值。
输出参数
| 参数 | Python 类型 | 方向 | 输出值 | 说明 |
|---|---|---|---|---|
enabled |
ctypes.c_int() + ctypes.byref() |
输出 | 1 |
设备报告保护流程状态标记已启用 |
enabled |
同上 | 输出 | 0 |
设备报告该状态标记未启用 |
返回值
| 返回值 | 含义 |
|---|---|
0 |
enabled.value 已写入;状态值不在函数返回码中 |
-3 |
设备未打开 |
-4/-7/-8/-9 |
返回数据长度、校验或通信异常 |
-5 |
输出指针无效 |
Python 示例
import ctypes
flash_state = ctypes.c_int()
require_success(
sdk.pynect_direct_get_flash_write_protect(
ctypes.byref(flash_state)
),
"Get Flash protection state",
)
print("Device state flag enabled:", bool(flash_state.value))
常见错误
把函数返回的 0 当成“保护关闭”;看到输出 1 就在没有授权的情况下执行写入;使用 c_uint8 代替 c_int。关联 API:pynect_direct_set_flash_write_protect。
pynect_direct_reset_device
功能说明
向当前设备发送复位命令。复位可能中断正在进行的采集,并使临时参数或当前设备状态发生变化;DLL 中已选择的波长范围会失效,不能直接继续调用指定波段读取接口。
适用范围
UV/VIS、NIR;高风险设备控制接口。仅用于明确的故障恢复或维护流程。
调用前提
设备已打开;采集已停止;未保存的测量结果已处理;应用已准备在复位后重新确认设备是否在线、重新查询 capability,并恢复所需临时参数和波长范围。
输入参数
无。
输出参数
无。
返回值
| 返回值 | 含义 |
|---|---|
0 |
复位命令发送成功;仍需执行复位后检查 |
-3 |
设备未打开 |
-4/-7/-8/-9 |
设备返回、校验或通信异常 |
Python 示例
ALLOW_DEVICE_RESET = False
if ALLOW_DEVICE_RESET:
require_success(
sdk.pynect_direct_reset_device(),
"Reset device",
)
print("Reset sent; recheck connection, settings, and wavelength range")
else:
print("Skipped: device reset is disabled")
常见错误
采集过程中复位;复位成功后立即读取指定波段而没有重新设置范围;把命令发送成功等同于设备已经完全恢复。关联 API:pynect_direct_is_open、pynect_direct_get_capabilities、pynect_direct_set_selected_wavelength_range。
pynect_direct_flash_read
功能说明
读取指定 Flash/FLS 扇区的原始字节。函数不会解析标定、身份或配置字段;成功时直接返回实际读取字节数,而不是标准成功码 0。
适用范围
UV/VIS、NIR;要求 PYNECT_DIRECT_CAP_FLASH;只读维护接口。读取到的数据可能包含重要设备配置,必须按设备资料解释。
调用前提
设备已打开,扇区编号已由设备资料确认,调用者已按字节容量分配输出数组。UV/VIS 单次有效读取上限约为 1024 字节;更大的内容应按设备规定分段读取。
输入参数
| 参数 | Python 类型 | 方向 | 单位/范围 | 说明 |
|---|---|---|---|---|
sector |
Python int,按 ctypes.c_uint16 传入 |
输入 | 0-65535,扇区编号 |
只能使用设备资料明确允许读取的扇区 |
data_out |
(ctypes.c_uint8 * max_len)() |
输入/输出 | max_len 字节 |
接收原始 Flash/FLS 内容 |
max_len |
Python int |
输入 | 字节,必须大于 0 |
输出缓冲区容量;不是 16 位数据点数量 |
输出参数
成功后 data_out[0:返回值] 有效。未读取到的数组尾部仍是初始化值,不属于设备返回内容。
返回值
| 返回值 | 含义 |
|---|---|
>= 0 |
实际读取字节数;只处理该长度内的数据 |
-3 |
设备未打开 |
-4 |
设备报告读取失败或返回数据异常 |
-5 |
缓冲区无效、长度不大于 0 或内存分配失败 |
-7/-8 |
数据校验或包头异常 |
-9 |
等待 Flash 读取完成时超时 |
Python 示例
import ctypes
# 扇区编号必须替换为设备资料明确允许读取的值。
approved_sector = 0
buffer_capacity = 1024
buffer = (ctypes.c_uint8 * buffer_capacity)()
bytes_read = sdk.pynect_direct_flash_read(
approved_sector, buffer, buffer_capacity
)
if bytes_read < 0:
raise RuntimeError(f"Flash read failed: {bytes_read}")
payload = bytes(buffer[:bytes_read])
print("Flash bytes read:", bytes_read)
print("First bytes:", payload[:16].hex(" "))
常见错误
成功时要求返回 0;把 max_len 当成数据点数;解析整个缓冲区而不是前 bytes_read 字节;未经资料确认就猜测扇区含义。关联 API:pynect_direct_get_flash_write_protect、pynect_direct_get_capabilities。
pynect_direct_flash_write
功能说明
把原始字节写入指定 Flash/FLS 扇区。错误的扇区、长度或数据可能破坏设备标定、身份信息或启动配置,导致设备测量错误或无法使用。
适用范围
UV/VIS、NIR;要求 PYNECT_DIRECT_CAP_FLASH;最高风险维护接口。学生实验禁止调用,普通应用不应提供此功能入口。
调用前提
设备已打开;已获得书面维护授权;目标扇区和精确数据格式已由设备供应方确认;原扇区已有可验证备份;电源和 USB 连接稳定;写后校验及失败恢复方案已准备完成。
输入参数
| 参数 | Python 类型 | 方向 | 单位/范围 | 说明 |
|---|---|---|---|---|
sector |
Python int,按 ctypes.c_uint16 传入 |
输入 | 0-65535,扇区编号 |
必须是维护资料明确授权的目标扇区 |
data |
(ctypes.c_uint8 * len)(...) |
输入 | len 字节 |
待写入的完整原始字节,不得使用试验数据 |
len |
Python int |
输入 | 字节,必须大于 0 |
必须等于数组中有效数据的准确长度,并符合设备单次写入限制 |
输出参数
无。写入成功后应使用设备规定的只读方式重新读取并核对内容;不要仅依赖返回码判断长期保存结果。
返回值
| 返回值 | 含义 |
|---|---|
0 |
写入流程完成 |
-3 |
设备未打开 |
-4 |
设备拒绝写入、完成状态异常或数据返回异常 |
-5 |
数据为空、长度不大于 0 或内存分配失败 |
-7/-8 |
数据校验或包头异常 |
-9 |
等待写入完成时超时 |
-10 |
设备报告写保护,写入未获允许 |
Python 示例
import ctypes
ALLOW_FLASH_WRITE = False
approved_sector = None
approved_payload = None
if ALLOW_FLASH_WRITE:
if approved_sector is None or approved_payload is None:
raise ValueError("Approved sector and payload are required")
if not 0 <= approved_sector <= 0xFFFF:
raise ValueError("Flash sector must fit uint16")
payload_bytes = bytes(approved_payload)
if not payload_bytes:
raise ValueError("Flash payload must not be empty")
data = (ctypes.c_uint8 * len(payload_bytes)).from_buffer_copy(
payload_bytes
)
require_success(
sdk.pynect_direct_flash_write(
approved_sector, data, len(payload_bytes)
),
"Write approved Flash payload",
)
else:
print("Skipped: Flash write is disabled")
常见错误
用全零或随机数据测试写接口;扇区编号偏移一位;len 与有效数组长度不一致;没有备份和写后校验;出现超时后立即重复写入。关联 API:pynect_direct_flash_read、pynect_direct_get_flash_write_protect。
15.8 固化配置与狭缝信息
pynect_direct_set_stored_integration_time
功能说明
把默认积分时间写入设备的固化配置。它不同于只影响当前会话的 pynect_direct_set_integration_time,可能改变设备以后上电或初始化时采用的默认值。
适用范围
UV/VIS;要求 PYNECT_DIRECT_CAP_STORED_CONFIG;高风险持久配置接口。NIR 返回 -11。
调用前提
设备已打开;设备型号和允许的积分时间范围已确认;已读取并记录原固化值;已获得教师、实验室管理员或设备维护人员授权。
输入参数
| 参数 | Python 类型 | 方向 | 单位/范围 | 说明 |
|---|---|---|---|---|
us |
Python int,按 ctypes.c_uint 传入 |
输入 | 微秒;ABI 范围 0-4294967295 |
要保存的默认积分时间;应用应限制为设备允许的正整数范围 |
ABI 可表示范围不等于设备有效范围。超出设备资料范围的值不得通过试错方式写入。
输出参数
无。写入后应调用对应读取函数核对。
返回值
| 返回值 | 含义 |
|---|---|
0 |
固化积分时间写入命令成功 |
-3 |
设备未打开 |
-4/-7/-8/-9 |
设备拒绝、返回校验异常或通信超时 |
-10 |
设备报告当前写操作受保护 |
-11 |
当前设备不支持固化配置 |
Python 示例
import ctypes
ALLOW_STORED_CONFIG_WRITE = False
approved_integration_us = None
if ALLOW_STORED_CONFIG_WRITE:
if approved_integration_us is None:
raise ValueError("An approved integration time is required")
if not 0 < approved_integration_us <= 0xFFFFFFFF:
raise ValueError("Stored integration time must fit uint32")
old_value = ctypes.c_uint()
require_success(
sdk.pynect_direct_get_stored_integration_time(
ctypes.byref(old_value)
),
"Read stored integration time",
)
print("Original stored value:", old_value.value, "us")
require_success(
sdk.pynect_direct_set_stored_integration_time(
approved_integration_us
),
"Set stored integration time",
)
else:
print("Skipped: stored configuration write is disabled")
常见错误
误以为该设置只对当前采集有效;单位使用毫秒;未记录原值;用 ABI 最大范围代替设备有效范围。关联 API:pynect_direct_get_stored_integration_time、pynect_direct_set_integration_time。
pynect_direct_set_stored_average_number
功能说明
把默认光谱平均次数写入设备的固化配置。较大的默认平均次数会增加以后采集的总耗时,且可能影响依赖响应时间的实验流程。
适用范围
UV/VIS;要求 PYNECT_DIRECT_CAP_STORED_CONFIG;高风险持久配置接口。NIR 返回 -11。
调用前提
设备已打开;已确认设备允许范围并记录原固化值;已评估目标平均次数对采集时间的影响;已获得维护授权。
输入参数
| 参数 | Python 类型 | 方向 | 范围/单位 | 说明 |
|---|---|---|---|---|
count |
Python int,按 ctypes.c_uint8 传入 |
输入 | 通常 1-255 次 |
要保存的默认平均次数;准确有效范围以设备资料为准 |
不建议写入 0,除非具体设备资料明确规定其含义。
输出参数
无。写入后应调用对应读取函数核对。
返回值
| 返回值 | 含义 |
|---|---|
0 |
固化平均次数写入命令成功 |
-3 |
设备未打开 |
-4/-7/-8/-9 |
设备拒绝、返回校验异常或通信超时 |
-10 |
设备报告当前写操作受保护 |
-11 |
当前设备不支持固化配置 |
Python 示例
import ctypes
ALLOW_STORED_CONFIG_WRITE = False
approved_average_count = None
if ALLOW_STORED_CONFIG_WRITE:
if approved_average_count is None:
raise ValueError("An approved average count is required")
if not 1 <= approved_average_count <= 255:
raise ValueError("Stored average count must be 1-255")
old_value = ctypes.c_uint8()
require_success(
sdk.pynect_direct_get_stored_average_number(
ctypes.byref(old_value)
),
"Read stored average count",
)
print("Original stored average:", old_value.value)
require_success(
sdk.pynect_direct_set_stored_average_number(
approved_average_count
),
"Set stored average count",
)
else:
print("Skipped: stored configuration write is disabled")
常见错误
把平均次数当作毫秒;写入 0 而未确认设备含义;忽略平均次数会成倍增加采集时间;把固化值与当前会话值混淆。关联 API:pynect_direct_get_stored_average_number、pynect_direct_set_average_number。
pynect_direct_set_stored_smoothing_width
功能说明
把默认平滑宽度写入设备的固化配置。平滑会影响光谱细节和峰形,错误参数可能降低后续测量的光谱分辨表现。
适用范围
仅应在报告 PYNECT_DIRECT_CAP_STORED_CONFIG 的 UV/VIS 设备上使用;高风险持久配置接口。当前库对 NIR 调用可能返回 0 但不实际应用设置,因此 NIR 程序必须依靠 capability 检查跳过此函数,不能仅根据返回码判断是否生效。
调用前提
设备已打开;capability 已确认;平滑宽度的允许范围和定义已从设备资料取得;已记录原固化值并获得维护授权。
输入参数
| 参数 | Python 类型 | 方向 | 范围/单位 | 说明 |
|---|---|---|---|---|
width |
Python int,按 ctypes.c_uint8 传入 |
输入 | ABI 范围 0-255,设备定义的宽度值 |
准确有效范围、是否允许 0 以及窗口含义均以设备资料为准 |
输出参数
无。UV/VIS 写入后应调用对应读取函数核对;NIR 的成功返回不得视为已应用。
返回值
| 返回值 | 含义 |
|---|---|
0 |
UV/VIS 写入命令成功;NIR 当前也可能返回 0 但不执行设置 |
-3 |
设备未打开 |
-4/-7/-8/-9 |
UV/VIS 设备拒绝、返回校验异常或通信超时 |
-10 |
设备报告当前写操作受保护 |
-11 |
当前协议不是受支持的 UV/VIS 或兼容 NIR 路径 |
Python 示例
import ctypes
CAP_STORED_CONFIG = 0x00002000
ALLOW_STORED_CONFIG_WRITE = False
approved_smoothing_width = None
capabilities = ctypes.c_uint32()
require_success(
sdk.pynect_direct_get_capabilities(ctypes.byref(capabilities)),
"Get capabilities",
)
if not capabilities.value & CAP_STORED_CONFIG:
print("Skipped: stored smoothing is not supported")
elif ALLOW_STORED_CONFIG_WRITE:
if approved_smoothing_width is None:
raise ValueError("An approved smoothing width is required")
if not 0 <= approved_smoothing_width <= 255:
raise ValueError("Smoothing width must fit uint8")
require_success(
sdk.pynect_direct_set_stored_smoothing_width(
approved_smoothing_width
),
"Set stored smoothing width",
)
else:
print("Skipped: stored configuration write is disabled")
常见错误
在 NIR 上看到返回 0 就认为设置已保存;未检查 capability;用试错方式寻找宽度范围;忽略平滑对峰形的影响。关联 API:pynect_direct_get_stored_smoothing_width、pynect_direct_get_capabilities。
pynect_direct_get_stored_integration_time
功能说明
读取设备固化配置中的默认积分时间。该值不一定等于当前会话正在使用的积分时间。
适用范围
UV/VIS;要求 PYNECT_DIRECT_CAP_STORED_CONFIG;只读。NIR 返回 -11。
调用前提
设备已打开并支持固化配置。准备一个与无符号 32 位参数匹配的 ctypes.c_uint 输出变量。
输入参数
无普通输入值。
输出参数
| 参数 | Python 类型 | 方向 | 单位/范围 | 说明 |
|---|---|---|---|---|
us |
ctypes.c_uint() + ctypes.byref() |
输出 | 微秒;无符号 32 位 | 设备保存的默认积分时间 |
返回值
| 返回值 | 含义 |
|---|---|
0 |
us.value 已写入 |
-3 |
设备未打开 |
-4/-7/-8/-9 |
返回数据长度、校验或通信异常 |
-11 |
当前设备不支持固化配置读取 |
Python 示例
import ctypes
stored_us = ctypes.c_uint()
code = sdk.pynect_direct_get_stored_integration_time(
ctypes.byref(stored_us)
)
if code == -11:
print("Stored integration time is not supported")
else:
require_success(code, "Get stored integration time")
print("Stored integration time:", stored_us.value, "us")
常见错误
使用 c_uint8 或 c_uint16 截断数值;把固化默认值当成当前实际值;误把单位当成毫秒。关联 API:pynect_direct_get_integration_time、pynect_direct_set_stored_integration_time。
pynect_direct_get_stored_average_number
功能说明
读取设备固化配置中的默认平均次数。该值用于了解设备保存的启动配置,不一定等于当前会话的平均次数。
适用范围
UV/VIS;要求 PYNECT_DIRECT_CAP_STORED_CONFIG;只读。NIR 返回 -11。
调用前提
设备已打开并支持固化配置。准备一个无符号 8 位输出变量。
输入参数
无普通输入值。
输出参数
| 参数 | Python 类型 | 方向 | 范围/单位 | 说明 |
|---|---|---|---|---|
count |
ctypes.c_uint8() + ctypes.byref() |
输出 | 0-255 次 |
设备保存的默认平均次数;有效含义以设备资料为准 |
返回值
| 返回值 | 含义 |
|---|---|
0 |
count.value 已写入 |
-3 |
设备未打开 |
-4/-7/-8/-9 |
返回数据长度、校验或通信异常 |
-11 |
当前设备不支持固化配置读取 |
Python 示例
import ctypes
stored_average = ctypes.c_uint8()
code = sdk.pynect_direct_get_stored_average_number(
ctypes.byref(stored_average)
)
if code == -11:
print("Stored average count is not supported")
else:
require_success(code, "Get stored average count")
print("Stored average count:", stored_average.value)
常见错误
把函数返回码当成平均次数;把固化默认值与当前平均次数混淆;看到 0 后擅自解释其设备含义。关联 API:pynect_direct_get_average_number、pynect_direct_set_stored_average_number。
pynect_direct_get_stored_smoothing_width
功能说明
读取设备固化配置中的默认平滑宽度。返回的是设备定义的原始宽度值,SDK 不解释窗口算法或平滑阶数。
适用范围
UV/VIS;要求 PYNECT_DIRECT_CAP_STORED_CONFIG;只读。NIR 返回 -11。
调用前提
设备已打开并支持固化配置。若要解释该值对光谱处理的影响,需要对应设备的平滑参数资料。
输入参数
无普通输入值。
输出参数
| 参数 | Python 类型 | 方向 | 范围/单位 | 说明 |
|---|---|---|---|---|
width |
ctypes.c_uint8() + ctypes.byref() |
输出 | 0-255,设备定义宽度值 |
设备保存的默认平滑宽度 |
返回值
| 返回值 | 含义 |
|---|---|
0 |
width.value 已写入 |
-3 |
设备未打开 |
-4/-7/-8/-9 |
返回数据长度、校验或通信异常 |
-11 |
当前设备不支持该固化配置查询 |
Python 示例
import ctypes
stored_width = ctypes.c_uint8()
code = sdk.pynect_direct_get_stored_smoothing_width(
ctypes.byref(stored_width)
)
if code == -11:
print("Stored smoothing width is not supported")
else:
require_success(code, "Get stored smoothing width")
print("Stored smoothing width:", stored_width.value)
常见错误
把宽度值直接解释成 nm 或像素数;在 NIR 上调用后忽略 -11;把读取成功误认为当前光谱一定已应用该平滑。关联 API:pynect_direct_set_stored_smoothing_width。
pynect_direct_get_slit_width
功能说明
读取设备保存的入射狭缝宽度信息。该值是设备身份和光学配置参数,不会改变狭缝,也不能单独代表光谱分辨率。
适用范围
UV/VIS;要求 PYNECT_DIRECT_CAP_SLIT_WIDTH;只读。NIR 返回 -11。
调用前提
设备已打开并支持狭缝信息查询。准备一个无符号 8 位输出变量。
输入参数
无普通输入值。
输出参数
| 参数 | Python 类型 | 方向 | 单位/范围 | 说明 |
|---|---|---|---|---|
um |
ctypes.c_uint8() + ctypes.byref() |
输出 | 微米(um);0-255 |
设备报告的狭缝宽度 |
文档使用 ASCII um 与函数参数名保持一致,其物理单位为微米。
返回值
| 返回值 | 含义 |
|---|---|
0 |
um.value 已写入 |
-3 |
设备未打开 |
-4/-7/-8/-9 |
返回数据长度、校验或通信异常 |
-11 |
当前设备不支持狭缝宽度查询 |
Python 示例
import ctypes
slit_width_um = ctypes.c_uint8()
code = sdk.pynect_direct_get_slit_width(
ctypes.byref(slit_width_um)
)
if code == -11:
print("Slit width query is not supported")
else:
require_success(code, "Get slit width")
print("Slit width:", slit_width_um.value, "um")
常见错误
使用 c_uint16 后忽略 ABI 定义;把数值单位当成 nm;仅凭狭缝宽度推断整机分辨率。关联 API:pynect_direct_get_device_model、pynect_direct_get_hardware_version。
16. 学生实验
以下实验默认禁止调用第 12 章列出的高风险写接口。
16.1 实验一:环境和设备检查
目标:完成只读测试并识别设备。
步骤:
- 检查 Python 为 64 位。
- 检查
dll文件夹内包含两个 DLL。 - 运行
minimal_test.py --read-only。 - 记录 DLL 路径、芯片序列号、设备型号、设备序列号和波长点数。
完成标准:最终 FAIL=0,并能解释 PASS 和 SKIP 的区别。
16.2 实验二:采集并保存完整光谱
目标:理解波长和强度的一一对应关系。
步骤:
- 运行完整光谱采集程序。
- 检查点数和波长范围。
- 保存
spectrum.csv。 - 随机检查 5 行数据是否能在 Python 输出中找到对应值。
完成标准:CSV 中数据行数与波长点数一致,两列数据无错位。
16.3 实验三:绘制光谱曲线
目标:将 CSV 转换为可检查的光谱图。
步骤:
- 使用第 9 章脚本绘图。
- 标注样品名称、积分时间和平均次数。
- 检查横轴波长范围与设备返回范围一致。
- 描述主要峰或变化区域,不要求进行物质定性结论。
完成标准:图形包含标题、横轴名称、纵轴名称,数据没有明显错位。
16.4 实验四:积分时间比较
目标:观察积分时间对强度和采集时间的影响。
建议设置:使用设备允许范围内的三个积分时间,每个条件保持样品、光路和平均次数不变。
记录:
- 每个积分时间的最大强度。
- 是否出现饱和。
- 单次采集大致耗时。
- 实验结束后是否恢复原积分时间。
16.5 实验五:平均次数比较
目标:观察平均次数对随机波动和采集时间的影响。
建议依次使用 1、3、5 次平均,保持积分时间和样品不变。比较曲线平滑程度和采集时间,并在结束后恢复原值。
16.6 实验六:指定波段采集
目标:理解请求范围、实际范围和像素点之间的关系。
步骤:
- 读取设备完整波长范围。
- 在完整范围内选择一个较小波段。
- 设置波段并读取实际范围。
- 保存指定波段的波长和强度。
- 比较请求边界与实际边界的差异。
16.7 提交检查清单
提交前确认:
- [ ] 记录 Python 位数和测试命令。
- [ ] 记录设备型号、芯片序列号和设备序列号。
- [ ] 记录积分时间、平均次数和测量时间。
- [ ] CSV 数据行数与点数一致。
- [ ] 波长和强度按索引配对。
- [ ] 图形坐标轴和单位完整。
- [ ] 程序使用
try/finally关闭设备。 - [ ] 临时参数已恢复。
- [ ] 没有执行 Flash 写入、固化配置、设备复位或未知输出操作。
17. 日常使用检查表
测量前:
- 检查 USB、光源、光纤和样品位置。
- 确认没有其他程序占用设备。
- 确认加载的 DLL 路径正确。
- 记录原积分时间和平均次数。
测量中:
- 检查光谱点数和波长范围。
- 检查强度是否过低或饱和。
- 保持样品和光路稳定。
- 为每次数据记录设备和参数信息。
测量后:
- 恢复临时参数。
- 关闭设备。
- 保存 CSV、图形和实验记录。
- 确认文件可以重新打开和读取。