From 9eb3879aab6d8b9776fcdc02c0c3b9414177cf74 Mon Sep 17 00:00:00 2001 From: CaoWangrenbo Date: Wed, 19 Feb 2025 16:09:44 +0800 Subject: [PATCH] initial commit --- .gitignore | 290 ++++++++++++++++++++++++++++++++++++++++++ .vscode/settings.json | 10 ++ CMakeLists.txt | 29 +++++ hx_ringbuffer.c | 123 ++++++++++++++++++ hx_ringbuffer.h | 46 +++++++ jpeg_corrupt_test.py | 81 ++++++++++++ recv_test | Bin 0 -> 16800 bytes recv_test.c | 141 ++++++++++++++++++++ serial_data.txt | 1 + serial_module.c | 262 ++++++++++++++++++++++++++++++++++++++ serial_module.so | Bin 0 -> 37160 bytes serial_module_bk.c | 269 +++++++++++++++++++++++++++++++++++++++ test_recv.jpg | Bin 0 -> 10573 bytes test_recv.py | 21 +++ test_send.jpg | Bin 0 -> 6920 bytes test_send.py | 43 +++++++ tool_capserial | Bin 0 -> 16544 bytes tool_capserial.c | 77 +++++++++++ tool_ckframe.py | 33 +++++ 19 files changed, 1426 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/settings.json create mode 100644 CMakeLists.txt create mode 100644 hx_ringbuffer.c create mode 100644 hx_ringbuffer.h create mode 100644 jpeg_corrupt_test.py create mode 100755 recv_test create mode 100644 recv_test.c create mode 100644 serial_data.txt create mode 100644 serial_module.c create mode 100755 serial_module.so create mode 100644 serial_module_bk.c create mode 100644 test_recv.jpg create mode 100644 test_recv.py create mode 100644 test_send.jpg create mode 100644 test_send.py create mode 100755 tool_capserial create mode 100644 tool_capserial.c create mode 100644 tool_ckframe.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a3585c6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,290 @@ +# Created by https://www.toptal.com/developers/gitignore/api/c,c++,visualstudiocode,python,cmake +# Edit at https://www.toptal.com/developers/gitignore?templates=c,c++,visualstudiocode,python,cmake + +### C ### +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + +### C++ ### +# Prerequisites + +# Compiled Object files +*.slo + +# Precompiled Headers + +# Compiled Dynamic libraries + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai + +# Executables + +### CMake ### +CMakeLists.txt.user +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps + +### CMake Patch ### +CMakeUserPresets.json + +# External projects +*-prefix/ + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +### Python Patch ### +# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration +poetry.toml + +# ruff +.ruff_cache/ + +# LSP config files +pyrightconfig.json + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +# End of https://www.toptal.com/developers/gitignore/api/c,c++,visualstudiocode,python,cmake + +# 排除生成产物 +!serial_module.so + diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..325b0a1 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,10 @@ +{ + "files.associations": { + "hx_serial.h": "c", + "stdlib.h": "c", + "fec.h": "c", + "unistd.h": "c", + "hx_ringbuffer.h": "c", + "zlib.h": "c" + } +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..b78a879 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.10) +project(serial_module) + +# 查找 Python 开发包 +set(Python3_ROOT_DIR ~/miniconda3/envs/videomea_deploy) +find_package(Python3 REQUIRED COMPONENTS Development) + +# 添加 Python 头文件路径 +include_directories(${Python3_INCLUDE_DIRS}) + +# 添加系统头文件路径(如果 hx_serial.h 在默认位置,可以省略) +# include_directories(/usr/include /usr/local/include) + +# 添加源文件 +set(SOURCES serial_module.c hx_ringbuffer.c) + +# 创建 Python 模块 +Python3_add_library(serial_module MODULE ${SOURCES}) + +find_package(ZLIB REQUIRED) + +target_link_libraries(serial_module PRIVATE hx-serial fec ${ZLIB_LIBRARIES}) + +# 设置输出目录和文件名 +set_target_properties(serial_module PROPERTIES + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR} + PREFIX "" + SUFFIX ".so" +) \ No newline at end of file diff --git a/hx_ringbuffer.c b/hx_ringbuffer.c new file mode 100644 index 0000000..572df63 --- /dev/null +++ b/hx_ringbuffer.c @@ -0,0 +1,123 @@ +#include +#include +#include + +#include "hx_ringbuffer.h" + +int by_ringbuf_init(by_ringbuf_t *rb, int size) { +#ifdef BY_RINGBUF_STATIC_ALLOC + // 使用预先分配的内存 + static uint8_t static_buffer[BY_RINGBUF_STATIC_BUFFER_SIZE]; + + if (size > sizeof(static_buffer)) { + return -1; // 预先分配的内存不足 + } + rb->buffer = static_buffer; +#else + // 使用 malloc 动态分配内存 + rb->buffer = (uint8_t *)malloc(size); + if (rb->buffer == NULL) { + return -1; // 分配内存失败 + } +#endif + + rb->size = size; + rb->head = 0; + rb->tail = 0; + rb->is_full = false; + return 0; +} + +void by_ringbuf_free(by_ringbuf_t *rb) { +#ifndef BY_RINGBUF_STATIC_ALLOC + // 只有使用 malloc 分配的内存才需要释放 + if (rb->buffer) { + free(rb->buffer); + rb->buffer = NULL; + } +#endif + + rb->size = 0; + rb->head = 0; + rb->tail = 0; + rb->is_full = false; +} + +int by_ringbuf_append(by_ringbuf_t *rb, const uint8_t *data, int len) { + if (len > by_ringbuf_available_space(rb)) { + return -1; // 缓冲区空间不足 + } + + for (int i = 0; i < len; i++) { + rb->buffer[rb->head] = data[i]; + rb->head = (rb->head + 1) % rb->size; + if (rb->head == rb->tail) { + rb->is_full = true; + } + } + + return len; +} + +int by_ringbuf_pop(by_ringbuf_t *rb, uint8_t *data, int len) { + if (len > by_ringbuf_available_data(rb)) { + return -1; // 数据不足 + } + + for (int i = 0; i < len; i++) { + data[i] = rb->buffer[rb->tail]; + rb->tail = (rb->tail + 1) % rb->size; + rb->is_full = false; + } + + return len; +} + +int by_ringbuf_find(by_ringbuf_t *rb, const uint8_t *pattern, int pattern_len) { + int available_data = by_ringbuf_available_data(rb); + if (pattern_len > available_data) { + return -1; // 数据不足,无法查找 + } + + for (int i = 0; i <= available_data - pattern_len; i++) { + int match = 1; + for (int j = 0; j < pattern_len; j++) { + int index = (rb->tail + i + j) % rb->size; + if (rb->buffer[index] != pattern[j]) { + match = 0; + break; + } + } + if (match) { + return i; // 返回匹配的起始位置 + } + } + + return -1; // 未找到匹配 +} + +int by_ringbuf_available_data(by_ringbuf_t *rb) { + if (rb->is_full) { + return rb->size; + } + return (rb->head - rb->tail + rb->size) % rb->size; +} + +int by_ringbuf_available_space(by_ringbuf_t *rb) { + return rb->size - by_ringbuf_available_data(rb); +} + +// 调试函数:打印环形缓冲区中的数据及其序号 +void by_ringbuf_debug_print(by_ringbuf_t *rb) { + int available_data = by_ringbuf_available_data(rb); + if (available_data == 0) { + printf("Ring buffer is empty.\n"); + return; + } + + printf("Ring buffer content (size: %d, available data: %d):\n", rb->size, available_data); + for (int i = 0; i < available_data; i++) { + int index = (rb->tail + i) % rb->size; + printf("[%04d] 0x%02X\n", i, rb->buffer[index]); + } +} \ No newline at end of file diff --git a/hx_ringbuffer.h b/hx_ringbuffer.h new file mode 100644 index 0000000..8577a35 --- /dev/null +++ b/hx_ringbuffer.h @@ -0,0 +1,46 @@ +#ifndef _BY_RINGBUF_H__ +#define _BY_RINGBUF_H__ + +#include +#include + +// 定义宏来选择内存分配方式 +// 如果定义了 BY_RINGBUF_STATIC_ALLOC,则使用预先分配的内存 +// 否则使用 malloc 动态分配内存 +// #define BY_RINGBUF_STATIC_ALLOC + +#define BY_RINGBUF_STATIC_BUFFER_SIZE (8192) + +typedef struct { + uint8_t *buffer; // 缓冲区指针 + int size; // 缓冲区大小 + int head; // 写指针 + int tail; // 读指针 + bool is_full; // 缓冲区是否已满 +} by_ringbuf_t; + +// 初始化环形缓冲区 +extern int by_ringbuf_init(by_ringbuf_t *rb, int size); + +// 释放环形缓冲区 +extern void by_ringbuf_free(by_ringbuf_t *rb); + +// 向缓冲区追加数据 +extern int by_ringbuf_append(by_ringbuf_t *rb, const uint8_t *data, int len); + +// 从缓冲区弹出数据 +extern int by_ringbuf_pop(by_ringbuf_t *rb, uint8_t *data, int len); + +// 查找缓冲区中是否包含特定数据 +extern int by_ringbuf_find(by_ringbuf_t *rb, const uint8_t *pattern, int pattern_len); + +// 获取缓冲区中可用数据的大小 +extern int by_ringbuf_available_data(by_ringbuf_t *rb); + +// 获取缓冲区中空闲空间的大小 +extern int by_ringbuf_available_space(by_ringbuf_t *rb); + +// 调试函数:打印环形缓冲区中的数据及其序号 +extern void by_ringbuf_debug_print(by_ringbuf_t *rb); + +#endif // _BY_RINGBUF_H__ \ No newline at end of file diff --git a/jpeg_corrupt_test.py b/jpeg_corrupt_test.py new file mode 100644 index 0000000..602eb94 --- /dev/null +++ b/jpeg_corrupt_test.py @@ -0,0 +1,81 @@ +import cv2 +import numpy as np + +def corrupt_data(data, corruption_type='modify', severity=1): + """ + 对二进制数据进行损坏 + :param data: 原始二进制数据 + :param corruption_type: 损坏类型 ('modify', 'shift', 'loss') + :param severity: 损坏严重程度 (1-10) + :return: 损坏后的二进制数据 + """ + data = bytearray(data) # 转换为可变的 bytearray + length = len(data) + + if corruption_type == 'modify': + # 修改部分数据 + for i in range(severity * 5): + idx = np.random.randint(0, length) + data[idx] = np.random.randint(0, 256) + + elif corruption_type == 'shift': + # 数据移位 + shift = severity * 10 + data = data[shift:] + data[:shift] + + elif corruption_type == 'loss': + # 数据丢失 + loss_start = np.random.randint(0, length - severity * 10) + data[loss_start:loss_start + severity * 10] = b'\x00' * (severity * 10) + + return bytes(data) + +def main(): + # 打开摄像头 + cap = cv2.VideoCapture(0) + + if not cap.isOpened(): + print("无法打开摄像头") + return + + while True: + # 读取一帧图像 + ret, frame = cap.read() + if not ret: + print("无法读取图像") + break + + frame = cv2.resize(frame, (224, 224)) + + # 显示原始图像 + cv2.imshow('Original Image', frame) + + # 将图像编码为 JPEG 格式的二进制数据 + ret, jpeg_data = cv2.imencode('.jpg', frame) + if not ret: + print("图像编码失败") + break + + # 对二进制数据进行损坏 + corrupted_data = corrupt_data(jpeg_data, corruption_type='modify', severity=2) + + # 解码损坏后的二进制数据 + corrupted_image = cv2.imdecode(np.frombuffer(corrupted_data, dtype=np.uint8), cv2.IMREAD_COLOR) + + if corrupted_image is None: + print("损坏后的数据无法解码") + else: + # 显示损坏后的图像 + cv2.imshow('Corrupted Image', corrupted_image) + + # 等待用户按键 + key = cv2.waitKey(0) + if key == ord('q'): # 按下 'q' 键退出 + break + + # 释放摄像头并关闭所有窗口 + cap.release() + cv2.destroyAllWindows() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/recv_test b/recv_test new file mode 100755 index 0000000000000000000000000000000000000000..cc3bb3d3e70a9071182617dada8b149b583d99b7 GIT binary patch literal 16800 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 +#include +#include +#include +#include "hx_serial.h" +#include "hx_ringbuffer.h" + +#define FRAME_HEADER_1 0x55 +#define FRAME_HEADER_2 0xAA +#define MAX_DATA_LEN 232 +#define CRC32_LEN 4 +#define FRAME_HEADER_LEN 2 +#define FRAME_SEQ_LEN 1 +#define DATA_LEN_LEN 1 +#define FRAME_OVERHEAD (FRAME_HEADER_LEN + FRAME_SEQ_LEN + DATA_LEN_LEN + CRC32_LEN) +#define MAX_FRAME_LEN (FRAME_OVERHEAD + MAX_DATA_LEN) + +// CRC32 校验函数(假设已经实现) +uint32_t crc32(const uint8_t *data, int len); + +// 解析一帧数据 +int parse_frame(by_ringbuf_t *ringbuf, uint8_t *output_data, int *output_len) { + uint8_t frame[MAX_FRAME_LEN]; + int available_data = by_ringbuf_available_data(ringbuf); + // printf("Available data: %d\n", available_data); + // 检查是否有足够的数据解析一帧 + if (available_data < FRAME_OVERHEAD) { + return -1; // 数据不足,无法解析 + }else{ + // by_ringbuf_debug_print(ringbuf); + } + + // 查找帧头 + uint8_t header[2] = {FRAME_HEADER_1, FRAME_HEADER_2}; + int header_pos = by_ringbuf_find(ringbuf, header, 2); + printf("Header pos: %d\n", header_pos); + if (header_pos < 0) { + return -1; // 没有找到帧头 + } + + // 弹出帧头之前的数据 + by_ringbuf_pop(ringbuf, frame, header_pos); + + // 检查是否有足够的数据解析一帧 + if (by_ringbuf_available_data(ringbuf) < MAX_FRAME_LEN) { + return -1; // 数据不足,无法解析 + } + + // 读取帧数据 + by_ringbuf_pop(ringbuf, frame, MAX_FRAME_LEN); + + // 解析帧序号、有效数据长度、数据段和 CRC32 + uint8_t seq = frame[FRAME_HEADER_LEN]; + uint8_t valid_data_len = frame[FRAME_HEADER_LEN + FRAME_SEQ_LEN]; + uint8_t *data_segment = &frame[FRAME_HEADER_LEN + FRAME_SEQ_LEN + DATA_LEN_LEN]; + uint32_t received_crc = *(uint32_t *)&frame[FRAME_HEADER_LEN + FRAME_SEQ_LEN + DATA_LEN_LEN + MAX_DATA_LEN]; + + printf("Received frame: %d, valid_data_len: %d, received_crc: %08X\n", seq, valid_data_len, received_crc); + + // // 计算 CRC32 校验 + // uint32_t calculated_crc = crc32(data_segment, valid_data_len); + // if (received_crc != calculated_crc) { + // return -1; // CRC 校验失败,丢弃该帧 + // } + + // 将有效数据拼接到输出缓冲区 + memcpy(&output_data[*output_len], data_segment, valid_data_len); + *output_len += valid_data_len; + + // for(int i = 0; i < valid_data_len; i++){ + // printf("0x%02X ", data_segment[i]); + // } + + // 判断是否为最后一帧 + if (valid_data_len < MAX_DATA_LEN) { + 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[MAX_FRAME_LEN]; + int ret; + + // 从串口读取数据到环形缓冲区 + ret = by_serial_read(serial_port, buffer, MAX_FRAME_LEN); + 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) { + // printf("Parsed data length: %d\n", *output_len); + return 0; // 解析完成 + } else if (parse_result == -1) { + // printf("Failed to parse frame\n"); + break; // 数据不足或解析失败,退出循环 + } + } + + return -1; // 未找到完整帧 +} + +// 示例 CRC32 校验函数(需要根据实际情况实现) +uint32_t crc32(const uint8_t *data, int len) { + // 这里实现 CRC32 校验算法 + // 例如使用查表法或其他方法计算 CRC32 + return 0; // 返回计算出的 CRC32 值 +} + +int main() { + by_serial_t serial_port; + by_ringbuf_t ringbuf; + uint8_t output_data[4096]; + int output_len = 0; + + // 初始化串口和环形缓冲区 + by_serial_init(&serial_port, "/dev/ttyUSB1"); + by_ringbuf_init(&ringbuf, 4096); + + // 边读取边解析串口数据 + while (1) { + if (parse_serial_data(&serial_port, &ringbuf, output_data, &output_len) == 0) { + printf("Parsed data length: %d\n", output_len); + // 处理解析后的数据 + break; // 解析完成,退出循环 + } else { + // printf("Waiting for more data...\n"); + } + + usleep(1000); + } + + // 释放资源 + by_ringbuf_free(&ringbuf); + return 0; +} \ No newline at end of file diff --git a/serial_data.txt b/serial_data.txt new file mode 100644 index 0000000..a9513cf --- /dev/null +++ b/serial_data.txt @@ -0,0 +1 @@ +55 AA 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 4B 13 47 E7 FC 55 AA 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FC 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F6 DB 09 E1 FC 55 AA 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 31 82 DA EB FC 55 AA 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FC 00 00 00 00 00 00 00 00 00 00 00 00 8C 4A 94 ED FC 55 AA 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 BF 31 7C FE FD 55 AA 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FC 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 F9 32 F8 FC 55 AA 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C5 A0 E1 F2 FC 55 AA 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FC 00 00 00 00 00 00 00 00 00 00 00 78 68 AF F4 FC 55 AA 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 A3 56 31 D5 FC 55 AA 09 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FC 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1E 9E 7F D3 FC 55 AA 0A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 D9 C7 AC D9 FC 55 AA 0B 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \ No newline at end of file diff --git a/serial_module.c b/serial_module.c new file mode 100644 index 0000000..eb92914 --- /dev/null +++ b/serial_module.c @@ -0,0 +1,262 @@ +#define PY_SSIZE_T_CLEAN +#include +#include +#include +#include +#include +#include // 引入 zlib 库 +#include // 引入 libfec 库 +#include "hx_serial.h" +#include "hx_ringbuffer.h" +#include // 引入 pthread 库 + +// 宏定义 +#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 +#define QUEUE_MAX_SIZE 1024 // 队列最大容量 + +// 全局变量 +static by_serial_t serial_port; +static by_ringbuf_t ring_buffer; +static uint8_t send_buffer[FRAME_SIZE]; +static uint8_t frame_counter = 0; +static uint8_t data_len = 0; + +// 定义队列结构体 +typedef struct { + uint8_t *data; + int length; +} FrameData; + +// 队列相关定义 +static FrameData frame_queue[QUEUE_MAX_SIZE]; // 存储接收到的数据帧 +static int queue_head = 0; // 队列头指针 +static int queue_tail = 0; // 队列尾指针 +static pthread_mutex_t queue_mutex = PTHREAD_MUTEX_INITIALIZER; // 保护队列的互斥锁 +static bool stop_receiving = false; // 控制接收线程停止的标志 + +// 前向声明 +void *receive_thread_func(void *arg); + +// 计算 CRC32 校验和 +uint32_t calculate_crc32(const uint8_t *data, size_t length) { + return crc32(0, data, length); +} + +// 解析一帧数据 +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]; + + // 计算 CRC32 校验 + 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; // 成功解析一帧,但可能还有更多帧 +} + +// 接收线程函数 +void *receive_thread_func(void *arg) { + while (!stop_receiving) { + uint8_t output_data[8192]; + int output_len = 0; + + // 从串口读取数据到环形缓冲区 + uint8_t buffer[FRAME_SIZE]; + int ret = by_serial_read(&serial_port, buffer, FRAME_SIZE); + if (ret > 0) { + by_ringbuf_append(&ring_buffer, buffer, ret); + } + + // 尝试解析环形缓冲区中的数据 + while (1) { + int parse_result = parse_frame(&ring_buffer, output_data, &output_len); + if (parse_result == 1) { + // 将解析后的数据放入队列 + pthread_mutex_lock(&queue_mutex); + if ((queue_tail + 1) % QUEUE_MAX_SIZE != queue_head) { // 队列未满 + frame_queue[queue_tail].data = malloc(output_len); + memcpy(frame_queue[queue_tail].data, output_data, output_len); + frame_queue[queue_tail].length = output_len; + queue_tail = (queue_tail + 1) % QUEUE_MAX_SIZE; + } else { + printf("Queue is full, dropping frame!\n"); + } + pthread_mutex_unlock(&queue_mutex); + break; + } else if (parse_result == -1) { + break; // 数据不足或解析失败,退出循环 + } + } + + usleep(1000); // 避免占用过多 CPU + } + return NULL; +} + +// 初始化串口 +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; + } + + // 启动接收线程 + pthread_t receive_thread; + stop_receiving = false; + if (pthread_create(&receive_thread, NULL, receive_thread_func, NULL) != 0) { + PyErr_SetString(PyExc_RuntimeError, "Failed to start receive thread"); + return NULL; + } + + 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; + } + + size_t offset = 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); + + // 计算 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); + + // 发送帧 + 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++; + usleep(80000); + } + + frame_counter = 0; + Py_RETURN_NONE; +} + +// 接收数据 +static PyObject *serial_receive(PyObject *self, PyObject *args) { + pthread_mutex_lock(&queue_mutex); + if (queue_head == queue_tail) { + pthread_mutex_unlock(&queue_mutex); + PyErr_SetString(PyExc_IOError, "No data available in the queue"); + return NULL; + } + + // 获取队列中最早的数据包 + FrameData frame = frame_queue[queue_head]; + queue_head = (queue_head + 1) % QUEUE_MAX_SIZE; + pthread_mutex_unlock(&queue_mutex); + + // 返回解析后的数据 + PyObject *result = Py_BuildValue("y#", frame.data, frame.length); + free(frame.data); // 释放内存 + return result; +} + +// 模块方法表 +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); +} \ No newline at end of file diff --git a/serial_module.so b/serial_module.so new file mode 100755 index 0000000000000000000000000000000000000000..6a5dec947d8ad8e1c1a05fa896b0f43db349f367 GIT binary patch literal 37160 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 literal 0 HcmV?d00001 diff --git a/serial_module_bk.c b/serial_module_bk.c new file mode 100644 index 0000000..39e749e --- /dev/null +++ b/serial_module_bk.c @@ -0,0 +1,269 @@ +#define PY_SSIZE_T_CLEAN +#include +#include +#include +#include +#include +#include // 引入 zlib 库 +#include // 引入 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); +} \ No newline at end of file diff --git a/test_recv.jpg b/test_recv.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5dcabf54590bc1701c2f3ff6761109d4cd2003c6 GIT binary patch literal 10573 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 ATmS$7 literal 0 HcmV?d00001 diff --git a/test_recv.py b/test_recv.py new file mode 100644 index 0000000..6ef147c --- /dev/null +++ b/test_recv.py @@ -0,0 +1,21 @@ +import serial_module +import cv2 +import numpy as np + +serial_module.init("/dev/ttyUSB1") +while True: + try: + data = serial_module.receive() + # print("Received data:", data) + if data: + frame = np.frombuffer(data, np.uint8) + # 将数据转换为图像 + image = cv2.imdecode(frame, cv2.IMREAD_COLOR) + # 显示图像 + cv2.imshow('Received Image', image) + cv2.imwrite('test_recv.jpg', image) + # 等待按键输入 + if cv2.waitKey(1) & 0xFF == ord('q'): + break + except Exception as e: + print("Error:", e) \ No newline at end of file diff --git a/test_send.jpg b/test_send.jpg new file mode 100644 index 0000000000000000000000000000000000000000..469e20876937ee695c673f619d39c63f1eca3bb5 GIT binary patch literal 6920 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 M!tjdrM(yoqiy~`@&E_PL#5brO?%duE{gL(VB z!rKV4O|KjONBb-xx$d~MWAB;(6ayrwUXC-3@jXa$oI&v;_(NTXfQU6bt-BGhTVPZc z%r9ok5mv2{*s^uHOHQd4cSAMroOq0Wxm8ws z!wj3&4~Fp8t22Wiom55(NbH9yIT4=CUkW;{>VNT}m&O3Lfhu}Mb}RDJYjIAeSb1WK zgm3*`3-(pNq1IEFzg(SBr~1T5)JN66!`C11e6zI*@tRte@~U*Q_Xx@_L<@3_UfDzV zuRv&skqo_Lk&0UkK;nuP++46p( z`n_FN@)Zpm7hSJYea^nH&-S^A4>v5_T34GdJ->9goLi$%nF^ILVcDFk%Al{VHF5?$ z{tdQ_lA&Gf@NJ%x5VIFPApgiyN)G=7hlO|MAY`}P`_x^`7`)7l#gqg!7V4eqM@VDc zvURy*NNqbbjsB9ZfK4MrArp_UD3LvVlQ z0^$jJqH`5g0cgRZ|3Dro-?tOSS zND~SF7;AA?U35p69Mmd=hy^_7M^|Az?z=vr1lxv&2NafhJIx&3Q{uiX;)An25ceo7 zbK5w7*RS4XqGNXIW))=fIF`pfaujQp*be&aGrL3h$-s051@#oZ?l7viDzwyKh_J2` z)qd{GP$JTBneEM%2x8^pB*Sd!c_DhLy}?royhdmq=VHv1Y}&e=Z%Bzkhi;vuM}WMl75>PRQ&$9wXF9Y{&v{@_E^60bR=%CC&3FKXXy zg9+dlT0ILZITos7x&1zTF@Lq0{Y7Z&t^G6BR_Io^vbB?mrjPTq$Z6sVf`hD(VdSsg2je|TTY?|(N z&`e64&E=YZ0Zj7aw(P4~J5Ej?>v7G$wUF@rhw44+1K3+xxU5dRjb^f3ATIkw zy>vaNw+Y%hpHK6+b`L0mUWp+8cx<o<@3g zH8~nn+}V0`!yQDiAW6hy_sL}qpzt037aqp2# zs+`9Ll#Ij}Pt!{6A4PkC!>%F*J3y&As83WWPSvG`wN{ZwKzI!djV^U_eA)B!Ro$k| zO7rE;p3e@J(+_|IqClf?ugl8}11HD?ifh1j(*oWyW-KfoO6kmVs@biJVd(or9NoT6 zJ+Bz(&(URs80>CBTB^&o_XqDeY;)E}EB?YL?T)#ob~{?u%T~R1u}>5}In%gJF-_?G z7jS-kU&KIt&~dNd(;SnWDp&Jp0~gkDH}L7DLz$+ENhdwcldOr3NB*sfmpN_P8;^{E z7pq`7Q!4>1{7x%ae|3r_&PSTZJfr*V&dK^Qt(mna2ek)kTsK_j99V&QU&xznw!Y#q z5DH6wz9k*^jcG6!&cThrYTEU7wFaWOg=Q)27N|@G$OYweTG~e=whPiOj*Z4IClT73naWIwiGC4KxS9n%+-T z(tLEGLD85Sf*DF9FD57J$_%a}Y5~yi%sjosyDfysxe^f z(T%HSjMlq=Lvm;3@0jC^H#bvKuZ?yCWd~B#U9RSKp=)*YM56Ew8sCn-UlE`CrzDh;XG4 z^j15LSfc~W_#wJ~SbW)WGpZRpiom#us0~D{RuB8|OCk5?GhbRSZ^$PfOl=sos+ibi z#?(z*aGV%-8kEVBB;JglRtFw;t7JhyZEE=8ce+v^HdalBwA7WHvv^q}TE4lV@!&IR z*P)<&23}pz->IrA3a>_8w^VjI$zo>vgR@pq9n29DGPQ^&(fPKw+oaMq1-L9)UD}dp zxG|M3ri`!C;(X_`Ijh2_Aw(*_UY|iywy9{DyWzL~9$e3~m!%r1B#l2=vz)lx;}fLV z8fOzw^g6$=2gzVmntu?5!&Fzbi@0gTQ-}f4rE8iUi%kEQ(2SK{WFj(tNONq=4^wyE&AfkHwF)KTJ1Y zM;+b~)Pw&zky#@6{U;Ijvk9ChfjRa5oNH-T5h1?+Dev}-%C8+CES4Y(bm)*W<|qst_Y~h2!T0>}^w7A0utfMDx>g)kZIseokBH z7*+H=!4afvN>cJEDo)q0ReUm09Ca&g7vH1@*gso~Qm&<_)``m37!efd%)SN~;W&c3 zi2y7ymT85T9mUkxi&WPp_iOeH5|X`gJ_3}Rv708(Ch4@yIRG0(1)9dCUm7j{b%T9T zjEFLz#ZXV34{+ZQ;B>1fhskX7rW-GksNGR)cM*hN8wsd0smN!&^tDyDu#Zm6=pPK(8ti3K3OW++5Kx^wLm(WIznHAS{5b_oo5OaU6at zFS`+TWka-GGzb&AeK98F>k888t1#z=Up6V}Ru3=3q0~}M_@LjJbUA^xY~!hGhIkTr zek|kCvl{=;xk)R4vbGwWVY|9cl6(PE|0yWnyG)ZUt?C&|As_#$OLz#tJxjkqlstCJ w`CaY1pov_=psAsbCt3+JO|`D-S{{7Ul)SQKN#U>6mMMt`uN4c# zRKTa<7t&%sJyD?qOslls6i~98N0lPN=gDcccCcJ11(UE47gtgk8OlX618 zCY?_|t%r;XQ@>rWw)4}q%1kh&HmGcQ-;I2e_S)I*LglB)M;jF^m~wm9!H)9szZO2s zn{|7oj>DMFBU3uwRF=k~ohurb#v*mGXgu9t*Wa|FZbf4-l?XOSImKn*N5f{_#;tT% z#t74C6csxZ&;Cd@N6Sh7pf$ej!M>l~c+>Iq`=4)k@`>}qd+#G1ikoamhYI=QLry%^ z&%%#%WIh6Sqb4c{Bmc+k*ZZ#gY?x0Qk`)xv)~9v>e!K)u?HC1`ig^m8m>;^76vLk> zq5okCyrP7k))M-EDS=-A+`!LYZU#^+&X-HzRVCuN9Qp=+{;~%^G5<~p{IwGJXTTTY z=P!Q(Fk8$QMo3Bcd=^$)#|A56J9bYr<=RfihBdK7-0lc>#%y6(J$;F|m2$(5YgtOQ zsAA`Um9m{^I0oWco#AxE3A?r^gp*+>>JE6oXgunASjP@WJZujP&Zc+m02p z<06@MQ-}%yb#1e{dbe5K;b=^BCz6n*Q!(34LW(o7OUK+7j>bjGMfV)hophpcw;Kvw z{b8#+8V|>!x7(t-E0#!sY)5dmfNgJoo$3otUgEpxBwiubt#4~yV>JXDbG3%x6}kFy zy8Z-kwgqqoPQjIx{;3|&2vH?dXFSzwF-G{hGbb9INmt}cHI|+q#hq!2Sg!fs{^Wj~ zz7=8>cq)8<;Nv*12al<*|BUa`cvVQ63C5W}u}a}|ZSY<<#yvP+qeyeYgP);H<^QAy zulC?4Jvd!+xbQfn>mgl-xb$lMX#jLrr6}pa>AJ_I--GL0vJ~y`;PSes4R(2OYJ9~Gp@J`X;foq#^(!Do2zQ4fv-oht`C_^cd?n}Y}EF+$>3Jos#n{xJ`( z54lHLu9h=U&OkW>+k02K5C0otGmCaN&hu(K*n8Pbu!A!KB%4R1bIC@7aw}KDc4BK4$ zWS`j%Ayu}*&b<4hB*tIF96oK)V(F^o_-#mUL7L+5Hmh==+MCnq5A?2e5B$Hsd;oF0ks2YE1S6(r-1hKf_Nzai=z{>A=TKk z8)0~mtY4t9OwzNYwDMQd)e$)Txpq381VcL?qo4+#CnC~UA&^cT$a&;N2l7L0^TC(d z?6B+yJP(0UQSE^mJojs@dI-3?&^rWnXy-mOF!((Ei@T~{+;?w4OuPa?W)p0OrF4j* zvz3nnXk1L3BOQ%QQiv*j2kB*$IrKX9?Ad>l-(O0<^e+Z_5&pwVNa4`IT2J_w=)f+4 zzdh!#>N7k%01vtD90Y>^cHpEoWhialP!|R&}rvgtZkzt)m#p zgyT*Z+dG9`BZ`FGaM0~{Jw~*GVjjK}$@neQzTpN#T<;`Y8@v{yv3!VY(HEmDoOII;`imHnb|h#>G!?#0Wn@umx(J*%>wlpLV zg>V55s&cO8c|RDf?oi<;^7)Dt zyf2J5db0fQr?LrB8P%J-cn{SvUE#e`C$yX=X4mTYuuLJ#JWX|2n#=ERZP)vg)a()a zm9;(1H>mJltaB7AZqWfUzDrj)?h{&%_hfPV3pCDpSRIl5Lvs?s3X0@S?GKA@ESHv; z-bjAFmj6TZy8GJu|BvMMY5QE(>*F2Lv|ZC%G)-!{L(@H)?$dNs(=kntX*#ayq^8&u z`i)9eNSUo$v*s#e@z&0C+)W$HmIs#y>+4peCEIXkLu0VM@lp+cbu%;^P7|NXH8rm$ z9p3;XyY&Guw2<}^7SpHWUmAm7*%5w=4_~fvJ|Dr#(uV&4_RB5~DP9j(LA$I2 z;_Te{q@+UJfeQKO^PBNqQh#o4zb504qEamWQvEt0{mc>bwzYN^q;5_s#;Ik{v6?|T? zXq<4$v^K&rxh$Umufh1N4{1P?$AO;-2_GE!ZV0l^wZ7rg$Doz^8GSJ2yB+9PN?bej zkohI>%S+&^fK$Kx$MJi>4Ub>0+9mu9mcZ`=zL1SQbT{c&;O@!SIW2p#gr70sMfb;V z>2lm3m;VQL7*=!zUK3ZVjn%^Tc^X0=)B)A6tt#3fhd5~#}5UN2&M-5 z+;AtT>nPgGHGCmqJ4q3YP$!RnNu{Pq1DZ8b#z)t_1nO=>wv&n`;suNanPbPoWT0!wm@9&^pFvcEJqfT>N!eW@=-OB`2+Cm+ zbP{qL1?^saX7onjjXC8*og&JD>u4(67lkurjw3CCI5+!n%6Tpy-?&Q8-?-G$WmOjc z_lo@dt;JH8>qNhUA3b`qeW~yANS6vf=PFK!6{vXa{om)&`hd6a{e&@k?(y35a~D&C z6*cwSUl05XJTr6rJg;E7SljWu!XJMaa+*`HJfV%dw%|p0;5Mow&!^a zQ=Yd#MHcOjS#c|BG$&wto(C|!OlxxdtjF|D$Z3wjJkK+jhP1suehrHeR4Aux&+{Ip zC$u8B@9+Nu+P+!q@jQwt&%4N;a^|=H1u)79`_J7!^?j7*mr#+#fBYW=>a{nt9n(o| z$AoXsOds{x*Xa34j-+QfJ8jR$Ul>|b(e*p83m z6Tm2cIeY!yqJ1f8<2{KYxqr52Iu*uVdlAyA^@?&k?11f +#include +#include +#include + +#define BUFFER_SIZE 1024 +#define OUTPUT_FILE "serial_data.txt" + +int main() { + by_serial_t serial_port; + char buffer[BUFFER_SIZE]; + int bytes_read; + int total_bytes_read = 0; + FILE *output_file; + + // 初始化串口 + if (by_serial_init(&serial_port, "/dev/ttyUSB1") != 0) { + fprintf(stderr, "Failed to initialize serial port\n"); + return -1; + } + + by_serial_set_baudrate(&serial_port, 115200); + by_serial_set_parity(&serial_port, 8, 1, 'N'); + + // 打开输出文件 + output_file = fopen(OUTPUT_FILE, "wb"); + if (output_file == NULL) { + fprintf(stderr, "Failed to open output file\n"); + close(serial_port.fd); + return -1; + } + + printf("Reading from serial port. Press ENTER to stop...\n"); + + // 循环读取串口数据 + while (1) { + // // 检查用户输入 + // if (fgetc(stdin) == '\n') { + // break; + // } + + // 检查缓冲区中是否有数据 + int used_len = by_serial_get_used_buffer_len(&serial_port); + if (used_len <= 0) { + usleep(100000); // 等待 100ms + // printf("no data\n"); + continue; + }else{ + printf("used_len = %d; ", used_len); + } + + // 读取数据 + bytes_read = by_serial_read(&serial_port, buffer, BUFFER_SIZE); + if (bytes_read < 0) { + fprintf(stderr, "Error reading from serial port\n"); + break; + } + + total_bytes_read += bytes_read; + printf("Total bytes read: %d\n", total_bytes_read); + + // 将数据以 ASCII 格式写入文件 + // fwrite(buffer, 1, bytes_read, output_file); + for (int i = 0; i < bytes_read; i++) { + fprintf(output_file, "%02X ", (unsigned char)buffer[i]); + } + fprintf(stderr, "Wrote %d bytes to file\n", bytes_read); + } + + // 关闭文件和串口 + fclose(output_file); + close(serial_port.fd); + + printf("Data capture stopped. Data saved to %s\n", OUTPUT_FILE); + return 0; +} \ No newline at end of file diff --git a/tool_ckframe.py b/tool_ckframe.py new file mode 100644 index 0000000..566d446 --- /dev/null +++ b/tool_ckframe.py @@ -0,0 +1,33 @@ +def calculate_frame_lengths(file_content): + # 将文件内容转换为十六进制字节列表 + hex_data = file_content.split() + + frame_lengths = [] + frame_start = 0 + + # 遍历字节列表,查找帧头 + for i in range(len(hex_data) - 1): + if hex_data[i] == '55' and hex_data[i + 1] == 'AA': + # 找到帧头,计算当前帧的长度 + if frame_start != 0: + frame_length = i - frame_start + frame_lengths.append(frame_length) + frame_start = i + + # 处理最后一帧 + if frame_start != 0: + frame_length = len(hex_data) - frame_start + frame_lengths.append(frame_length) + + return frame_lengths + +# 读取文件内容 +with open('serial_data.txt', 'r') as file: + file_content = file.read() + +# 计算每一帧的长度 +frame_lengths = calculate_frame_lengths(file_content) + +# 输出每一帧的长度 +for i, length in enumerate(frame_lengths): + print(f"Frame {i + 1}: Length = {length} bytes") \ No newline at end of file