嵌入式通信協議框架的四層架構設計與實現

文章目錄

  • 一、硬件抽象層:數據收發的基石
    • 1.1 設計要點
    • 1.2 代碼示例
  • 二、協議管理層:智能路由中樞
    • 2.1 設計要點
    • 2.2 代碼示例
  • 三、協議處理層:協議具體實現
    • 3.1 設計要求
    • 3.2代碼示例
      • 3.2.1 協議公共定義
      • 3.2.2 協議一設計
      • 3.2.3 協議二設計
  • 四、應用層:業務邏輯實現
    • 4.1 設計要點
    • 4.2 代碼示例
      • 4.2.1 協議一處理
      • 4.2.2 協議二處理
  • 五、四層協作流程
    • 5.1 收發流程
    • 5.2 代碼示例
  • 總結


在嵌入式系統開發中,高效可靠的通信協議棧設計對系統穩定性至關重要。本文將深入剖析一種四層通信協議架構設計,從硬件抽象到應用處理逐層分解,幫助開發者構建靈活、可擴展的嵌入式通信系統。

下面我將完整展示每個層次的示例代碼實現,并附上詳細說明。這個架構已被多個工業級項目驗證,能夠處理復雜的通信需求。

一、硬件抽象層:數據收發的基石

硬件抽象層是與具體硬件打交道的底層,需要處理最原始的數據收發和緩沖管理。

1.1 設計要點

  1. 雙緩沖設計:獨立的發送和接收緩沖區避免數據競爭

  2. 環形隊列:高效利用緩沖區空間,避免頻繁內存分配

  3. 硬件封裝:drv_custom_can_開頭的函數是硬件驅動接口

  4. 狀態管理:通過can_t結構體維護通信狀態

  5. 錯誤隔離:硬件錯誤不會直接影響上層邏輯

1.2 代碼示例

/* 緩沖區大小配置 */
#define CUSTOM_CAN_TX_BUFFER_SIZE 1024
#define CUSTOM_CAN_RX_BUFFER_SIZE 512/* 靜態緩沖區分配 */
static uint8_t custom_can_tx_buf[CUSTOM_CAN_TX_BUFFER_SIZE];
static uint8_t custom_can_rx_buf[CUSTOM_CAN_RX_BUFFER_SIZE];/* CAN硬件信息結構體 */
typedef struct {uint8_t* tx_buf;        // 發送緩沖區指針uint8_t* rx_buf;        // 接收緩沖區指針uint16_t tx_buf_size;   // 發送緩沖區大小uint16_t rx_buf_size;   // 接收緩沖區大小bool tx_running;        // 發送狀態標志bool can_error;         // 錯誤狀態標志RingQueue rx_queue;     // 接收環形隊列RingQueue tx_queue;     // 發送環形隊列
} can_t;/* CAN硬件信息實例 */
static can_t custom_can_info = {.tx_buf = custom_can_tx_buf,.rx_buf = custom_can_rx_buf,.tx_buf_size = CUSTOM_CAN_TX_BUFFER_SIZE,.rx_buf_size = CUSTOM_CAN_RX_BUFFER_SIZE,.tx_running = false,.can_error = false,
};/* 獲取CAN信息結構體指針 */
can_t* get_custom_can_info(void)
{return &custom_can_info;
}/* 硬件初始化函數 */
void custom_can_init(void)
{can_t* can_info = get_custom_can_info();/* 初始化收發環形隊列 */init_queue(&can_info->rx_queue, can_info->rx_buf, can_info->rx_buf_size);init_queue(&can_info->tx_queue, can_info->tx_buf, can_info->tx_buf_size);/* 硬件特定初始化 */drv_custom_can_hw_init();/* 上層協議初始化 */protocol_manager_init();
}/* 清空接收隊列 */
void custom_can_rx_queue_clear(void)
{can_t* can_info = get_custom_can_info();clear_queue(&can_info->rx_queue);
}/* 獲取接收隊列數據長度 */
uint16_t custom_can_rx_queue_len(void)
{can_t* can_info = get_custom_can_info();return queue_length(&can_info->rx_queue);
}/* 從接收隊列讀取數據 */
uint16_t custom_can_read(uint8_t* buf, uint16_t read_len)
{can_t* can_info = get_custom_can_info();return read_block_queue(buf, &can_info->rx_queue, read_len);
}/* 發送數據接口 */
uint16_t custom_can_puts(const uint8_t *src, uint16_t len)
{/* 調用硬件驅動發送 */return drv_custom_can_puts(src, len);
}

二、協議管理層:智能路由中樞

協議管理層是框架的核心樞紐,負責協議的識別和路由。

2.1 設計要點

  1. 插件架構:通過描述符動態注冊協議

  2. 自動識別:基于特征值快速識別協議類型

  3. 統一接口:為上層提供一致的解析和構建接口

  4. 類型安全:使用強類型避免錯誤

  5. 可擴展性:易于添加新協議支持

2.2 代碼示例

/* 最大支持的協議數量 */
#define MAX_PROTOCOLS 5/* 自動解析協議數據 */
ProtocolStatus parse_protocol_auto(const uint8_t* data, uint16_t length, ProtocolType* type, void* frame, size_t frame_size
);/* 協議1發送接口 */
ProtocolStatus send_protocol1(uint16_t src_id,uint16_t dest_id,uint8_t cmd_set,uint8_t cmd_id,const uint8_t* data,uint16_t data_len
);/* 協議2發送接口 */ 
ProtocolStatus send_protocol2(uint8_t src_id,uint8_t dest_id,uint8_t cmd_id,const uint8_t* data,uint16_t data_len
);/* 已注冊協議數組 */
static const ProtocolDescriptor* registered_protocols[MAX_PROTOCOLS];
static int protocol_count = 0;/* 協議管理器初始化 */
void protocol_manager_init(void) 
{if (protocol_count == 0) {/* 注冊協議1 */registered_protocols[protocol_count++] = &protocol1_descriptor;/* 注冊協議2 */registered_protocols[protocol_count++] = &protocol2_descriptor;/* 可擴展注冊更多協議... */}
}/* 協議自動識別 */
static ProtocolType detect_protocol(const uint8_t* data, uint16_t length) 
{if (length < 1) return PROTOCOL_UNKNOWN;/* 檢查協議1特征 */if (data[0] == PROTOCOL1_HEADER) {return PROTOCOL_TYPE_1;} /* 檢查協議2特征 */else if (length >= 2 && data[0] == PROTOCOL2_HEADER_1 && data[1] == PROTOCOL2_HEADER_2) {return PROTOCOL_TYPE_2;}return PROTOCOL_UNKNOWN;
}/* 獲取協議描述符 */
static const ProtocolDescriptor* get_protocol(ProtocolType type) 
{for (int i = 0; i < protocol_count; i++) {if (registered_protocols[i]->type == type) {return registered_protocols[i];}}return NULL;
}/* 通用協議解析入口 */
ProtocolStatus parse_protocol_auto(const uint8_t* data, uint16_t length, ProtocolType* type, void* frame, size_t frame_size) 
{/* 1. 協議識別 */ProtocolType detected_type = detect_protocol(data, length);if (detected_type == PROTOCOL_UNKNOWN) {return PROTOCOL_ERR_TYPE;}/* 2. 獲取協議描述符 */const ProtocolDescriptor* proto = get_protocol(detected_type);if (!proto || frame_size < proto->frame_size) {return PROTOCOL_ERR_TYPE;}/* 3. 調用具體協議解析 */*type = detected_type;return proto->parse(data, length, frame);
}/* 構建協議數據 */
static ProtocolStatus build_protocol(ProtocolType type, const void* frame, uint8_t* buffer, uint16_t buffer_size) 
{const ProtocolDescriptor* proto = get_protocol(type);if (!proto) return PROTOCOL_ERR_TYPE;return proto->build(frame, buffer, buffer_size);
}/* 協議解包處理 */
void custom_can_run_unpack(uint8_t *pdata, uint16_t pdata_len)
{ProtocolType type;union {Protocol1Frame frame1;Protocol2Frame frame2;} frame;/* 1. 自動解析協議 */ProtocolStatus status = parse_protocol_auto(pdata, pdata_len, &type, &frame, sizeof(frame));/* 2. 根據協議類型路由處理 */if (status == PROTOCOL_OK) {switch(type) {case PROTOCOL_TYPE_1:handle_protocol1_data(&frame.frame1);break;case PROTOCOL_TYPE_2:handle_protocol2_data(&frame.frame2);break;default:DEBUG_MSG("Unknown protocol type");break;}} else {DEBUG_MSG("Parse error: %d", status);}
}/* 協議1數據發送實現 */
ProtocolStatus send_protocol1(uint16_t src_id,uint16_t dest_id,uint8_t cmd_set,uint8_t cmd_id,const uint8_t* data,uint16_t data_len) 
{uint8_t send_buf[MAX_PROTOCOL_LEN];/* 構造協議1幀 */Protocol1Frame frame = {.src_id = src_id,.dest_id = dest_id,.cmd_set = cmd_set,.cmd_id = cmd_id,.data_len = data_len,.data = (uint8_t*)data};/* 構建協議1原始數據 */ProtocolStatus status = build_protocol(PROTOCOL_TYPE_1, &frame, send_buf, sizeof(send_buf));/* 通過硬件層發送 */if (status == PROTOCOL_OK) {uint16_t total_len = protocol1_descriptor.min_frame_len + data_len;custom_can_puts(send_buf, total_len);}return status;
}/* 協議2數據發送實現 */
ProtocolStatus send_protocol2(uint8_t src_id,uint8_t dest_id,uint8_t cmd_id,const uint8_t* data,uint16_t data_len) 
{uint8_t send_buf[MAX_PROTOCOL_LEN];/* 構造協議2幀 */Protocol2Frame frame = {.src_id = src_id,.dest_id = dest_id,.cmd_id = cmd_id,.data_len = data_len,.data = (uint8_t*)data};/* 構建協議2原始數據 */ProtocolStatus status = build_protocol(PROTOCOL_TYPE_2, &frame, send_buf, sizeof(send_buf));/* 通過硬件層發送 */if (status == PROTOCOL_OK) {uint16_t total_len = protocol2_descriptor.min_frame_len + data_len;custom_can_puts(send_buf, total_len);}return status;
}

三、協議處理層:協議具體實現

協議處理層包含各具體協議的實現細節(幀結構定義、解析函數、構建函數、校驗機制)。

3.1 設計要求

  1. 協議獨立性:每個協議完全獨立實現
  2. 內存安全:嚴格檢查緩沖區邊界
  3. 校驗機制:支持多種校驗方式
  4. 零拷貝:直接引用原始數據減少拷貝
  5. 標準接口:統一通過描述符暴露功能

3.2代碼示例

3.2.1 協議公共定義

/* 協議類型枚舉 */
typedef enum {PROTOCOL_TYPE_1 = 1,   // 協議類型1PROTOCOL_TYPE_2 = 2,   // 協議類型2PROTOCOL_UNKNOWN = 0xFF
} ProtocolType;/* 協議處理狀態 */
typedef enum {PROTOCOL_OK,            // 處理成功PROTOCOL_ERR_HEADER,    // 頭部錯誤PROTOCOL_ERR_LENGTH,    // 長度錯誤PROTOCOL_ERR_CHECKSUM,  // 校驗錯誤PROTOCOL_ERR_TYPE,      // 類型錯誤PROTOCOL_ERR_BUFFER     // 緩沖區不足
} ProtocolStatus;/* 協議解析函數指針 */
typedef ProtocolStatus (*ParseFunc)(const uint8_t*, uint16_t, void* frame);/* 協議構建函數指針 */
typedef ProtocolStatus (*BuildFunc)(const void* frame, uint8_t*, uint16_t);/* 協議描述符結構 */
typedef struct {ProtocolType type;       // 協議類型ParseFunc parse;         // 解析函數BuildFunc build;         // 構建函數uint16_t min_frame_len;  // 最小幀長度size_t frame_size;       // 幀結構體大小
} ProtocolDescriptor;#endif

3.2.2 協議一設計

/* 協議1定義 */
#define PROTOCOL1_HEADER 0x11
#define PROTOCOL1_MIN_LEN 11  // 最小幀長度/* 協議1幀結構 */
typedef struct {uint16_t src_id;       // 源地址uint16_t dest_id;      // 目的地址uint8_t cmd_set;       // 命令集uint8_t cmd_id;        // 命令IDuint16_t data_len;     // 數據長度uint8_t* data;         // 數據指針
} Protocol1Frame;/* 協議1描述符聲明 */
extern const ProtocolDescriptor protocol1_descriptor;/* 計算校驗和 */
static uint16_t calculate_checksum(const uint8_t* data, uint16_t len) {uint16_t sum = 0;for (uint16_t i = 0; i < len; i++) {sum += data[i];}return sum;
}/* 協議1解析實現 */
static ProtocolStatus parse_protocol1(const uint8_t* data, uint16_t length, void* frame) 
{Protocol1Frame* p1frame = (Protocol1Frame*)frame;/* 檢查最小長度 */if (length < PROTOCOL1_MIN_LEN) {return PROTOCOL_ERR_LENGTH;}/* 檢查幀頭 */if (data[0] != PROTOCOL1_HEADER) {return PROTOCOL_ERR_HEADER;}/* 解析數據長度 */uint16_t data_len = (data[1] << 8) | data[2];/* 檢查完整幀長度 */if (length < (PROTOCOL1_MIN_LEN + data_len)) {return PROTOCOL_ERR_LENGTH;}/* 填充幀結構 */p1frame->src_id = (data[3] << 8) | data[4];p1frame->dest_id = (data[5] << 8) | data[6];p1frame->cmd_set = data[7];p1frame->cmd_id = data[8];p1frame->data_len = data_len;p1frame->data = (uint8_t*)&data[9]; // 指向原始數據/* 校驗和檢查 */uint16_t checksum = (data[9+data_len] << 8) | data[10+data_len];if (checksum != calculate_checksum(&data[1], 8 + data_len)) {return PROTOCOL_ERR_CHECKSUM;}return PROTOCOL_OK;
}/* 協議1構建實現 */
static ProtocolStatus build_protocol1(const void* frame, uint8_t* buffer, uint16_t buffer_size) 
{const Protocol1Frame* p1frame = (const Protocol1Frame*)frame;uint16_t required_len = PROTOCOL1_MIN_LEN + p1frame->data_len;if (buffer_size < required_len) {return PROTOCOL_ERR_BUFFER;}/* 填充固定字段 */buffer[0] = PROTOCOL1_HEADER;buffer[1] = (p1frame->data_len >> 8) & 0xFF;buffer[2] = p1frame->data_len & 0xFF;buffer[3] = (p1frame->src_id >> 8) & 0xFF;buffer[4] = p1frame->src_id & 0xFF;buffer[5] = (p1frame->dest_id >> 8) & 0xFF;buffer[6] = p1frame->dest_id & 0xFF;buffer[7] = p1frame->cmd_set;buffer[8] = p1frame->cmd_id;/* 填充數據 */if (p1frame->data_len > 0) {memcpy(&buffer[9], p1frame->data, p1frame->data_len);}/* 計算校驗和 */uint16_t checksum = calculate_checksum(&buffer[1], 8 + p1frame->data_len);buffer[9+p1frame->data_len] = (checksum >> 8) & 0xFF;buffer[10+p1frame->data_len] = checksum & 0xFF;return PROTOCOL_OK;
}/* 協議1描述符定義 */
const ProtocolDescriptor protocol1_descriptor = {PROTOCOL_TYPE_1,parse_protocol1,build_protocol1,PROTOCOL1_MIN_LEN,sizeof(Protocol1Frame)
};

3.2.3 協議二設計

/* 協議2定義 */
#define PROTOCOL2_HEADER_1 0x22
#define PROTOCOL2_HEADER_2 0x33
#define PROTOCOL2_MIN_LEN 9  // 最小幀長度/* 協議2幀結構 */
typedef struct {uint8_t src_id;        // 源地址uint8_t dest_id;       // 目的地址uint8_t cmd_id;        // 命令IDuint16_t data_len;     // 數據長度uint8_t* data;         // 數據指針
} Protocol2Frame;/* 協議2描述符聲明 */
extern const ProtocolDescriptor protocol2_descriptor;
/* CRC16計算函數 */
static uint16_t calculate_crc16(const uint8_t* data, uint16_t len) {uint16_t crc = 0xFFFF;for (uint16_t i = 0; i < len; i++) {crc ^= data[i];for (uint8_t j = 0; j < 8; j++) {if (crc & 0x0001) {crc = (crc >> 1) ^ 0xA001;} else {crc >>= 1;}}}return crc;
}/* 協議2解析實現 */
static ProtocolStatus parse_protocol2(const uint8_t* data, uint16_t length, void* frame) 
{Protocol2Frame* p2frame = (Protocol2Frame*)frame;/* 檢查最小長度 */if (length < PROTOCOL2_MIN_LEN) {return PROTOCOL_ERR_LENGTH;}/* 檢查幀頭 */if (data[0] != PROTOCOL2_HEADER_1 || data[1] != PROTOCOL2_HEADER_2) {return PROTOCOL_ERR_HEADER;}/* 解析數據長度 */uint16_t data_len = (data[2] << 8) | data[3];/* 檢查完整幀長度 */if (length < (PROTOCOL2_MIN_LEN + data_len)) {return PROTOCOL_ERR_LENGTH;}/* 填充幀結構 */p2frame->src_id = data[4];p2frame->dest_id = data[5];p2frame->cmd_id = data[6];p2frame->data_len = data_len;p2frame->data = (uint8_t*)&data[7]; // 指向原始數據/* CRC校驗檢查 */uint16_t received_crc = (data[7+data_len] << 8) | data[8+data_len];uint16_t calculated_crc = calculate_crc16(&data[2], 5 + data_len);if (received_crc != calculated_crc) {return PROTOCOL_ERR_CHECKSUM;}return PROTOCOL_OK;
}/* 協議2構建實現 */
static ProtocolStatus build_protocol2(const void* frame, uint8_t* buffer, uint16_t buffer_size) 
{const Protocol2Frame* p2frame = (const Protocol2Frame*)frame;uint16_t required_len = PROTOCOL2_MIN_LEN + p2frame->data_len;if (buffer_size < required_len) {return PROTOCOL_ERR_BUFFER;}/* 填充固定字段 */buffer[0] = PROTOCOL2_HEADER_1;buffer[1] = PROTOCOL2_HEADER_2;buffer[2] = (p2frame->data_len >> 8) & 0xFF;buffer[3] = p2frame->data_len & 0xFF;buffer[4] = p2frame->src_id;buffer[5] = p2frame->dest_id;buffer[6] = p2frame->cmd_id;/* 填充數據 */if (p2frame->data_len > 0) {memcpy(&buffer[7], p2frame->data, p2frame->data_len);}/* 計算CRC */uint16_t crc = calculate_crc16(&buffer[2], 5 + p2frame->data_len);buffer[7+p2frame->data_len] = (crc >> 8) & 0xFF;buffer[8+p2frame->data_len] = crc & 0xFF;return PROTOCOL_OK;
}/* 協議2描述符定義 */
const ProtocolDescriptor protocol2_descriptor = {PROTOCOL_TYPE_2,parse_protocol2,build_protocol2,PROTOCOL2_MIN_LEN,sizeof(Protocol2Frame)
};

四、應用層:業務邏輯實現

應用層處理具體的業務邏輯,主要功能包括:命令處理、數據加工、業務決策、狀態管理。

4.1 設計要點

  1. 表驅動編程:使用命令表簡化路由邏輯
  2. 業務隔離:協議處理與業務邏輯分離
  3. 模塊化設計:各命令處理函數獨立
  4. 默認處理:提供未識別命令的默認處理
  5. 可測試性:獨立于協議棧進行單元測試

4.2 代碼示例

4.2.1 協議一處理

/* 命令處理函數類型 */
typedef void (*Protocol1CmdHandler)(const Protocol1Frame* frame);/* 命令集條目 */
typedef struct {uint8_t cmd_set;           // 命令集IDuint8_t cmd_id;            // 命令IDProtocol1CmdHandler handler; // 處理函數
} Protocol1CmdEntry;/**************** 命令處理表 ****************/
static const Protocol1CmdEntry protocol1_cmd_table[] = {// 系統命令集 (0x01){0x01, 0x01, handle_system_cmd_01},{0x01, 0x02, handle_system_cmd_02},// 數據采集命令集 (0x02){0x02, 0x10, handle_acq_cmd_10},{0x02, 0x20, handle_acq_cmd_20},
};/* 默認處理函數 */
static void default_protocol1_handler(const Protocol1Frame* frame) {DEBUG_MSG("Unhandled Protocol1 command: set=0x%02X, cmd=0x%02X", frame->cmd_set, frame->cmd_id);
}/* 協議1數據處理入口 */
void handle_protocol1_data(const Protocol1Frame* frame)
{const Protocol1CmdEntry* entry = NULL;size_t table_size = sizeof(protocol1_cmd_table) / sizeof(Protocol1CmdEntry);/* 查找匹配的命令處理函數 */for (size_t i = 0; i < table_size; i++) {if (protocol1_cmd_table[i].cmd_set == frame->cmd_set && protocol1_cmd_table[i].cmd_id == frame->cmd_id) {entry = &protocol1_cmd_table[i];break;}}/* 調用處理函數 */if (entry) {entry->handler(frame);} else {default_protocol1_handler(frame);}
}/**************** 具體命令處理實現 ****************/
static void handle_system_cmd_01(const Protocol1Frame* frame) {DEBUG_MSG("Processing System Command 01 from 0x%04X", frame->src_id);/* 實際業務處理... */
}static void handle_system_cmd_02(const Protocol1Frame* frame) {DEBUG_MSG("Processing System Command 02 with %d bytes data", frame->data_len);/* 實際業務處理... */
}static void handle_acq_cmd_10(const Protocol1Frame* frame) {DEBUG_MSG("Processing Acquisition Command 10");/* 實際業務處理... */
}static void handle_acq_cmd_20(const Protocol1Frame* frame) {DEBUG_MSG("Processing Acquisition Command 20");/* 實際業務處理... */
}

4.2.2 協議二處理

/* 命令處理函數類型 */
typedef void (*Protocol2CmdHandler)(const Protocol2Frame* frame);/* 命令集條目 */
typedef struct {uint8_t cmd_id;            // 命令IDProtocol2CmdHandler handler; // 處理函數
} Protocol2CmdEntry;/**************** 命令處理表 ****************/
static const Protocol2CmdEntry protocol2_cmd_table[] = {{0x10, handle_status_query},{0x20, handle_parameter_set},{0x30, handle_other_command},
};/* 默認處理函數 */
static void default_protocol2_handler(const Protocol2Frame* frame) {DEBUG_MSG("Unhandled Protocol2 command: 0x%02X", frame->cmd_id);
}/* 協議2數據處理入口 */
void handle_protocol2_data(const Protocol2Frame* frame)
{const Protocol2CmdEntry* entry = NULL;size_t table_size = sizeof(protocol2_cmd_table) / sizeof(Protocol2CmdEntry);/* 查找匹配的命令處理函數 */for (size_t i = 0; i < table_size; i++) {if (protocol2_cmd_table[i].cmd_id == frame->cmd_id) {entry = &protocol2_cmd_table[i];break;}}/* 調用處理函數 */if (entry) {entry->handler(frame);} else {default_protocol2_handler(frame);}
}/**************** 具體命令處理實現 ****************/
static void handle_status_query(const Protocol2Frame* frame) {DEBUG_MSG("Status query from device %d", frame->src_id);/* 構造響應數據并發送... */
}static void handle_parameter_set(const Protocol2Frame* frame) {DEBUG_MSG("Parameter set from device %d", frame->src_id);/* 參數處理邏輯... */
}static void handle_other_command(const Protocol2Frame* frame) {DEBUG_MSG("Processing command 0x%02X", frame->cmd_id);/* 其他命令處理... */
}

五、四層協作流程

5.1 收發流程

接收流程:

  • 硬件抽象層接收原始數據存入環形緩沖區

  • 協議管理層從緩沖區取出數據并識別協議類型

  • 協議處理層解析數據為結構化信息

  • 應用層處理具體業務邏輯

發送流程:

  • 應用層準備業務數據

  • 協議處理層打包為協議幀

  • 協議管理層選擇適當發送接口

  • 硬件抽象層將數據發送至物理介質

在這里插入圖片描述

5.2 代碼示例

/* 系統初始化 */
void system_init(void)
{// 1. 硬件抽象層初始化custom_can_init();// 2. 應用層初始化app_init();
}/* 主任務循環 */
void main_task(void)
{uint8_t raw_data[256];while(1) {// 1. 從硬件層讀取數據uint16_t len = custom_can_read(raw_data, sizeof(raw_data));if(len > 0) {// 2. 協議管理層處理custom_can_run_unpack(raw_data, len);}// 3. 應用層處理app_process();// 4. 休眠或等待事件delay_ms(10);}
}/* 應用層發送示例 */
void send_heartbeat(void)
{uint8_t hb_data[4] = {0x01, 0x02, 0x03, 0x04};// 使用協議1發送心跳ProtocolStatus status = send_protocol1(LOCAL_DEVICE_ID, MASTER_DEVICE_ID,CMD_SET_SYSTEM,CMD_HEARTBEAT,hb_data,sizeof(hb_data));if(status != PROTOCOL_OK) {handle_send_error(status);}
}

總結

這個四層通信協議架構具有以下優勢:

  1. 清晰的層次劃分:各層職責明確,便于維護

  2. 高度可擴展:輕松添加新協議和新命令

  3. 強類型安全:減少運行時錯誤

  4. 高效處理:優化數據流轉路徑

  5. 平臺無關:硬件抽象層隔離硬件差異

實際項目中可根據需求調整各層實現,如增加加密層、優化緩沖區管理等。

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

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

相關文章

RA信號處理

ra_snr_gui.m 作用&#xff1a;統計不同信噪比下&#xff0c;五種信號的峰值旁瓣比RA和低高頻均值比RM&#xff0c;繪制結果&#xff0c;參考圖3.11和3.12 DFCW_RA_SNR.m 作用&#xff1a;產生正交離散頻率編碼信號&#xff0c;并計算峰值旁瓣比RA和低高頻均值比 RM LFM_RA_S…

【go的測試】單測之gomock包與gomonkey包

目錄 使用gomock包 1. 安裝mockgen 2. 定義接口 3. 生成mock文件 4. 在單測中使用mock的函數 5. gomock 包的使用問題 使用gomonkey包 1. mock 一個包函數 2. mock 一個公有成員函數 3. mock 一個私有成員函數 使用gomock包 1. 安裝mockgen go get -u github.com/go…

html實現登錄與注冊功能案例(不寫死且只使用js)

目錄 案例需求 實現思路 代碼參考 login.html register.html 運行效果 升級思路 案例需求 需要一個登錄界面和注冊頁面實現一個較為完整的登錄注冊功能 1.登錄界面沒有登錄限制需求&#xff08;降低難度&#xff09;&#xff0c;實現基本的登錄判斷需求&#xff0c;彈窗…

PHP is the best language.

PHP很好寫。 眾所周知Python很好寫&#xff0c;Python 也能開發 Web 應用&#xff0c;但和 PHP 相比&#xff0c;在“直接處理網頁”這件事上&#xff0c;PHP 更加貼近底層和原生。 想快速搭建原型或者 B 端后臺工具&#xff0c;不妨用 PHP Laravel 來搞&#xff0c;真的很香…

Mybatis-Plus 在 getOne() 的時候要加上 .last(“limit 1“)

1.先寫結論: 1.為了確保 SQL 查詢只返回一條記錄&#xff08;當查詢返回多條時會報錯->多為代碼本身問題&#xff09;。 2.防止數據庫執行全表掃描 3.參考網址&#xff1a;問題記錄&#xff1a;MyBatis-Plus 中 ServiceImpl 類的 getOne_mybatis_無他&唯手熟爾-2048…

C語言:二分搜索函數

一、二分搜索基本概念 二分搜索&#xff08;Binary Search&#xff09;是一種在有序數組中查找特定元素的高效算法&#xff0c;時間復雜度為O(log n)。 基本特點&#xff1a; 僅適用于有序數組&#xff08;升序或降序&#xff09; 每次比較將搜索范圍減半 比線性搜索(O(n))…

[前端AI]LangChain.js 和 Next.js LLM構建——協助博客撰寫和總結助手

LangChain.js 和 Next.js LLM 后端應用于協助博客撰寫和總結領域是一個非常實用的方向&#xff01;這涉及到理解和處理文本內容&#xff0c;并生成新的、有結構的信息。 根據您之前提供的代碼和需求&#xff0c;我們可以在此基礎上進行更具針對性的功能規劃和技術實現。 博客…

用 GitHub Issues 做任務管理和任務 List,簡單好用!

說實話&#xff0c;我平時也是一個人寫代碼&#xff0c;每次開完會整理任務最麻煩&#xff1a; 一堆事項堆在聊天里、文檔里&#xff0c;或者散落在郵件里…… 為了理清這些&#xff0c;我通常會做一份 List&#xff0c;標好優先級&#xff0c;再安排到每日的工作里 雖然這個…

每日算法刷題Day35 6.22:leetcode枚舉技巧枚舉中間2道題,用時1h

枚舉中間 對于三個或者四個變量的問題&#xff0c;枚舉中間的變量往往更好算。 為什么&#xff1f;比如問題有三個下標&#xff0c;需要滿足 0≤i<j<k<n&#xff0c;對比一下&#xff1a; 枚舉 i&#xff0c;后續計算中還需保證 j<k。 枚舉 j&#xff0c;那么 i 和…

【教學類-18-06】20250623蒙德里安黑白七款合并WORD(500張、無學號)

背景需要 客戶買了蒙德里安黑白格子7種尺寸,但是不需要學號方塊,并指定要WORD 設計思路 【教學類-18-05】20241118正方形手工紙(蒙德里安-風格派-紅黃藍黑白)-CSDN博客文章瀏覽閱讀1.3k次,點贊29次,收藏18次。【教學類-18-05】20241118正方形手工紙(蒙德里安-風格派-紅…

langchain--(4)

7 Embedding文本向量化 Embedding文本向量化是一種將非結構化文本轉化為低維、連續數值向量的技術,旨在通過數學方式捕捉文本的語義、語法或特征信息,從而讓機器更高效地處理語言任務。其核心思想源于流形假設(Manifold Hypothesis),即認為高維原始數據(如文本)實際隱含…

DMDRS部署實施手冊(ORACLE=》DM)

DMDRS部署實施手冊&#xff08;ORACLE》DM&#xff09; 1 同步說明2 DMDRS安裝3 數據庫準備3.1 源端準備3.1.1 開啟歸檔日志和附加日志3.1.2 關閉回收站3.1.3 創建同步用戶 3.2 目標準備3.2.1 創建同步用戶 4 DMDRS配置4.1 源端配置4.2 目標配置 5 DMDRS啟動5.1 啟動源端服務5.…

十(1)作業:sqli-labs重點關卡

參考文章&#xff1a;詳細sqli-labs&#xff08;1-65&#xff09;通關講解-CSDN博客 第1關&#xff1a; 輸入 &#xff1a; ?id3 輸入 &#xff1a; ?id2 當輸入的數字不同&#xff0c;頁面的響應也不同&#xff0c;說明&#xff0c;輸入的內容被帶入到數據庫里查詢了 輸…

Python 爬蟲入門 Day 7 - 復盤 + 實戰挑戰日

Python 第二階段 - 爬蟲入門 &#x1f3af; 本周知識回顧 網絡請求與網頁結構基礎 HTML解析入門&#xff08;使用 BeautifulSoup&#xff09; 實現爬蟲多頁抓取與翻頁邏輯 模擬登錄爬蟲與 Session 維持 使用 XPath 進行網頁解析&#xff08;lxml XPath&#xff09; 反爬蟲應對…

WebRTC(七):媒體能力協商

目的 在 WebRTC 中&#xff0c;每個瀏覽器或終端支持的音視頻編解碼器、分辨率、碼率、幀率等可能不同。媒體能力協商的目的就是&#xff1a; 確保雙方能“聽得懂”對方發的媒體流&#xff1b;明確誰發送、誰接收、怎么發送&#xff1b;保障連接的互操作性和兼容性。 P2P的基…

可信啟動方案設計

安全之安全(security)博客目錄導讀 目錄 一、引言 二、關鍵數據(Critical Data) 三、度量槽(Measurement Slot) 四、可信啟動后端 1、事件日志(Event Log) 2、離散型 TPM(Discrete TPM) 3、RSE(運行時安全引擎) 五、平臺接口 平臺接口的職責: 1、函數:b…

?通義萬相2.1深度解析:AI視頻生成引擎FLF2V-14B全流程指南(命令行參數+模型架構+數據流)

&#x1f31f; 從零詳解&#xff1a;如何用AI模型生成視頻&#xff1f;命令行、模型結構、數據流全解析&#xff01; 本文通過一個實際案例&#xff0c;詳細解析使用AI模型生成視頻的整個流程。從命令行參數解讀到模型結構&#xff0c;再到數據在模型間的流動&#xff0c;一步步…

在 TypeScript 前端中使用 Umi-Request 調用 Java 接口的完整指南

下面我將詳細介紹如何在基于 TypeScript 的前端項目中使用 umi-request 調用 IntelliJ IDEA 中開發的 Java 接口&#xff0c;包括完整的實現方案和代碼示例。 整體方案設計 一、Java 后端接口準備 1. 創建 Spring Boot 控制器 // src/main/java/com/example/demo/controller…

GO Gin Web框架面試題及參考答案

目錄 Gin 與 net/http 有哪些主要區別?為什么選擇 Gin? 如何使用 Gin 啟動一個 HTTP 服務并設置默認路由? Gin 的默認路由和自定義路由器組是如何工作的? 如何在 Gin 中綁定請求參數(Query、Form、JSON、XML)? 如何在 Gin 中使用中間件?中間件執行順序是怎樣的? …

asp.net core Razor動態語言編程代替asp.net .aspx更高級嗎?

For Each item In products<tr><td>item.Id</td><td>item.Name</td><td>item.Price.ToString("C")</td></tr>Next為什么要用<tr> ? 在Blazor的Razor語法中&#xff0c;使用<tr>是為了在VB.NET代碼塊中…