uniapp+vue3實現CK通信協議(基于jjc-tcpTools)

1. TCP 服務封裝 (tcpService.js)

export class TcpService {constructor() {this.connections = uni.requireNativePlugin('jjc-tcpTools')this.clients = new Map() // 存儲客戶端連接this.servers = new Map() // 存儲服務端實例}// 創建 TCP 服務端 (字符串模式)createStringServer(port, onCreated, onData, onConnect) {this.connections.createTcpServer(port,(res) => {console.log('Server created:', res)this.servers.set(port, { type: 'string' })onCreated?.(res)},(res) => {console.log('Received data:', res)this._addClient(res.ip, res.port)onData?.(res)},(res) => {console.log('New connection:', res)this._addClient(res.ip, res.port)onConnect?.(res)})}// 創建 TCP 服務端 (字節數組模式)createByteServer(port, onCreated, onData) {this.connections.createByteTcpServer(port,(res) => {console.log('Byte server created:', res)this.servers.set(port, { type: 'byte' })onCreated?.(res)},(res) => {console.log('Received byte data:', res)this._addClient(res.ip, res.port)onData?.(res)})}// 創建 TCP 客戶端 (字符串模式)createStringClient(ip, port, onCreated, onData) {this.connections.createTcpClient(ip,port,(res) => {console.log('Client connected:', res)this.clients.set(`${ip}:${port}`, { type: 'string' })onCreated?.(res)},(res) => {console.log('Client received:', res)onData?.(res)})}// 創建 TCP 客戶端 (字節數組模式)createByteClient(ip, port, onCreated, onData) {this.connections.createByteTcpClient(ip,port,(res) => {console.log('Byte client connected:', res)this.clients.set(`${ip}:${port}`, { type: 'byte' })onCreated?.(res)},(res) => {console.log('Byte client received:', res)onData?.(res)})}// 發送數據 (服務端群發字符串)sendToAllClients(port, message, callback) {this.connections.sendTcpMSG2Client(port,message,(res) => {console.log('Send to all:', res)callback?.(res)})}// 發送數據 (服務端指定客戶端發字符串)sendToClients(port, clients, message, callback) {this.connections.sendTcpMSG2Clients(port,JSON.stringify(clients),message,(res) => {console.log('Send to clients:', res)callback?.(res)})}// 發送數據 (客戶端發字符串)sendToServer(ip, port, message, callback) {this.connections.sendTcpMSG2Server(ip,port,message,(res) => {console.log('Send to server:', res)callback?.(res)})}// 發送字節數據 (服務端群發)sendBytesToAllClients(port, byteArray, callback) {this.connections.sendTcpByteMSG2Client(port,byteArray,(res) => {console.log('Send bytes to all:', res)callback?.(res)})}// 發送字節數據 (服務端指定客戶端發)sendBytesToClients(port, clients, byteArray, callback) {this.connections.sendTcpByteMSG2Clients(port,JSON.stringify(clients),byteArray,(res) => {console.log('Send bytes to clients:', res)callback?.(res)})}// 發送字節數據 (客戶端發)sendBytesToServer(ip, port, byteArray, callback) {this.connections.sendTcpMSGByte2Server(ip,port,byteArray,(res) => {console.log('Send bytes to server:', res)callback?.(res)})}// 設置客戶端重連時間setReconnectTime(ip, port, interval, callback) {this.connections.setReConnectTime(ip,port,interval,(res) => {console.log('Set reconnect time:', res)callback?.(res)})}// 關閉客戶端closeClient(ip, port, callback) {this.connections.closeTcpClient(ip,port,(res) => {console.log('Client closed:', res)this.clients.delete(`${ip}:${port}`)callback?.(res)})}// 關閉服務端closeServer(port, callback) {this.connections.closeTcpServer(port,(res) => {console.log('Server closed:', res)this.servers.delete(port)callback?.(res)})}// 私有方法:添加客戶端記錄_addClient(ip, port) {const key = `${ip}:${port}`if (!this.clients.has(key)) {this.clients.set(key, { ip, port })}}
}// 單例模式導出
export const tcpService = new TcpService()

2. CK協議適配器 (ckProtocol.js)

import { tcpService } from './tcpService'
import { crc16 } from './crc16'// 命令類型枚舉
const CMD_TYPE = {LOCK_CONTROL: 0x01,// ...其他命令類型
}export class CKProtocol {constructor() {this.cabinetNo = 0 // 默認柜號this.serialNo = 0 // 序列號計數器}// 初始化連接init(ip, port = 5460) {this.serverIp = ipthis.serverPort = port// 創建字節數組模式的客戶端連接tcpService.createByteClient(ip,port,(res) => {console.log('Connected to CK device:', res)this.isConnected = res.result === 'success'},(res) => {this.handleDeviceResponse(res)})}// 構建協議幀buildFrame(cmdType, cmdTag, data = null) {const magic = 0x1799 // 上位機→主板通信const dataLength = data ? data.length : 0const buffer = new ArrayBuffer(11 + dataLength)const view = new DataView(buffer)// 填充幀頭view.setUint16(0, magic, false)view.setUint8(2, this.cabinetNo)view.setUint32(3, this.serialNo++, false)view.setUint8(7, cmdType)view.setUint8(8, cmdTag)view.setUint16(9, dataLength, false)// 填充數據區if (data && dataLength > 0) {for (let i = 0; i < dataLength; i++) {view.setUint8(11 + i, data[i])}}// 計算CRC16const crc = crc16(new Uint8Array(buffer.slice(0, 11 + dataLength)))// 創建最終字節數組const fullFrame = new Uint8Array(13 + dataLength)fullFrame.set(new Uint8Array(buffer), 0)fullFrame.set([crc >> 8, crc & 0xFF], 11 + dataLength)return fullFrame}// 發送命令sendCommand(cmdType, cmdTag, data = null) {if (!this.isConnected) {console.error('Not connected to device')return false}const frame = this.buildFrame(cmdType, cmdTag, data)tcpService.sendBytesToServer(this.serverIp,this.serverPort,Array.from(frame),(res) => {console.log('Command sent:', res)})return true}// 處理設備響應handleDeviceResponse(response) {try {// 將響應數據轉換為Uint8Arrayconst data = new Uint8Array(response.msg.split(',').map(Number))// 解析響應幀if (data.length < 12) {throw new Error('Invalid response length')}const view = new DataView(data.buffer)const magic = view.getUint16(0, false)const cabinetNo = view.getUint8(2)const serialNo = view.getUint32(3, false)const cmdType = view.getUint8(7)const cmdTag = view.getUint8(8)const result = view.getUint8(9)const dataLength = view.getUint16(10, false)// 驗證CRCconst receivedCrc = view.getUint16(12 + dataLength, false)const calculatedCrc = crc16(data.slice(0, 12 + dataLength))if (receivedCrc !== calculatedCrc) {throw new Error('CRC check failed')}// 提取數據區let responseData = nullif (dataLength > 0) {responseData = data.slice(12, 12 + dataLength)}// 返回解析結果return {magic,cabinetNo,serialNo,cmdType,cmdTag,result,dataLength,data: responseData}} catch (error) {console.error('Failed to parse device response:', error)return null}}// 鎖控命令controlLock(lockNo, action) {const tagMap = {open: 0x01,close: 0x03,status: 0x02,openAll: 0x06}const tag = tagMap[action]if (tag === undefined) return falseconst data = action === 'openAll' ? null : new Uint8Array([lockNo])return this.sendCommand(CMD_TYPE.LOCK_CONTROL, tag, data)}// 查詢設備信息queryDeviceInfo(infoType) {const tagMap = {mac: 0x01,hardwareVersion: 0x02,softwareVersion: 0x03,firmwareTime: 0x04,uptime: 0x05}const tag = tagMap[infoType]if (tag === undefined) return falsereturn this.sendCommand(CMD_TYPE.QUERY_INFO, tag)}// 其他協議命令...
}// 單例模式導出
export const ckProtocol = new CKProtocol()

3. Vue組件中使用 (DeviceControl.vue)

<template><view class="device-control"><view class="connection-section"><input v-model="serverIp" placeholder="設備IP" /><input v-model="serverPort" placeholder="端口號" type="number" /><button @click="connectDevice" :disabled="isConnected">連接</button><button @click="disconnectDevice" :disabled="!isConnected">斷開</button></view><view class="command-section"><view class="command-group"><text class="group-title">鎖控制</text><button @click="openLock(1)">開鎖1</button><button @click="closeLock(1)">關鎖1</button><button @click="openAllLocks">開所有鎖</button></view><view class="command-group"><text class="group-title">設備查詢</text><button @click="queryMac">查詢MAC</button><button @click="queryVersion">查詢版本</button></view></view><view class="log-section"><text class="section-title">通信日志</text><scroll-view class="log-content" scroll-y><view v-for="(log, index) in logs" :key="index" class="log-item">{{ log }}</view></scroll-view></view></view>
</template><script setup>
import { ref } from 'vue'
import { ckProtocol } from '@/api/ckProtocol'const serverIp = ref('192.168.1.100')
const serverPort = ref('5460')
const isConnected = ref(false)
const logs = ref([])// 連接設備
const connectDevice = () => {addLog(`正在連接 ${serverIp.value}:${serverPort.value}...`)ckProtocol.init(serverIp.value, parseInt(serverPort.value))// 模擬連接成功 (實際應該通過回調事件)setTimeout(() => {isConnected.value = trueaddLog('連接成功')}, 1000)
}// 斷開連接
const disconnectDevice = () => {tcpService.closeClient(serverIp.value, serverPort.value, (res) => {isConnected.value = falseaddLog('已斷開連接')})
}// 鎖控制命令
const openLock = (lockNo) => {addLog(`發送開鎖命令: 鎖${lockNo}`)ckProtocol.controlLock(lockNo, 'open')
}const closeLock = (lockNo) => {addLog(`發送關鎖命令: 鎖${lockNo}`)ckProtocol.controlLock(lockNo, 'close')
}const openAllLocks = () => {addLog('發送開所有鎖命令')ckProtocol.controlLock(null, 'openAll')
}// 查詢命令
const queryMac = () => {addLog('發送查詢MAC地址命令')ckProtocol.queryDeviceInfo('mac')
}const queryVersion = () => {addLog('發送查詢版本命令')ckProtocol.queryDeviceInfo('softwareVersion')
}// 添加日志
const addLog = (message) => {const timestamp = new Date().toLocaleTimeString()logs.value.unshift(`[${timestamp}] ${message}`)if (logs.value.length > 100) {logs.value.pop()}
}
</script><style>
.device-control {padding: 20px;
}.connection-section {display: flex;flex-wrap: wrap;gap: 10px;margin-bottom: 20px;
}.connection-section input {flex: 1;min-width: 120px;padding: 8px;border: 1px solid #ddd;border-radius: 4px;
}.connection-section button {min-width: 80px;
}.command-section {margin-bottom: 20px;
}.command-group {margin-bottom: 15px;padding: 10px;background-color: #f5f5f5;border-radius: 8px;
}.group-title {display: block;font-weight: bold;margin-bottom: 8px;
}.command-group button {margin-right: 10px;margin-bottom: 8px;
}.log-section {margin-top: 20px;
}.section-title {font-weight: bold;margin-bottom: 8px;
}.log-content {height: 200px;padding: 10px;background-color: #f0f0f0;border-radius: 4px;font-family: monospace;font-size: 12px;
}.log-item {margin-bottom: 4px;padding-bottom: 4px;border-bottom: 1px solid #e0e0e0;
}
</style>

4. CRC16工具 (crc16.js)

// CRC-16/XMODEM (x16 + x12 + x5 + 1)
export function crc16(data) {let crc = 0x0000for (let i = 0; i < data.length; i++) {crc ^= data[i] << 8for (let j = 0; j < 8; j++) {if (crc & 0x8000) {crc = (crc << 1) ^ 0x1021} else {crc <<= 1}}}return crc & 0xFFFF
}

關鍵點說明

  1. 完全適配 jjc-tcpTools 插件

    • 嚴格按照插件提供的 API 進行封裝
    • 支持字符串和字節數組兩種通信模式
    • 實現了服務端和客戶端的所有基本操作
  2. CK 協議實現

    • 按照文檔規范構建協議幀
    • 實現了 CRC16 校驗
    • 封裝了常用命令如鎖控制、設備查詢等
  3. 組件集成

    • 提供直觀的設備控制界面
    • 顯示通信日志
    • 管理連接狀態
  4. 錯誤處理

    • 基本的錯誤檢測和日志記錄
    • CRC 校驗確保數據完整性
  5. 擴展性

    • 可以輕松添加更多協議命令
    • 支持多設備管理

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

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

相關文章

學習設計模式《十二》——命令模式

一、基礎概念 命令模式的本質是【封裝請求】命令模式的關鍵是把請求封裝成為命令對象&#xff0c;然后就可以對這個命令對象進行一系列的處理&#xff08;如&#xff1a;參數化配置、可撤銷操作、宏命令、隊列請求、日志請求等&#xff09;。 命令模式的定義&#xff1a;將一個…

Webpack的基本使用 - babel

Mode配置 Mode配置選項可以告知Webpack使用相應模式的內置優化 默認值是production&#xff08;什么都不設置的情況下&#xff09; 可選值有&#xff1a;none | development | production; 這幾個選項有什么區別呢&#xff1f; 認識source-map 我們的代碼通常運行在瀏覽器…

「基于連續小波變換(CWT)和卷積神經網絡(CNN)的心律失常分類算法——ECG信號處理-第十五課」2025年6月6日

一、引言 心律失常是心血管疾病的重要表現形式&#xff0c;其準確分類對臨床診斷具有關鍵意義。傳統的心律失常分類方法主要依賴于人工特征提取和經典機器學習算法&#xff0c;但這些方法往往受限于特征選擇的主觀性和模型的泛化能力。 隨著深度學習技術的發展&#xff0c;基于…

C++.OpenGL (11/64)材質(Materials)

材質(Materials) 真實感材質系統 #mermaid-svg-NjBjrmlcpHupHCFQ {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-NjBjrmlcpHupHCFQ .error-icon{fill:#552222;}#mermaid-svg-NjBjrmlcpHupHCFQ .error-text{fill:…

P1345 [USACO5.4] 奶牛的電信Telecowmunication

P1345 [USACO5.4] 奶牛的電信Telecowmunication 突然發現 USACO 好喜歡玩諧音梗。 題意就是給定一個無向圖&#xff0c;問你要刪多少點才能使 s , t s,t s,t 不連通。 注意是刪點而不是刪邊&#xff0c;所以不能直接使用最小割來求。所以考慮變換一下題目模型。 經典 tric…

EXCEL如何快速批量給兩字姓名中間加空格

EXCEL如何快速批量給姓名中間加空格 優點&#xff1a;不會導致排版混亂 缺點&#xff1a;無法輸出在原有單元格上&#xff0c;若需要保留原始數據&#xff0c;可將公式結果復制后“選擇性粘貼為值” 使用場景&#xff1a;在EXCEL中想要快速批量給兩字姓名中間加入空格使姓名對…

使用vtk8.2.0加載dicom圖像

1 上一篇文章我們已經編譯好了VTK的dll&#xff0c;下面我們就來加載他。 2 在Pro里面加載dll #------------------------------------------------- # # Project created by QtCreator 2024-02-04T14:39:07 # #-------------------------------------------------QT …

使用vsftpd搭建FTP服務器(TLS/SSL顯式加密)

安裝vsftpd服務 使用vsftpd RPM安裝包安裝即可&#xff0c;如果可以訪問YUM鏡像源&#xff0c;通過dnf或者yum工具更加方便。 yum -y install vsftpd 啟動vsftpd、查看服務狀態 systemctl enable vsftpd systemctl start vsftpd systemctl status vsftpd 備份配置文件并進…

鴻蒙OSUniApp集成WebGL:打造跨平臺3D視覺盛宴#三方框架 #Uniapp

UniApp集成WebGL&#xff1a;打造跨平臺3D視覺盛宴 在移動應用開發日新月異的今天&#xff0c;3D視覺效果已經成為提升用戶體驗的重要手段。本文將深入探討如何在UniApp中集成WebGL技術&#xff0c;實現炫酷的3D特效&#xff0c;并特別關注鴻蒙系統(HarmonyOS)的適配與優化。 …

前端文件下載常用方式詳解

在前端開發中&#xff0c;實現文件下載是常見的需求。根據不同的場景&#xff0c;我們可以選擇不同的方法來實現文件流的下載。本文介紹三種常用的文件下載方式&#xff1a; 使用 axios 發送 JSON 請求下載文件流使用 axios 發送 FormData 請求下載文件流使用原生 form 表單提…

MacOS解決局域網“沒有到達主機的路由 no route to host“

可能原因&#xff1a;MacOS 15新增了"本地網絡"訪問權限&#xff0c;在 APP 第一次嘗試訪問本地網絡的時候會請求權限&#xff0c;可能順手選擇了關閉。 解決辦法&#xff1a;給想要訪問本地網絡的 APP &#xff08;例如 terminal、Navicat、Ftp&#xff09;添加訪問…

中英文實習證明模板:一鍵生成標準化實習證明,助力實習生職場發展

中英文實習證明模板&#xff1a;一鍵生成標準化實習證明&#xff0c;助力實習生職場發展 【下載地址】中英文實習證明模板 這份中英文實習證明模板專為實習生設計&#xff0c;內容簡潔專業&#xff0c;適用于多種場景。模板采用中英文對照格式&#xff0c;方便國際交流與使用。…

RocketMQ運行架構和消息模型

運?架構 nameServer 命名服務 NameServer 是 RocketMQ 的 輕量級注冊中心&#xff0c;負責管理集群的路由信息&#xff08;Broker 地址、Topic 隊列分布等&#xff09;&#xff0c;其核心作用是解耦 Broker 與客戶端&#xff0c;實現動態服務發現。broker 核?服務 RocketMQ最…

C++學習-入門到精通【11】輸入/輸出流的深入剖析

C學習-入門到精通【11】輸入/輸出流的深入剖析 目錄 C學習-入門到精通【11】輸入/輸出流的深入剖析一、流1.傳統流和標準流2.iostream庫的頭文件3.輸入/輸出流的類的對象 二、輸出流1.char* 變量的輸出2.使用成員函數put進行字符輸出 三、輸入流1.get和getline成員函數2.istrea…

OpenCV 圖像像素的邏輯操作

一、知識點 1、圖像像素的邏輯操作&#xff0c;指的是位操作bitwise&#xff0c;與、或、非、異或等。 2、位操作簡介: 位1 位2 與and 或or 異或xor0 0 0 0 00 1 0 1 11 0 0 …

【AAOS】【源碼分析】用戶管理(二)-- 整體架構

整體介紹 Android多用戶功能作為 Android Automotive 的重要組成部分,為不同駕駛員和乘客提供了一個更加定制化、隱私保護的使用環境。Android 多用戶的存在,它可以讓多個用戶使用同一臺設備,同時保持彼此的數據、應用和設置分隔開來。 各用戶類型的權限 能力SystemAdminS…

Redis最佳實踐——電商應用的性能監控與告警體系設計詳解

Redis 在電商應用的性能監控與告警體系設計 一、原子級監控指標深度拆解 1. 內存維度監控 核心指標&#xff1a; # 實時內存組成分析&#xff08;單位字節&#xff09; used_memory: 物理內存總量 used_memory_dataset: 數據集占用量 used_memory_overhead: 管理開銷內存 us…

多模態大語言模型arxiv論文略讀(109)

Math-PUMA: Progressive Upward Multimodal Alignment to Enhance Mathematical Reasoning ?? 論文標題&#xff1a;Math-PUMA: Progressive Upward Multimodal Alignment to Enhance Mathematical Reasoning ?? 論文作者&#xff1a;Wenwen Zhuang, Xin Huang, Xiantao Z…

web3-以太坊智能合約基礎(理解智能合約Solidity)

以太坊智能合約基礎&#xff08;理解智能合約/Solidity&#xff09; 無需編程經驗&#xff0c;也可以幫助你了解Solidity獨特的部分&#xff1b;如果本身就有相應的編程經驗如java&#xff0c;python等那么學起來也會非常的輕松 一、Solidity和EVM字節碼 實際上以太坊鏈上儲存…

D2-基于本地Ollama模型的多輪問答系統

本程序是一個基于 Gradio 和 Ollama API 構建的支持多輪對話的寫作助手。相較于上一版本&#xff0c;本版本新增了對話歷史記錄、Token 計數、參數調節和清空對話功能&#xff0c;顯著提升了用戶體驗和交互靈活性。 程序通過抽象基類 LLMAgent 實現模塊化設計&#xff0c;當前…