fast(串口调试): 增加串口连接功能、设备参数获取写入、断路器标定功能、解决相关bug、打包1.0.6

This commit is contained in:
fhysy 2024-10-31 14:02:42 +08:00
parent d12381feb3
commit 1c024beeb8
18 changed files with 2388 additions and 17 deletions

View File

@ -1,6 +1,6 @@
{
"name": "gateway-app",
"version": "1.0.3",
"version": "1.0.6",
"description": "An Electron application with Vue",
"main": "./out/main/index.js",
"author": "example.com",

View File

@ -0,0 +1 @@
[{"name":"属性1","addr":"60000","len":"2","data":"15"},{"name":"属性2","addr":"50000","len":"1","data":"1"}]

View File

@ -1,5 +1,5 @@
server:
address: ":8000"
address: ":8888"
openapiPath: "/api.json"
swaggerPath: "/swagger"

View File

@ -0,0 +1,28 @@
server:
address: ":8888"
staticRoot: "./resource/template"
apiPrefix: "/api/v1"
pluginPrefix: "/plugins"
file:
upload_path: "./resource/upload"
dir_mode: "byDate"
logger:
level: debug
path: "./resource/logs/server.log"
max_size: 10
max_age: 30
database:
default:
kind: "mysql"
dsn: "root:mysql_YiniNx@tcp(123.60.30.87:3306)/goside?charset=utf8mb4&parseTime=True&loc=Local"
max_idle_conns: 10
max_open_conns: 100
# kind: "SQLite"
# dsn: "./resource/db/db.db"
# max_idle_conns: 10

Binary file not shown.

View File

@ -2,6 +2,7 @@ import { app, shell, BrowserWindow, ipcMain, globalShortcut, dialog } from 'elec
import { join } from 'path';
import { electronApp, optimizer, is } from '@electron-toolkit/utils';
import icon from '../../resources/icon.png?asset';
// const fs = require('fs');
//关闭exe命令
function killProcessByName(processName) {
@ -164,6 +165,44 @@ if (!gotTheLock) {
});
});
// 处理来自渲染进程的请求
// ipcMain.handle('readFile', async (event, path) => {
// return new Promise((resolve, reject) => {
// fs.readFile(join(__dirname, path), 'utf8', (err, data) => {
// if (err) {
// reject(err);
// } else {
// resolve(data);
// }
// });
// });
// });
//
// ipcMain.handle('writeFile', async (event, path, content) => {
// return new Promise((resolve, reject) => {
// fs.writeFile(join(__dirname, path), content, 'utf8', (err) => {
// if (err) {
// reject(err);
// } else {
// resolve();
// }
// });
// });
// });
//
// // 处理来自渲染进程的请求
// ipcMain.handle('readDirectory', async (event, directoryPath) => {
// return new Promise((resolve, reject) => {
// fs.readdir(join(__dirname, directoryPath), (err, files) => {
// if (err) {
// reject(err);
// } else {
// resolve(files);
// }
// });
// });
// });
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.

View File

@ -1,9 +1,21 @@
import { contextBridge } from 'electron'
import { contextBridge, ipcRenderer } from 'electron'
import { electronAPI } from '@electron-toolkit/preload'
// Custom APIs for renderer
// 自定义的主进程方法API
const api = {}
// const api = {
// readFile: async (path) => {
// const result = await ipcRenderer.invoke('readFile', path);
// return result;
// },
// writeFile: async (path, content) => {
// await ipcRenderer.invoke('writeFile', path, content);
// },
// readDirectory: async (directoryPath) => {
// const result = await ipcRenderer.invoke('readDirectory', directoryPath);
// return result;
// }
// }
// Use `contextBridge` APIs to expose Electron APIs to
// renderer only if context isolation is enabled, otherwise
@ -12,11 +24,11 @@ const api = {}
if (process.contextIsolated) {
try {
contextBridge.exposeInMainWorld('electron', electronAPI)
contextBridge.exposeInMainWorld('api', api)
// contextBridge.exposeInMainWorld('api', api)
} catch (error) {
console.error(error)
}
} else {
window.electron = electronAPI
window.api = api
// window.api = api
}

View File

@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 4622943 */
src: url('iconfont.woff2?t=1721353754291') format('woff2'),
url('iconfont.woff?t=1721353754291') format('woff'),
url('iconfont.ttf?t=1721353754291') format('truetype');
src: url('iconfont.woff2?t=1729646274723') format('woff2'),
url('iconfont.woff?t=1729646274723') format('woff'),
url('iconfont.ttf?t=1729646274723') format('truetype');
}
.iconfont {
@ -13,6 +13,26 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-com001:before {
content: "\e62c";
}
.icon-chuankou:before {
content: "\e6be";
}
.icon-chuankou1:before {
content: "\e60a";
}
.icon-chuankoushezhi:before {
content: "\e600";
}
.icon-chuankou2:before {
content: "\e6fc";
}
.icon-shousuoshangjiantou:before {
content: "\e9b6";
}

View File

@ -10,7 +10,9 @@ const settings = defineProps({
<el-scrollbar>
<el-menu default-active="/system/switch" :collapse="settings.collapse" :router="true">
<el-menu-item index="/system/switch"> <span class="iconfont icon-icon_duanluqi"></span> 断路器调试</el-menu-item>
<el-menu-item index="/system/videoplayer"><span class="iconfont icon-icon_jiankong"></span> 视频监控</el-menu-item>
<el-menu-item index="/system/videoplayer"><span class="iconfont icon-icon_jiankong"></span> 视频监控</el-menu-item>
<el-menu-item index="/system/serialport"><span class="iconfont icon-chuankou2"></span> 设备参数读写</el-menu-item>
<el-menu-item index="/system/devicestandard"><span class="iconfont icon-icon_chajian"></span> 空开标定</el-menu-item>
<!-- <el-menu-item index="/system/test"><el-icon> <Menu /> </el-icon></el-menu-item>-->
</el-menu>
</el-scrollbar>
@ -36,7 +38,7 @@ const settings = defineProps({
color: #333;
font-size: 16px;
.iconfont {
margin-right: 10px;
margin-right: 6px;
color: #999;
font-size: 22px;
}

View File

@ -26,12 +26,30 @@ const router = createRouter({
keepAlive: true
}
},
{
path: 'videoplayer',
name: 'videoplayer',
component: () => import('@renderer/views/system/videoplayer/index.vue'),
meta: {
menu: 'videoplayer',
keepAlive: true
}
},
{
path: 'serialport',
name: 'serialport',
component: () => import('@renderer/views/system/serialport/index.vue'),
meta: {
menu: 'serialport',
keepAlive: true
}
},
{
path: 'videoplayer',
name: 'videoplayer',
component: () => import('@renderer/views/system/videoplayer/index.vue'),
path: 'devicestandard',
name: 'devicestandard',
component: () => import('@renderer/views/system/serialport/devicestandard.vue'),
meta: {
menu: 'videoplayer',
menu: 'devicestandard',
keepAlive: true
}
},

View File

@ -0,0 +1,18 @@
import { defineStore } from 'pinia';
export const useSerialPortStore = defineStore('seralPort', {
state: () => ({
serialport: {
port: '',
baudrate: 115200,
databits: 8,
parity: 0,
stopbits: 0
}
}),
actions: {
setSerialport(data) {
this.serialport = data;
}
}
});

View File

@ -17,9 +17,14 @@
// }
export default {
url: 'http://127.0.0.1:8000',
wsUrl: 'ws://127.0.0.1:8000',
url: 'http://127.0.0.1:8888',
wsUrl: 'ws://127.0.0.1:8888',
swichWsUrl: 'ws://127.0.0.1:8001',
serialPortUrl: 'http://127.0.0.1:8888',
// 远程连接串口使用
// serialPortUrl: 'http://120.77.172.42:7202',
// serialPortUrl: 'http://192.168.1.17:8888',
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,760 @@
<template>
<div id="serialport-box">
<div id="serialport-main" class="serialport-main">
<el-collapse v-model="activeFold" @change="foldChange">
<el-collapse-item name="1" title="串口设置">
<el-form ref="serialportFormRef" :model="serialportForm" :rules="serialportRules" class="demo-serialportForm" label-width="auto" status-icon>
<el-form-item label="端口" prop="port" required >
<el-select v-model="serialportForm.port" :disabled="connectionState" placeholder="选择端口" style="flex: 1">
<el-option v-for="(item, index) in serialportList" :key="index" :label="item" :value="item" />
</el-select>
<el-button style="margin-left: 10px" type="primary" @click="getSerialPortList">获取端口列表</el-button>
</el-form-item>
<el-form-item label="波特率" prop="baudrate" required>
<el-select v-model="serialportForm.baudrate" :disabled="connectionState" placeholder="选择波特率">
<el-option label="4800" :value="4800" />
<el-option label="9600" :value="9600" />
<el-option label="19200" :value="19200" />
<el-option label="43000" :value="43000" />
<el-option label="56000" :value="56000" />
<el-option label="115200" :value="115200" />
</el-select>
</el-form-item>
<el-form-item label="数据位" prop="databits" required>
<el-select v-model="serialportForm.databits" :disabled="connectionState" placeholder="选择数据位">
<el-option label="5" :value="5" />
<el-option label="6" :value="6" />
<el-option label="7" :value="7" />
<el-option label="8" :value="8" />
</el-select>
</el-form-item>
<el-form-item label="校验位" prop="parity" required>
<el-select v-model="serialportForm.parity" :disabled="connectionState" placeholder="选择校验位">
<el-option label="None" :value="0" />
<el-option label="Odd" :value="1" />
<el-option label="Even" :value="2" />
<el-option label="Mark" :value="3" />
<el-option label="Space" :value="4" />
</el-select>
</el-form-item>
<el-form-item label="停止位" prop="stopbits" required>
<el-select v-model="serialportForm.stopbits" :disabled="connectionState" placeholder="选择停止位">
<el-option label="1" :value="0" />
<el-option label="1.5" :value="1" />
<el-option label="2" :value="2" />
</el-select>
</el-form-item>
<el-form-item class="btn-box">
<el-button type="danger" @click="disconnSerialPort">关闭 </el-button>
<el-button type="primary" @click="connectSerialPort(serialportFormRef)">{{ connectionState ? '已打开' : '打开' }}</el-button>
</el-form-item>
</el-form>
</el-collapse-item>
<!-- <el-collapse-item name="2" title="通用调试">-->
<!-- <el-form ref="commonDebuggerFormRef" :model="commonDebuggerForm" :rules="commonDebuggerRules" class="demo-serialportForm" label-width="auto" status-icon>-->
<!-- <el-form-item label="数据类型" prop="dataType">-->
<!-- <el-input-->
<!-- </el-form-item>-->
<!-- <el-form-item label="端口" prop="port" required >-->
<!-- <el-select v-model="commonDebuggerForm.port" :disabled="connectionState" placeholder="选择端口" style="flex: 1">-->
<!-- <el-option v-for="(item, index) in serialportList" :key="index" :label="item" :value="item" />-->
<!-- </el-select>-->
<!-- <el-button style="margin-left: 10px" type="primary" @click="getSerialPortList">获取端口列表</el-button>-->
<!-- </el-form-item>-->
<!-- <el-form-item label="波特率" prop="baudrate" required>-->
<!-- <el-select v-model="commonDebuggerForm.baudrate" :disabled="connectionState" placeholder="选择波特率">-->
<!-- <el-option label="4800" :value="4800" />-->
<!-- <el-option label="9600" :value="9600" />-->
<!-- <el-option label="19200" :value="19200" />-->
<!-- <el-option label="43000" :value="43000" />-->
<!-- <el-option label="56000" :value="56000" />-->
<!-- <el-option label="115200" :value="115200" />-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<!-- <el-form-item label="数据位" prop="databits" required>-->
<!-- <el-select v-model="commonDebuggerForm.databits" :disabled="connectionState" placeholder="选择数据位">-->
<!-- <el-option label="5" :value="5" />-->
<!-- <el-option label="6" :value="6" />-->
<!-- <el-option label="7" :value="7" />-->
<!-- <el-option label="8" :value="8" />-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<!-- <el-form-item label="校验位" prop="parity" required>-->
<!-- <el-select v-model="commonDebuggerForm.parity" :disabled="connectionState" placeholder="选择校验位">-->
<!-- <el-option label="None" :value="0" />-->
<!-- <el-option label="Odd" :value="1" />-->
<!-- <el-option label="Even" :value="2" />-->
<!-- <el-option label="Mark" :value="3" />-->
<!-- <el-option label="Space" :value="4" />-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<!-- <el-form-item label="停止位" prop="stopbits" required>-->
<!-- <el-select v-model="commonDebuggerForm.stopbits" :disabled="connectionState" placeholder="选择停止位">-->
<!-- <el-option label="1" :value="0" />-->
<!-- <el-option label="1.5" :value="1" />-->
<!-- <el-option label="2" :value="2" />-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<!-- <el-form-item class="btn-box">-->
<!-- <el-button type="danger" @click="disconnSerialPort">关闭 </el-button>-->
<!-- <el-button type="primary" @click="connectSerialPort(serialportFormRef)">{{ connectionState ? '已打开' : '打开' }}</el-button>-->
<!-- </el-form-item>-->
<!-- </el-form>-->
<!-- </el-collapse-item>-->
<el-collapse-item name="3" title="设备基础参数">
<div class="device-attr-list">
<div v-for="(item, index) in deviceAttrList" :key="item.id" class="device-attr-item">
<div class="device-attr-item-name">{{ item.name }}</div>
<div class="device-attr-item-value">
<el-input v-model="item.outputValue" class="device-attr-input" disabled />
<el-button type="primary" :loading="item.outputLoadingStatus" @click="sendDeviceAttr(item, 'output', index)">读取</el-button>
</div>
<div class="device-attr-item-value">
<el-input v-model="item.inputValue" :disabled="item.inputDisable" class="device-attr-input" />
<el-button type="primary" :disabled="item.inputDisable" :loading="item.inputLoadingStatus" @click="sendDeviceAttr(item, 'input', index)">写入</el-button>
</div>
</div>
<div class="btn-box">
<el-button type="primary" @click="allReadDeviceAttr">一键读取</el-button>
<el-button type="primary" @click="allWriteDeviceAttr">一键写入</el-button>
</div>
</div>
</el-collapse-item>
</el-collapse>
</div>
</div>
</template>
<script setup>
import axios from 'axios'; // axios
import config from '@renderer/util/config.js';
import { reactive, ref, onMounted, onUnmounted,watch } from 'vue';
import { ElMessage } from 'element-plus';
import { buildHead, hexToString, hexToVersion, rearrangeHexStr, versionToHex } from "./js/fun"
import { useSerialPortStore } from '@renderer/stores/seralPort.js';
const useseralPortStore = useSerialPortStore();
const activeFold = ref(['1', '2', '3']);
//
const connectionState = ref(false);
const serialportFormRef = ref();
const serialportList = ref([]);
const serialportForm = reactive({
port: '',
baudrate: 115200,
databits: 8,
parity: 0,
stopbits: 0
});
// serialportForm
watch(() => ({ ...serialportForm }), (newVal) => {
// localStorage
newVal.port = newVal.port.toLowerCase();
useseralPortStore.setSerialport(newVal);
// localStorage.setItem('serialportForm', newVal);
}, { deep: true });
const serialportRules = reactive({
port: [{ required: true, message: '请选择端口', trigger: 'change' }],
baudrate: [{ required: true, message: '请选择波特率', trigger: 'change' }],
databits: [{ required: true, message: '请选择port', trigger: 'change' }],
parity: [{ required: true, message: '请选择userName', trigger: 'change' }],
stopbits: [{ required: true, message: '请选择passWord', trigger: 'change' }]
});
//
const getSerialPortList = (msgShow = true) => {
axios
.get(config.serialPortUrl + '/serial/list', {})
.then(response => {
//
if (response.data.code === 0) {
serialportList.value = response.data.data.List || [];
if(msgShow){
ElMessage.success('获取端口列表成功');
}
} else {
ElMessage.error(response.data.message);
}
})
.catch(error => {
//
ElMessage.error(error);
});
};
//
const connectSerialPort = formEl => {
if (!formEl) return;
formEl.validate(valid => {
if (valid) {
serialportForm.port = serialportForm.port.toLowerCase();
axios
.post(config.serialPortUrl + '/serial/open', serialportForm)
.then(response => {
//
console.log(response); //
if (response.data.code === 0) {
ElMessage.success('打开成功');
connectionState.value = true;
} else {
if (response.data.code === 60) {
connectionState.value = false;
}
ElMessage.error(response.data.message);
}
})
.catch(error => {
//
if (error.response.data.message) {
ElMessage.error(error.response.data.message);
} else {
ElMessage.error(error);
}
});
}
});
};
//
const disconnSerialPort = () => {
serialportForm.port = serialportForm.port.toLowerCase();
axios
.get(config.serialPortUrl + '/serial/close', {
params: {
port: serialportForm.port
}
})
.then(response => {
//
if (response.data.code === 0) {
connectionState.value = false;
ElMessage.success('关闭成功');
} else {
ElMessage.error(response.data.message);
}
})
.catch(error => {
//
ElMessage.error(error);
});
};
const deviceAttrCommonList = ref({
input: {
//
datalentype: '00',
//ID
remote_id: '0',
//ID
local_id: '0',
//
cmd: '0100',
//
devtype: '00',
//
datatype: '00'
},
output: {
//
datalentype: '00',
//ID
remote_id: '0',
//ID
local_id: '0',
//
cmd: '0011',
//
devtype: '00',
//
datatype: '00'
}
});
const deviceAttrList = ref([
{
id: 1,
name: '芯片ID',
startValue: 0,
lengthValue: 4,
inputValue: '',
inputLoadingStatus: false,
outputValue: '',
outputLoadingStatus: false,
dataType: 'hex',
inputDisable: false
},
{
id: 2,
name: '设备序列号SN',
startValue: 4,
lengthValue: 8,
inputValue: '',
inputLoadingStatus: false,
outputValue: '',
outputLoadingStatus: false,
dataType: 'str',
inputDisable: false
},
{
id: 3,
name: '产品主型号',
startValue: 12,
lengthValue: 3,
inputValue: '',
inputLoadingStatus: false,
outputValue: '',
outputLoadingStatus: false,
dataType: 'str',
inputDisable: false
},
{
id: 4,
name: '产品次型号',
startValue: 15,
lengthValue: 5,
inputValue: '',
inputLoadingStatus: false,
outputValue: '',
outputLoadingStatus: false,
dataType: 'str',
inputDisable: false
},
{
id: 5,
name: '产品密钥',
startValue: 20,
lengthValue: 8,
inputValue: '',
inputLoadingStatus: false,
outputValue: '',
outputLoadingStatus: false,
dataType: 'str',
inputDisable: false
},
{
id: 6,
name: '主板序列号',
startValue: 28,
lengthValue: 8,
inputValue: '',
inputLoadingStatus: false,
outputValue: '',
outputLoadingStatus: false,
dataType: 'str',
inputDisable: false
},
{
id: 7,
name: '69序列号',
startValue: 36,
lengthValue: 8,
inputValue: '',
inputLoadingStatus: false,
outputValue: '',
outputLoadingStatus: false,
dataType: 'str',
inputDisable: false
},
{
id: 8,
name: '通信版本号',
startValue: 44,
lengthValue: 1,
inputValue: '',
inputLoadingStatus: false,
outputValue: '',
outputLoadingStatus: false,
dataType: 'firmware',
inputDisable: true
},
{
id: 9,
name: '软件固件号',
startValue: 45,
lengthValue: 1,
inputValue: '',
inputLoadingStatus: false,
outputValue: '',
outputLoadingStatus: false,
dataType: 'firmware',
inputDisable: true
}
]);
//
const analysisData = (hexData, data) => {
if (hexData.length < 28) {
console.log('返回hex小于28个字符串', hexData);
return '';
} else {
// let head = hexData.substring(0,8);
// let startAddr = hexData.substring(8,16);
// let len = hexData.substring(16,24);
let hexValue = hexData.substring(24, data.lengthValue * 4 * 2 + 24);
// let crc = hexData.substring(hexData.length - 4);
if (data.dataType === 'str') {
let str = hexToString(hexValue).trim();
return str;
}
else if(data.dataType === 'hex'){
let str = rearrangeHexStr(hexValue);
return str;
}
// else if(data.dataType === 'firmware'){
// let str = hexToVersion(hexValue);
// return str;
// }
else {
return hexValue;
}
}
};
const sendDeviceAttr = (data, type, index) => {
if (!serialportForm.port) {
ElMessage.error('请先打开串口');
return '';
}
console.log('readDeviceAttr', data);
let head = buildHead(
deviceAttrCommonList.value[type].datalentype,
deviceAttrCommonList.value[type].remote_id,
deviceAttrCommonList.value[type].local_id,
deviceAttrCommonList.value[type].cmd,
deviceAttrCommonList.value[type].devtype,
deviceAttrCommonList.value[type].datatype,
data.startValue,
data.lengthValue,
data.inputValue,
data
);
if (type === 'input') {
deviceAttrList.value[index].inputLoadingStatus = true;
// head = head + 'd240';
} else {
deviceAttrList.value[index].outputLoadingStatus = true;
}
axios
.post(
config.serialPortUrl + '/serial/response',
{
port: serialportForm.port,
data: head,
hex: 1,
crc: 1,
flush:1
},
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
)
.then(response => {
//
console.log('串口请求', response); //
if (response.data.code === 0) {
ElMessage.success('操作成功');
if (type === 'output') {
deviceAttrList.value[index].outputValue = analysisData(response.data.data.hex || '', data);
}
} else {
ElMessage.error(response.data.message);
}
if (type === 'input') {
deviceAttrList.value[index].inputLoadingStatus = false;
} else {
deviceAttrList.value[index].outputLoadingStatus = false;
}
})
.catch(error => {
console.log('error', error);
if (type === 'input') {
deviceAttrList.value[index].inputLoadingStatus = false;
} else {
deviceAttrList.value[index].outputLoadingStatus = false;
}
//
if (error.response.data.message) {
ElMessage.error(error.response.data.message);
} else {
ElMessage.error(error);
}
});
};
const allReadDeviceAttr = () => {
if (!serialportForm.port) {
ElMessage.error('请先打开串口');
return '';
}
let head = buildHead(
deviceAttrCommonList.value['output'].datalentype,
deviceAttrCommonList.value['output'].remote_id,
deviceAttrCommonList.value['output'].local_id,
deviceAttrCommonList.value['output'].cmd,
deviceAttrCommonList.value['output'].devtype,
deviceAttrCommonList.value['output'].datatype,
0,
46,
''
);
axios
.post(
config.serialPortUrl + '/serial/response',
{
port: serialportForm.port,
data: head,
hex: 1,
crc: 1,
flush:1
},
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
)
.then(response => {
//
console.log('串口请求', response); //
if (response.data.code === 0) {
ElMessage.success('操作成功');
let hexValue = response.data.data.hex.substring(24, 392);
let startValue = 0;
deviceAttrList.value.forEach((item, index) => {
if(startValue === 0){
startValue = item.startValue;
}
let value = hexValue.substring(startValue, item.lengthValue * 4 * 2 + startValue);
startValue = startValue + item.lengthValue * 4 * 2;
console.log("value",value)
if (item.dataType === 'str') {
deviceAttrList.value[index].outputValue = hexToString(value).trim();
deviceAttrList.value[index].inputValue = hexToString(value).trim();
}else if (item.dataType === 'hex') {
deviceAttrList.value[index].outputValue = rearrangeHexStr(value);
deviceAttrList.value[index].inputValue = rearrangeHexStr(value);
}else{
deviceAttrList.value[index].outputValue = value;
deviceAttrList.value[index].inputValue = value;
}
})
// deviceAttrList.value[index].outputValue = analysisData(response.data.data.hex || '', data);
} else {
ElMessage.error(response.data.message);
}
})
.catch(error => {
console.log('error', error);
//
if (error.response.data.message) {
ElMessage.error(error.response.data.message);
} else {
ElMessage.error(error);
}
});
}
const allWriteDeviceAttr = () => {
if (!serialportForm.port) {
ElMessage.error('请先打开串口');
return '';
}
deviceAttrList.value.forEach((item, index)=>{
setTimeout(()=>{
sendDeviceAttr(item, 'input', index)
},50)
})
// let head = buildHead(
// deviceAttrCommonList.value['input'].datalentype,
// deviceAttrCommonList.value['input'].remote_id,
// deviceAttrCommonList.value['input'].local_id,
// deviceAttrCommonList.value['input'].cmd,
// deviceAttrCommonList.value['input'].devtype,
// deviceAttrCommonList.value['input'].datatype,
// 0,
// 46,
// ''
// );
//
// axios
// .post(
// config.serialPortUrl + '/serial/response',
// {
// port: serialportForm.port,
// data: head,
// hex: 1,
// crc: 1
// },
// {
// headers: {
// 'Content-Type': 'application/x-www-form-urlencoded'
// }
// }
// )
// .then(response => {
// //
// console.log('', response); //
// if (response.data.code === 0) {
// ElMessage.success('');
// let hexValue = response.data.data.hex.substring(24, 392);
// let startValue = 0;
// deviceAttrList.value.forEach((item, index) => {
// if(startValue === 0){
// startValue = item.startValue;
// }
// let value = hexValue.substring(startValue, item.lengthValue * 4 * 2 + startValue);
// startValue = startValue + item.lengthValue * 4 * 2;
// console.log("value",value)
// if (item.dataType === 'str') {
// deviceAttrList.value[index].outputValue = hexToString(value).trim();
// deviceAttrList.value[index].inputValue = hexToString(value).trim();
// }else{
// deviceAttrList.value[index].outputValue = value;
// deviceAttrList.value[index].inputValue = value;
// }
// })
// // deviceAttrList.value[index].outputValue = analysisData(response.data.data.hex || '', data);
// } else {
// ElMessage.error(response.data.message);
// }
// })
// .catch(error => {
// console.log('error', error);
// //
// if (error.response.data.message) {
// ElMessage.error(error.response.data.message);
// } else {
// ElMessage.error(error);
// }
// });
}
// const commonDebuggerFormRef = ref();
//
// const commonDebuggerList = ref([]);
//
// const commonDebuggerForm = reactive({
// localId:'',
// port: '',
// baudrate: 115200,
// databits: 8,
// parity: 0,
// stopbits: 0
// });
//
// const commonDebuggerRules = reactive({
// port: [{ required: true, message: '', trigger: 'change' }],
// baudrate: [{ required: true, message: '', trigger: 'change' }],
// databits: [{ required: true, message: 'port', trigger: 'change' }],
// parity: [{ required: true, message: 'userName', trigger: 'change' }],
// stopbits: [{ required: true, message: 'passWord', trigger: 'change' }]
// });
//
onMounted(() => {
getSerialPortList(false);
});
onUnmounted(() => {});
</script>
<style lang="less" scoped>
/* 样式可以在这里定义 */
#serialport-box {
height: 100%;
position: relative;
padding-bottom: 5px;
.serialport-main {
height: calc(100% - 60px);
overflow-y: auto;
border-radius: 10px;
background: #f2f2f2;
&.open-log {
height: calc(50% - 42px);
}
}
.device-attr-list {
padding: 20px 10px;
.device-attr-item {
display: flex;
.device-attr-item-name {
width: 120px;
}
.device-attr-item-value {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
padding: 5px;
.device-attr-input {
margin-right: 10px;
}
}
}
.btn-box{
display: flex;
justify-content: center;
padding: 20px;
}
}
:deep(.el-form) {
padding: 20px 20px 0;
}
:deep(.el-tabs--border-card > .el-tabs__content) {
padding: 0;
}
:deep(.el-collapse-item__header) {
//height: 42px;
//line-height: 42px;
}
:deep(.el-collapse-item__content) {
padding-bottom: 0;
}
:deep(.el-tabs__content) {
background: #f2f2f2;
}
:deep(.el-tabs__item) {
background: #e6e6e6;
&.is-active {
background: #f2f2f2;
}
}
:deep(.log-box-search .el-input__wrapper) {
background: #fff;
}
:deep(.log-box-search .el-select__wrapper) {
background: #fff;
}
.btn-box {
:deep(.el-form-item__content) {
justify-content: end;
width: 100%;
padding: 0;
}
}
}
</style>

View File

@ -0,0 +1,296 @@
/*
* @Descripttion:
* @version:
* @Author: lfzxs@qq.com
* @Date: 2024-10-16 13:52:11
* @LastEditors: lfzxs@qq.com
* @LastEditTime: 2024-10-18 16:33:31
*/
export function buildHead(d_length,d_remote_id,d_local_id,d_cmd,d_dev_type,d_data_type,dataStart,dataLength,dataValue,activeData) {
// 初始化data为一个32位2进制数
let data = "0000" + d_data_type + d_dev_type + d_cmd + toBinaryString(d_local_id,9) + toBinaryString(d_remote_id,9) + d_length;
console.log("获取头部",data);
let hex_data = binaryToHex(data);
let dataBuffer = '';
let buffer = hexToBuffer(hex_data);
//根据d_cmd的值拼接命令格式
switch (d_cmd) {
case "0000"://特殊指令
break;
case "0011"://地址读
buffer = concatenateBuffers(htonl(buffer),htonl(toFixedSizeBuffer(parseInt(dataStart),4)),htonl(toFixedSizeBuffer(parseInt(dataLength),4)));
break;
case "0100"://地址写
if(activeData.dataType === 'hex'){
dataValue = rearrangeHexStr(dataValue);
dataBuffer = hexToBuffer(dataValue);
}else if(activeData.dataType === 'hexString'){
dataBuffer = hexToBuffer(dataValue);
}else{
dataBuffer = stringToHexBuffer(dataValue,dataLength*4*2);
}
console.log("dataBuffer",dataBuffer)
buffer = concatenateBuffers(htonl(buffer),htonl(toFixedSizeBuffer(parseInt(dataStart),4)),htonl(toFixedSizeBuffer(parseInt(dataLength),4)),dataBuffer)
break;
}
console.log("dataValue-buffer",dataValue,buffer)
let result = bufferToHex(buffer);
return result;
}
export function allBuildHead(d_length,d_remote_id,d_local_id,d_cmd,d_dev_type,d_data_type,dataStart,dataLength,dataValue,allList) {
// 初始化data为一个32位2进制数
let data = "0000" + d_data_type + d_dev_type + d_cmd + toBinaryString(d_local_id,9) + toBinaryString(d_remote_id,9) + d_length;
console.log("获取头部",data);
let hex_data = binaryToHex(data);
let buffer = hexToBuffer(hex_data);
let allBufferList = [];
//根据d_cmd的值拼接命令格式
switch (d_cmd) {
case "0000"://特殊指令
break;
case "0011"://地址读
buffer = concatenateBuffers(htonl(buffer),htonl(toFixedSizeBuffer(parseInt(dataStart),4)),htonl(toFixedSizeBuffer(parseInt(dataLength),4)));
break;
case "0100"://地址写
allBufferList = allList.map(item=>{
return stringToHexBuffer(item.inputValue,item.lengthValue*4*2);
})
buffer = concatenateBuffers(htonl(buffer),htonl(toFixedSizeBuffer(parseInt(dataStart),4)),htonl(toFixedSizeBuffer(parseInt(dataLength),4)),...allBufferList)
break;
}
let result = bufferToHex(buffer);
return result;
}
export function bufferToHex(buffer) {
let hexString = '';
const view = new Uint8Array(buffer);
for (let i = 0; i < view.length; i++) {
const hex = view[i].toString(16).padStart(2, '0');
hexString += hex;
}
return hexString;
}
export function toBinaryString(number, length) {
let binaryString = number.toString(2);
return binaryString.padStart(length, '0');
}
export function binaryToHex(binaryStr) {
// 确保二进制字符串长度是4的倍数
if (binaryStr.length % 4 !== 0) {
binaryStr = binaryStr.padStart(binaryStr.length + 4 - (binaryStr.length % 4), '0');
}
let hexStr = '';
for (let i = 0; i < binaryStr.length; i += 4) {
// 取出每4位二进制字符串
const binaryChunk = binaryStr.slice(i, i + 4);
// 转换成十六进制字符并追加到结果字符串中
hexStr += parseInt(binaryChunk, 2).toString(16);
}
return hexStr;
}
export function hexToBuffer(hexStr) {
if (hexStr.length % 2 !== 0) {
throw new Error('Invalid hex string');
}
let buffer = new ArrayBuffer(hexStr.length / 2);
let view = new Uint8Array(buffer);
for (let i = 0; i < hexStr.length; i += 2) {
view[i / 2] = parseInt(hexStr.substr(i, 2), 16);
}
return buffer;
}
export function swapEndian(buffer) {
const swappedBuffer = new ArrayBuffer(buffer.byteLength);
const view = new DataView(buffer);
const swappedView = new DataView(swappedBuffer);
for (let i = 0; i < buffer.byteLength; i++) {
swappedView.setUint8(i, view.getUint8(buffer.byteLength - 1 - i));
}
return swappedBuffer;
}
export function htonl(buffer) {
if (buffer.byteLength !== 4) {
throw new Error('Buffer must be exactly 4 bytes.');
}
let view = new DataView(buffer);
let number = view.getUint32(0);
let swappedNumber = ((number & 0xFF) << 24) |
((number & 0xFF00) << 8) |
((number & 0xFF0000) >> 8) |
((number >> 24) & 0xFF);
let swappedBuffer = new ArrayBuffer(4);
let swappedView = new DataView(swappedBuffer);
swappedView.setUint32(0, swappedNumber);
return swappedBuffer;
}
//将数字转换成指定字节大小的buffer
export function toFixedSizeBuffer(number, byteSize) {
if (byteSize <= 0) {
throw new Error('Byte size must be greater than zero.');
}
let buffer = new ArrayBuffer(byteSize);
let view = new DataView(buffer);
// 根据指定字节数设置数值到缓冲区中
for (let i = 0; i < byteSize; i++) {
view.setUint8(byteSize - 1 - i, number & 0xFF);
number = number >> 8;
}
return buffer;
}
export function concatenateBuffers(...buffers) {
// 确保所有元素均为 ArrayBuffer
buffers.forEach(buffer => {
if (!(buffer instanceof ArrayBuffer)) {
throw new TypeError('All arguments must be ArrayBuffers');
}
});
// 计算总长度
let totalLength = buffers.reduce((sum, buffer) => sum + buffer.byteLength, 0);
// 创建一个新的 ArrayBuffer 并使用 Uint8Array 进行操作
let concatenatedBuffer = new Uint8Array(totalLength);
let offset = 0;
// 逐个复制每个缓冲区的内容
buffers.forEach(buffer => {
concatenatedBuffer.set(new Uint8Array(buffer), offset);
offset += buffer.byteLength;
});
return concatenatedBuffer.buffer;
}
export function stringToHexBuffer(str,length) {
// return new TextEncoder().encode(str).buffer;
const bufferView = new TextEncoder().encode(str);
// 计算需要补充的00的数量
const targetLength = length / 2; // 目标长度(字节数)
const paddingLength = targetLength - bufferView.length;
// 创建一个新的Uint8Array长度为目标长度
const paddedBufferView = new Uint8Array(targetLength);
// 将原始Uint8Array的内容复制到新的Uint8Array中
paddedBufferView.set(bufferView);
// 填充00
if (paddingLength > 0) {
paddedBufferView.fill(0, bufferView.length, targetLength);
}
// 返回格式化后的Uint8Array
return paddedBufferView.buffer;
}
export function hexToString(hexStr) {
let str = '';
for (let i = 0; i < hexStr.length; i += 2) {
if(hexStr.substr(i, 2)!=='00'){
str += String.fromCharCode(parseInt(hexStr.substr(i, 2), 16));
}
}
return str;
}
export function rearrangeHexStr(hexStr) {
// 将输入的十六进制字符串解析为字节数组
// 将输入的十六进制字符串按每8位分组
const groups = [];
for (let i = 0; i < hexStr.length; i += 8) {
groups.push(hexStr.slice(i, i + 8));
}
// 对每个组内的每两位进行倒序拼接
const rearrangedGroups = groups.map(group => {
let rearrangedGroup = '';
for (let i = 0; i < group.length; i += 2) {
rearrangedGroup = group.substr(i, 2) + rearrangedGroup;
}
return rearrangedGroup;
});
// 将所有组重新拼接成一个字符串
const rearrangedHexStr = rearrangedGroups.join('');
return rearrangedHexStr;
}
//高低位交换
export function rearrangeHexStr4(hexStr) {
let rearrangedGroup = '';
for (let i = 0; i < hexStr.length; i += 2) {
rearrangedGroup = hexStr.substr(i, 2) + rearrangedGroup;
}
return rearrangedGroup;
}
export function hexToVersion(hexStr) {
let str = rearrangeHexStr(hexStr);
str = hexToDec(str);
return str;
}
export function versionToHex(hexStr) {
let str = decToHex(hexStr);
str = rearrangeHexStr(str);
return str;
}
// 十六进制转十进制
export function hexToDec(hexStr) {
// 去除前缀 "0x"(如果存在)
hexStr = hexStr.replace(/^0x/, '');
// 将十六进制字符串转换为十进制数字
return parseInt(hexStr, 16);
}
// 十进制转十六进制
export function decToHex(decNum) {
// 将十进制数字转换为十六进制字符串
let hexStr = decNum.toString(16);
// 可选:添加前缀 "0x"
return `0x${hexStr}`;
}