基于 Rust 與 GBT32960 規范的編解碼層

根據架構設計,實現編解碼層的代碼設計

Cargo.toml 加入二進制序列化支持

# 序列化支持
...
bincode = "1.3"           # 添加二進制序列化支持
bytes-utils = "0.1"       # 添加字節處理工具

開始編碼

錯誤處理(error.rs):

定義了編解碼過程中可能遇到的錯誤類型,使用枚舉定義

use thiserror::Error;#[derive(Error, Debug)]
pub enum CodecError {#[error("數據長度不足")]InsufficientData,#[error("校驗和錯誤")]ChecksumMismatch,#[error("無效的起始符")]InvalidStartByte,#[error("無效的命令標識: {0}")] InvalidCommand(u8),#[error("IO錯誤: {0}")] Io(#[from] std::io::Error),
}

數據幀結構(frame.rs):

- 定義了符合 GBT32960 協議的數據幀結構
- 提供了創建和校驗數據幀的方法

frame.rs

use bytes::{ Bytes, BytesMut, BufMut };
use chrono::NaiveDateTime;
use serde::{ Serialize, Deserialize };#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Frame {pub start_byte: u8, // 起始符 0x23pub command_flag: u8, // 命令標識pub response_flag: u8, // 應答標志pub vin: String, // 車輛識別碼pub encrypt_method: u8, // 加密方式pub payload_length: u16, // 數據單元長度pub payload: Bytes, // 數據單元pub checksum: u8, // BCC校驗碼
}impl Frame {pub fn new(command: u8, vin: String, payload: Bytes) -> Self {let payload_length = payload.len() as u16;Self {start_byte: 0x23,command_flag: command,response_flag: 0xfe,vin,encrypt_method: 0x01,payload_length,payload,checksum: 0x00, // 將在編碼時計算}}pub fn calculate_checksum(&self) -> u8 {let mut bcc: u8 = 0;// 命令標識bcc ^= self.command_flag;// 應答標志bcc ^= self.response_flag;// VIN碼(17位)for byte in self.vin.as_bytes() {bcc ^= byte;}// 加密方式bcc ^= self.encrypt_method;// 數據單元長度(2字節)bcc ^= ((self.payload_length >> 8) & 0xff) as u8;bcc ^= (self.payload_length & 0xff) as u8;// 數據單元for byte in self.payload.iter() {bcc ^= byte;}bcc}
}#[cfg(test)]
mod tests {use super::*;#[test]fn test_calculate_checksum() {let payload = Bytes::from_static(&[0x01, 0x02, 0x03]);let frame = Frame::new(0x01, // command"LSVNV2182E0200001".to_string(), // vinpayload);let checksum = frame.calculate_checksum();assert!(checksum != 0, "校驗和不應該為0");// 創建相同內容的幀,校驗和應該相同let frame2 = Frame::new(0x01,"LSVNV2182E0200001".to_string(),Bytes::from_static(&[0x01, 0x02, 0x03]));assert_eq!(checksum, frame2.calculate_checksum(), "相同內容的幀應該有相同的校驗和");}#[test]fn test_different_content_different_checksum() {let frame1 = Frame::new(0x01, "LSVNV2182E0200001".to_string(), Bytes::from_static(&[0x01]));let frame2 = Frame::new(0x01, "LSVNV2182E0200001".to_string(), Bytes::from_static(&[0x02]));assert_ne!(frame1.calculate_checksum(),frame2.calculate_checksum(),"不同內容的幀應該有不同的校驗和");}
}

編解碼器(codec.rs):

- 實現了 tokio 的 Decoder 和 Encoder trait
- 負責數據幀的序列化和反序列化

use bytes::{ BytesMut, Buf };
use tokio_util::codec::{ Decoder, Encoder };
use super::{ Frame, CodecError };pub struct Gbt32960Codec;impl Decoder for Gbt32960Codec {type Item = Frame;type Error = CodecError;fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {// 檢查數據長度是否足夠if src.len() < 22 {// 最小幀長度return Ok(None);}// 檢查起始符if src[0] != 0x23 {return Err(CodecError::InvalidStartByte);}// TODO: 實現完整的解碼邏輯// 1. 讀取各個字段// 2. 驗證校驗和// 3. 解析數據單元Ok(None)}
}impl Encoder<Frame> for Gbt32960Codec {type Error = CodecError;fn encode(&mut self, frame: Frame, dst: &mut BytesMut) -> Result<(), Self::Error> {// TODO: 實現編碼邏輯// 1. 寫入各個字段// 2. 計算并寫入校驗和Ok(())}
}

實現完整的解碼邏輯

use bytes::{BytesMut, Buf, BufMut};
use tokio_util::codec::{Decoder, Encoder};
use super::{Frame, CodecError};pub struct Gbt32960Codec;impl Decoder for Gbt32960Codec {type Item = Frame;type Error = CodecError;fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {// 檢查數據長度是否足夠if src.len() < 22 {  // 最小幀長度return Ok(None);}// 檢查起始符if src[0] != 0x23 {return Err(CodecError::InvalidStartByte);}// 讀取命令標識和應答標志let command_flag = src[1];let response_flag = src[2];// 讀取 VIN 碼(17字節)let vin = String::from_utf8_lossy(&src[3..20]).to_string();// 讀取加密方式let encrypt_method = src[20];// 讀取數據單元長度(2字節)let payload_length = ((src[21] as u16) << 8) | (src[22] as u16);// 檢查是否有足夠的數據let total_length = 23 + payload_length as usize + 1; // 頭部 + 數據單元 + 校驗碼if src.len() < total_length {return Ok(None);}// 讀取數據單元let payload = src.slice(23..23 + payload_length as usize);// 讀取校驗碼let received_checksum = src[total_length - 1];// 創建幀對象進行校驗和計算let frame = Frame {start_byte: 0x23,command_flag,response_flag,vin,encrypt_method,payload_length,payload: payload.freeze(),checksum: received_checksum,};// 驗證校驗和let calculated_checksum = frame.calculate_checksum();if calculated_checksum != received_checksum {return Err(CodecError::ChecksumMismatch);}// 消費已處理的字節src.advance(total_length);Ok(Some(frame))}
}impl Encoder<Frame> for Gbt32960Codec {type Error = CodecError;fn encode(&mut self, frame: Frame, dst: &mut BytesMut) -> Result<(), Self::Error> {// TODO: 實現編碼邏輯// 1. 寫入各個字段// 2. 計算并寫入校驗和Ok(())}
}#[cfg(test)]
mod tests {use super::*;use bytes::Bytes;#[test]fn test_decode_valid_frame() {let mut codec = Gbt32960Codec;let mut buffer = BytesMut::new();// 構造測試數據buffer.put_u8(0x23);                          // 起始符buffer.put_u8(0x01);                          // 命令標識buffer.put_u8(0xFE);                          // 應答標志buffer.extend_from_slice(b"LSVNV2182E0200001"); // VIN碼buffer.put_u8(0x01);                          // 加密方式buffer.put_u16(2);                            // 數據長度buffer.extend_from_slice(&[0x01, 0x02]);      // 數據單元// 計算并添加校驗和let checksum = buffer[1..buffer.len()].iter().fold(0u8, |acc, &x| acc ^ x);buffer.put_u8(checksum);// 解碼let result = codec.decode(&mut buffer).unwrap().unwrap();// 驗證解碼結果assert_eq!(result.command_flag, 0x01);assert_eq!(result.vin, "LSVNV2182E0200001");assert_eq!(result.payload.len(), 2);assert_eq!(buffer.len(), 0); // 確保所有數據都被消費}#[test]fn test_decode_invalid_checksum() {let mut codec = Gbt32960Codec;let mut buffer = BytesMut::new();// 構造測試數據(使用錯誤的校驗和)buffer.put_u8(0x23);buffer.put_u8(0x01);buffer.put_u8(0xFE);buffer.extend_from_slice(b"LSVNV2182E0200001");buffer.put_u8(0x01);buffer.put_u16(0);buffer.put_u8(0xFF); // 錯誤的校驗和// 驗證解碼失敗assert!(matches!(codec.decode(&mut buffer),Err(CodecError::ChecksumMismatch)));}
}

代碼地址

阿里云登錄 - 歡迎登錄阿里云,安全穩定的云計算服務平臺

總結

1. 完整的幀解析邏輯:
? ?- 起始符驗證,根據接口協議驗證是否0x23開頭
? ?- 命令標識和應答標志解析
? ?- VIN碼解析,vin碼17個字節長度
? ?- 加密方式解析,讀取加密方式,測試的時候可以先不使用,上生產環境后要打開
? ?- 數據單元長度解析,表示數據payload的總長度
? ?- 數據單元提取
? ?- 校驗和驗證
2. 數據完整性檢查:
? ?- 最小幀長度檢查
? ?- 完整數據長度檢查
? ?- 校驗和驗證
3. 添加了單元測試:
???- 測試有效幀的解碼
? ?- 測試校驗和錯誤的情況

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/896880.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/896880.shtml
英文地址,請注明出處:http://en.pswp.cn/news/896880.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

MOM成功實施分享(七)電力電容制造MOM工藝分析與解決方案(第一部分)

聲明&#xff1a;文章僅用于交流學習&#xff0c;不用于商業項目實施&#xff0c;圖片來源于網絡&#xff0c;如有侵犯權利&#xff0c;請聯系作者及時刪除。 本方案旨在對電力電容&#xff08;PEC和PQM型號&#xff09;制造工藝深度分析&#xff0c;結合管理要求設計MOM相關功…

FPGA開發,使用Deepseek V3還是R1(1):應用場景

以下都是Deepseek生成的答案 FPGA開發&#xff0c;使用Deepseek V3還是R1&#xff08;1&#xff09;&#xff1a;應用場景 FPGA開發&#xff0c;使用Deepseek V3還是R1&#xff08;2&#xff09;&#xff1a;V3和R1的區別 FPGA開發&#xff0c;使用Deepseek V3還是R1&#x…

JavaWeb后端基礎(3)

原打算把Mysql操作數據庫的一些知識寫進去&#xff0c;但是感覺沒必要&#xff0c;要是現在會的都是簡單的增刪改查&#xff0c;所以&#xff0c;這一篇&#xff0c;我直接從java操作數據庫開始寫&#xff0c;所以這一篇大致就是記一下JDBC、MyBatis、以及SpringBoot的配置文件…

Pytorch實現之SRGAN+CBAM的結構設計

簡介 簡介:在SRGAN的殘差連接中加入了CBAM注意力機制,同時設計了四類損失來訓練。 論文題目:Super-resolution Generative Adversarial Networks Based on Attention Model(基于注意力模型的超分辨率生成對抗網絡) 會議:2020 IEEE第六屆計算機與通信國際會議 摘要:基…

移動端國際化翻譯同步解決方案-V3

1.前言 因為軟件出海&#xff0c;從在上上家公司就開始做翻譯系統&#xff0c;到目前為止已經出了兩個比較大的版本了&#xff0c;各個版本解決的痛點如下&#xff1a; V1版本&#xff1a; 主要針對的是AndroidiOS翻譯不一致和翻譯內容管理麻煩的問題&#xff0c;通過這個工具…

2.css簡介

什么是css&#xff1a; CSS (Cascading Style Sheets&#xff0c;層疊樣式表&#xff09;&#xff0c;是一種用來為結構化文檔&#xff08;如 HTML 文檔或 XML 應用&#xff09;添加樣式&#xff08;字體、間距和顏色等&#xff09;的計算機語言&#xff0c;CSS 文件擴展名為 .…

機器人學習模擬框架 robosuite (3) 機器人控制代碼示例

Robosuite框架是一個用于機器人模擬和控制的強大工具&#xff0c;支持多種類型的機器人。 官方文檔&#xff1a;Overview — robosuite 1.5 documentation 開源地址&#xff1a;https://github.com/ARISE-Initiative/robosuite 目錄 1、通過鍵盤或SpaceMouse遠程控制機器人…

可終身授權的外國工具,不限次數使用!PDF轉CAD的軟件

最近有不少朋友問我有沒有好用的CAD轉換工具&#xff0c;今天就來給大家分享兩款超實用的小軟件&#xff0c;希望能幫到大家。 第一款軟件是一款國外開發的&#xff0c;它專門用來把PDF文件轉換成CAD格式&#xff0c;特別方便。 這款軟件的操作非常簡單&#xff0c;打開后無需安…

Ubuntu系統上部署Node.js項目的完整流程

以下是在Ubuntu系統上部署Node.js項目的完整流程&#xff0c;分為系統初始化、環境配置、項目部署三個部分&#xff1a; 一、系統初始化 & 環境準備 bash # 1. 更新系統軟件包 sudo apt update && sudo apt upgrade -y# 2. 安裝基礎工具 sudo apt install -y buil…

Android內存優化指南:從數據結構到5R法則的全面策略

目錄 一、APP 內存限制 二、內存的三大問題 2.1、內存抖動(Memory Churn) 2.1.1 頻繁創建短生命周期對象 2.1.2 系統API或第三方庫的不合理使用 2.1.3 Handler使用不當 2.2、內存泄漏(Memory Leak) 2.2.1 靜態變量持有Activity或Context引用 2.2.2 未取消的回調或…

ffmpeg源碼編譯支持cuda

1.安裝cuda CUDA Toolkit 11.3 Downloads | NVIDIA Developer 在選擇組件的時候&#xff0c;將CUDA中的Nsight VSE和Visual Studio Integration取消勾選 不然會安裝失敗 2.編譯ffmpeg 把cuda編譯宏定義開啟&#xff0c;再編譯avcodec 3.編譯livavutil報錯struct "Cuda…

Git強制覆蓋分支:將任意分支完全恢復為main分支內容

Git強制覆蓋分支&#xff1a;將任意分支完全恢復為main分支內容 場景背景完整操作步驟一、前置準備二、操作流程步驟 1&#xff1a;更新本地 main 分支步驟 2&#xff1a;強制重置目標分支步驟 3&#xff1a;強制推送至遠程倉庫 三、操作示意圖 關鍵風險提示&#xff08;必讀&a…

【Java反序列化測試】

Java反序列化測試 1. 識別反序列化入口點2. 構造探測Payload3. 發送Payload并觀察結果4. 繞過可能的防護5. 自動化工具注意事項總結 Java反序列化測試&#xff1a; 1. 識別反序列化入口點 常見入口&#xff1a; HTTP請求參數&#xff08;如POST數據、Cookie、Headers&#xff…

golang的io

https://www.bilibili.com/list/BV1gx4y1r7xb 1. 原生io包 io包是Go語言標準庫中底層的I/O接口層&#xff0c;定義了通用的讀寫規則和錯誤處理邏輯。每次讀寫都是直接調用底層系統 I/O&#xff0c;每次讀取1字節&#xff0c;系統調用次數多。適用于小數據量、實時性要求高。io…

【北京迅為】iTOP-RK3568OpenHarmony系統南向驅動開發-第4章 UART基礎知識

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工藝&#xff0c;搭載一顆四核Cortex-A55處理器和Mali G52 2EE 圖形處理器。RK3568 支持4K 解碼和 1080P 編碼&#xff0c;支持SATA/PCIE/USB3.0 外圍接口。RK3568內置獨立NPU&#xff0c;可用于輕量級人工…

【計算機網絡入門】初學計算機網絡(十)(重要)

目錄 1. 網絡層的作用 2. IPV4 2.1 IP 數據報格式 2.2 IP地址分類方案 2.3 數據的轉發 2.4 特殊用途的IP地址 3. 子網劃分和子網掩碼 3.1 子網劃分 3.2 子網掩碼 1. 網絡層的作用 按照教學五層模型&#xff0c;應用層、傳輸層、網絡層、數據鏈路層、物理層&#xff…

機器學習(五)

一&#xff0c;多類&#xff08;Multiclass&#xff09; 多類是指輸出不止有兩個輸出標簽&#xff0c;想要對多個種類進行分類。 Softmax回歸算法&#xff1a; Softmax回歸算法是Logistic回歸在多類問題上的推廣&#xff0c;和線性回歸一樣&#xff0c;將輸入的特征與權重進行…

基于 Vue 和 SSM 的前后端分離項目實戰:登錄與注冊功能實現

文章目錄 前言項目概述前端部分&#xff08;Vue&#xff09;1. 項目初始化2. 頁面布局Login.vueRegister.vue 3. 路由配置4. 主組件 后端部分&#xff08;SSM&#xff09;1. 項目結構2. 數據庫設計3. MyBatis 配置4. DAO 層5. Service 層6. Controller 層7. 配置文件8. Spring …

Windows安裝nvm【超詳細圖解】

目錄 前言 一、NVM下載 方式一&#xff1a;官網下載 方式二&#xff1a;GitHub 下載 二、NVM安裝 鏡像源配置 三、Node安裝 四、環境變量配置 前言 NVM&#xff08;Node Version Manager&#xff09;是一個命令行工具&#xff0c;用于在一臺計算機上輕松管理和切換多…

KVM虛擬機磁盤創建探究-2

使用 virt-install 命令自動創建磁盤鏡像和使用 qemu-img 手動創建磁盤鏡像&#xff0c;在磁盤鏡像本身格式和基本功能上是一致的&#xff0c;但在一些特性如初始占用磁盤空間、創建時的可配置性等方面存在區別&#xff0c;下面以 QCOW2 格式磁盤鏡像為例進行詳細說明。 初始占…