Files
lora_plug/serial_module_bk.c
2025-02-19 16:09:44 +08:00

269 lines
8.1 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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);
}