269 lines
8.1 KiB
C
269 lines
8.1 KiB
C
|
|
#define PY_SSIZE_T_CLEAN
|
|||
|
|
#include <Python.h>
|
|||
|
|
#include <stdint.h>
|
|||
|
|
#include <string.h>
|
|||
|
|
#include <stdlib.h>
|
|||
|
|
#include <unistd.h>
|
|||
|
|
#include <zlib.h> // 引入 zlib 库
|
|||
|
|
#include <fec.h> // 引入 libfec 库
|
|||
|
|
#include "hx_serial.h"
|
|||
|
|
#include "hx_ringbuffer.h"
|
|||
|
|
|
|||
|
|
// #define USE_FEC
|
|||
|
|
|
|||
|
|
#ifdef USE_FEC
|
|||
|
|
#define FEC_SIZE 32 // 前向纠错冗余数据大小
|
|||
|
|
#else
|
|||
|
|
#define FEC_SIZE 0 // 前向纠错冗余数据大小
|
|||
|
|
#endif
|
|||
|
|
#define FRAME_HEADER 0xAA55 // 帧头
|
|||
|
|
#define FRAME_SIZE (240) // 每帧大小
|
|||
|
|
#define HEADER_SIZE (4) // 帧头 + 帧序号 + 数据长度
|
|||
|
|
#define CHECKSUM_SIZE (4) // CRC32 校验和大小(4 字节)
|
|||
|
|
#define DATA_SIZE (FRAME_SIZE - HEADER_SIZE - CHECKSUM_SIZE - FEC_SIZE) // 数据段大小
|
|||
|
|
#define RING_BUFFER_SIZE (1024 * 10) // 环形缓冲区大小 - default 10KB
|
|||
|
|
|
|||
|
|
// 全局变量:串口设备和发送缓冲区
|
|||
|
|
static by_serial_t serial_port;
|
|||
|
|
static by_ringbuf_t ring_buffer;
|
|||
|
|
static uint8_t send_buffer[FRAME_SIZE];
|
|||
|
|
static uint8_t send_buffer_test[FRAME_SIZE];
|
|||
|
|
static uint8_t frame_counter = 0;
|
|||
|
|
static uint8_t data_len = 0;
|
|||
|
|
|
|||
|
|
// 计算 CRC32 校验和
|
|||
|
|
uint32_t calculate_crc32(const uint8_t *data, size_t length) {
|
|||
|
|
return crc32(0, data, length);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 前向纠错编码
|
|||
|
|
void fec_encode(uint8_t *data, size_t data_length, uint8_t *fec_data) {
|
|||
|
|
encode_rs_8(data, fec_data, 0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 前向纠错解码
|
|||
|
|
int fec_decode(uint8_t *data, size_t data_length, uint8_t *fec_data) {
|
|||
|
|
return decode_rs_8(data, (int *)fec_data, 0, 0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 解析一帧数据
|
|||
|
|
int parse_frame(by_ringbuf_t *ringbuf, uint8_t *output_data, int *output_len) {
|
|||
|
|
uint8_t frame[FRAME_SIZE];
|
|||
|
|
int available_data = by_ringbuf_available_data(ringbuf);
|
|||
|
|
|
|||
|
|
// 检查是否有足够的数据解析一帧
|
|||
|
|
if (available_data < HEADER_SIZE + CHECKSUM_SIZE + FEC_SIZE) {
|
|||
|
|
return -1; // 数据不足,无法解析
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 查找帧头
|
|||
|
|
uint16_t header = FRAME_HEADER;
|
|||
|
|
int header_pos = by_ringbuf_find(ringbuf, (uint8_t *)&header, 2);
|
|||
|
|
if (header_pos < 0) {
|
|||
|
|
return -1; // 没有找到帧头
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 弹出帧头之前的数据
|
|||
|
|
by_ringbuf_pop(ringbuf, frame, header_pos);
|
|||
|
|
|
|||
|
|
// 检查是否有足够的数据解析一帧
|
|||
|
|
if (by_ringbuf_available_data(ringbuf) < FRAME_SIZE) {
|
|||
|
|
return -1; // 数据不足,无法解析
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 读取帧数据
|
|||
|
|
by_ringbuf_pop(ringbuf, frame, FRAME_SIZE);
|
|||
|
|
|
|||
|
|
// 解析帧序号、有效数据长度、数据段和 CRC32
|
|||
|
|
uint8_t seq = frame[2];
|
|||
|
|
uint8_t valid_data_len = frame[2 + 1];
|
|||
|
|
uint8_t *data_segment = &frame[2 + 1 + 1];
|
|||
|
|
uint32_t received_crc = *(uint32_t *)&frame[2 + 1 + 1 + DATA_SIZE];
|
|||
|
|
|
|||
|
|
printf("Received frame: %d, valid_data_len: %d, received_crc: %08X\n", seq, valid_data_len, received_crc);
|
|||
|
|
|
|||
|
|
for(uint8_t i = 0; i < FRAME_SIZE; i++) {
|
|||
|
|
printf("%02X ", frame[i]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
printf("\n");
|
|||
|
|
|
|||
|
|
// 计算 CRC32 校验
|
|||
|
|
// uint32_t calculated_crc = calculate_crc32(data_segment, valid_data_len);
|
|||
|
|
uint32_t calculated_crc = calculate_crc32(frame, HEADER_SIZE + DATA_SIZE + FEC_SIZE);
|
|||
|
|
if (received_crc != calculated_crc) {
|
|||
|
|
printf("CRC mismatch! Expected: %08X, Received: %08X\n", calculated_crc, received_crc);
|
|||
|
|
return -1; // CRC 校验失败,丢弃该帧
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 将有效数据拼接到输出缓冲区
|
|||
|
|
memcpy(&output_data[*output_len], data_segment, valid_data_len);
|
|||
|
|
*output_len += valid_data_len;
|
|||
|
|
|
|||
|
|
// 判断是否为最后一帧
|
|||
|
|
if (valid_data_len < DATA_SIZE) {
|
|||
|
|
printf("Received last frame!\n");
|
|||
|
|
return 1; // 最后一帧,解析完成
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return 0; // 成功解析一帧,但可能还有更多帧
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 边读取边解析串口数据
|
|||
|
|
int parse_serial_data(by_serial_t *serial_port, by_ringbuf_t *ringbuf, uint8_t *output_data, int *output_len) {
|
|||
|
|
uint8_t buffer[FRAME_SIZE];
|
|||
|
|
int ret;
|
|||
|
|
|
|||
|
|
// 从串口读取数据到环形缓冲区
|
|||
|
|
ret = by_serial_read(serial_port, buffer, FRAME_SIZE);
|
|||
|
|
if (ret > 0) {
|
|||
|
|
by_ringbuf_append(ringbuf, buffer, ret);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 尝试解析环形缓冲区中的数据
|
|||
|
|
while (1) {
|
|||
|
|
int parse_result = parse_frame(ringbuf, output_data, output_len);
|
|||
|
|
if (parse_result == 1) {
|
|||
|
|
return 0; // 解析完成
|
|||
|
|
} else if (parse_result == -1) {
|
|||
|
|
break; // 数据不足或解析失败,退出循环
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return -1; // 未找到完整帧
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 初始化串口
|
|||
|
|
static PyObject *serial_init(PyObject *self, PyObject *args) {
|
|||
|
|
const char *dev_name;
|
|||
|
|
|
|||
|
|
if (!PyArg_ParseTuple(args, "s", &dev_name)) {
|
|||
|
|
return NULL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (by_serial_init(&serial_port, dev_name) != 0) {
|
|||
|
|
PyErr_SetString(PyExc_IOError, "Failed to initialize serial port");
|
|||
|
|
return NULL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 初始化环形缓冲区
|
|||
|
|
if (by_ringbuf_init(&ring_buffer, RING_BUFFER_SIZE) != 0) {
|
|||
|
|
PyErr_SetString(PyExc_IOError, "Failed to initialize ring buffer");
|
|||
|
|
return NULL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
frame_counter = 0; // 重置帧计数器
|
|||
|
|
Py_RETURN_NONE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 发送数据
|
|||
|
|
static PyObject *serial_send(PyObject *self, PyObject *args) {
|
|||
|
|
const char *data;
|
|||
|
|
Py_ssize_t length;
|
|||
|
|
|
|||
|
|
if (!PyArg_ParseTuple(args, "s#", &data, &length)) {
|
|||
|
|
return NULL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
printf("Send data len = %ld\n", length);
|
|||
|
|
|
|||
|
|
size_t offset = 0;
|
|||
|
|
uint8_t idx = 0;
|
|||
|
|
while (offset < length) {
|
|||
|
|
memset(send_buffer, 0, FRAME_SIZE);
|
|||
|
|
|
|||
|
|
// 构造帧头
|
|||
|
|
uint16_t header = FRAME_HEADER;
|
|||
|
|
memcpy(send_buffer, &header, 2);
|
|||
|
|
|
|||
|
|
// 构造帧序号
|
|||
|
|
memcpy(send_buffer + 2, &frame_counter, 1);
|
|||
|
|
|
|||
|
|
// 构造数据长度
|
|||
|
|
if (length - offset > DATA_SIZE) {
|
|||
|
|
data_len = DATA_SIZE;
|
|||
|
|
} else {
|
|||
|
|
data_len = length - offset;
|
|||
|
|
}
|
|||
|
|
memcpy(send_buffer + 3, &data_len, 1);
|
|||
|
|
|
|||
|
|
// 拷贝该帧对应数据段
|
|||
|
|
memcpy(send_buffer + HEADER_SIZE, data + offset, data_len);
|
|||
|
|
|
|||
|
|
#ifdef USE_FEC
|
|||
|
|
// 将 FEC 数据附加到帧中
|
|||
|
|
memcpy(send_buffer + HEADER_SIZE + DATA_SIZE, fec_data, 32);
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
// 计算 CRC32 校验和
|
|||
|
|
uint32_t crc = calculate_crc32(send_buffer, HEADER_SIZE + DATA_SIZE + FEC_SIZE);
|
|||
|
|
memcpy(send_buffer + HEADER_SIZE + DATA_SIZE + FEC_SIZE, &crc, CHECKSUM_SIZE);
|
|||
|
|
|
|||
|
|
for(uint8_t i = 0; i < FRAME_SIZE; i++) {
|
|||
|
|
printf("%02x ", send_buffer[i]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 发送帧
|
|||
|
|
if (by_serial_write(&serial_port, (const char *)send_buffer, FRAME_SIZE) != 0) {
|
|||
|
|
PyErr_SetString(PyExc_IOError, "Failed to send data over serial port");
|
|||
|
|
return NULL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
offset += DATA_SIZE;
|
|||
|
|
frame_counter++;
|
|||
|
|
|
|||
|
|
printf("* frame [%d]\n", frame_counter);
|
|||
|
|
|
|||
|
|
// usleep(50000);
|
|||
|
|
usleep(80000);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
frame_counter = 0;
|
|||
|
|
|
|||
|
|
printf("****************\n");
|
|||
|
|
|
|||
|
|
Py_RETURN_NONE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 接收数据
|
|||
|
|
static PyObject *serial_receive(PyObject *self, PyObject *args) {
|
|||
|
|
uint8_t output_data[8192];
|
|||
|
|
int output_len = 0;
|
|||
|
|
int timeout = 5000; // 超时时间,单位为毫秒
|
|||
|
|
int elapsed_time = 0;
|
|||
|
|
|
|||
|
|
// TODO 增加当接收新帧时的处理
|
|||
|
|
while (elapsed_time < timeout) {
|
|||
|
|
if (parse_serial_data(&serial_port, &ring_buffer, output_data, &output_len) == 0) {
|
|||
|
|
// 返回解析后的数据
|
|||
|
|
printf("Parsed data length: %d\n", output_len);
|
|||
|
|
return Py_BuildValue("y#", output_data, output_len);
|
|||
|
|
}
|
|||
|
|
usleep(1000); // 等待 1 毫秒
|
|||
|
|
elapsed_time += 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 超时未接收到完整帧
|
|||
|
|
PyErr_SetString(PyExc_TimeoutError, "Timeout while waiting for data");
|
|||
|
|
return NULL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 模块方法表
|
|||
|
|
static PyMethodDef SerialMethods[] = {
|
|||
|
|
{"init", serial_init, METH_VARARGS, "Initialize serial port"},
|
|||
|
|
{"send", serial_send, METH_VARARGS, "Send data over serial port"},
|
|||
|
|
{"receive", serial_receive, METH_VARARGS, "Receive data from serial port"},
|
|||
|
|
{NULL, NULL, 0, NULL}};
|
|||
|
|
|
|||
|
|
// 模块定义
|
|||
|
|
static struct PyModuleDef serialmodule = {
|
|||
|
|
PyModuleDef_HEAD_INIT,
|
|||
|
|
"serial_module",
|
|||
|
|
NULL,
|
|||
|
|
-1,
|
|||
|
|
SerialMethods};
|
|||
|
|
|
|||
|
|
// 模块初始化函数
|
|||
|
|
PyMODINIT_FUNC PyInit_serial_module(void) {
|
|||
|
|
return PyModule_Create(&serialmodule);
|
|||
|
|
}
|