Skip to content

Commit f2c4f1a

Browse files
committed
v1.7
1 parent 4febf5f commit f2c4f1a

File tree

11 files changed

+116
-59
lines changed

11 files changed

+116
-59
lines changed

README.md

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,47 +9,26 @@
99

1010
## 功能特点
1111

12-
- 🔌 支持串口和WebUSB设备连接
12+
- 🔌 支持串口、WebUSB、Websocket、stlink设备连接
1313
- 📝 实时数据收发显示
1414
- 🎨 支持文本和HEX格式数据发送
1515
- 📜 支持自定义脚本编写和执行
1616
- 🎯 快捷发送功能
1717
- ⚙️ 可配置的显示选项
1818
- 🌙 暗色主题支持
1919

20-
## 使用说明
21-
22-
### 连接设备
23-
1. 点击连接按钮选择串口设备
24-
2. 选择合适的波特率和其他串口参数
25-
3. 连接成功后即可开始收发数据
26-
27-
### 数据发送
28-
- 支持文本和HEX格式数据发送
29-
- 可以保存常用的发送内容为快捷发送项
30-
- 支持自定义脚本发送数据
31-
32-
### 脚本功能
20+
## 脚本功能
3321
可以编写JavaScript脚本来实现自动化操作,支持以下API:
3422
- `sendText(text)` - 发送文本数据
3523
- `sendHex(hex)` - 发送HEX格式数据
3624
- `sleep(ms)` - 延时指定毫秒数
3725

38-
## 技术栈
39-
40-
- Vue 3
41-
- TypeScript
42-
- Vite
43-
- Element Plus
44-
- CodeMirror 6
45-
- Xterm.js
46-
4726
## 开发环境要求
4827

4928
- Node.js >= 18.0.0
5029
- 支持 Web Serial API 的现代浏览器(如 Chrome、Edge)
5130

52-
## 安装
31+
## 编译
5332

5433
```bash
5534
# 安装依赖
@@ -58,13 +37,6 @@ yarn install
5837
# 启动开发服务器
5938
yarn dev
6039

61-
# 构建生产版本
62-
yarn build
63-
```
64-
65-
## 构建
66-
67-
```bash
6840
# 构建生产版本
6941
yarn build
7042

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,16 @@
1515
"@codemirror/state": "^6.4.1",
1616
"@codemirror/theme-one-dark": "^6.1.2",
1717
"@codemirror/view": "^6.36.2",
18+
"@element-plus/icons-vue": "^2.3.1",
1819
"@vueuse/core": "^12.5.0",
1920
"@xterm/addon-search": "^0.15.0",
20-
"@element-plus/icons-vue": "^2.3.1",
2121
"element-plus": "^2.9.3",
2222
"less": "^4.2.2",
2323
"pinia": "^2.3.1",
2424
"splitpanes": "^3.1.8",
2525
"stats.js": "^0.17.0",
2626
"three": "^0.173.0",
27+
"three-particle-fire": "^0.1.0",
2728
"uplot": "^1.6.31",
2829
"vue": "^3.5.13",
2930
"vue-router": "^4.5.0",

public/manifest.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
{
2-
"name": "Web Serial Debugger",
3-
"short_name": "Serial Debug",
2+
"name": "串口助手",
3+
"short_name": "串口助手",
44
"description": "Web Serial 串口调试工具",
55
"start_url": "./",
66
"display": "standalone",
7-
"background_color": "#ffffff",
8-
"theme_color": "#409eff",
7+
"background_color": "#000000",
8+
"theme_color": "#1d1e1f",
99
"icons": [
1010
{
1111
"src": "vite.svg",

src/App.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ handleResize()
9494
<el-tab-pane label="数据表">
9595
<DataTable />
9696
</el-tab-pane>
97+
<el-tab-pane label="工具箱">
98+
</el-tab-pane>
9799
</el-tabs>
98100
</Pane>
99101
<Pane class="w25">

src/components/Chart3D.vue

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,36 +12,44 @@ import { useDark } from '@vueuse/core'
1212
import { ElMessage } from 'element-plus'
1313
// @ts-ignore
1414
import Stats from 'stats.js'
15+
// @ts-ignore
16+
import particleFire from 'three-particle-fire';
17+
try { particleFire.install( { THREE: THREE } ); } catch (e) { }
1518
1619
const container = ref<HTMLDivElement | null>(null)
1720
const pitch = ref(0)
1821
const roll = ref(0)
1922
const yaw = ref(0)
20-
const currentModel = ref('arrow')
23+
const currentModel = ref('rocket')
2124
const customModel = ref<THREE.Group | null>(null)
2225
const fileInput = ref<HTMLInputElement | null>(null)
2326
2427
const isDark = useDark()
2528
const sceneBackground = computed(() => isDark.value ? 0x1a1a1a : 0xf0f0f0)
2629
// const gridColor = computed(() => isDark.value ? 0x404040 : 0x808080)
27-
const modelColor = computed(() => isDark.value ? 0x4a9eff : 0x3366ff)
30+
const modelColor = computed(() => isDark.value ? 0x404040 : 0x3366ff)
31+
// const modelColor = computed(() => isDark.value ? 0xF4F5F0 : 0x3366ff)
2832
2933
let scene: THREE.Scene
34+
let clock: THREE.Clock
3035
let camera: THREE.PerspectiveCamera
3136
let renderer: THREE.WebGLRenderer
3237
let model: THREE.Group
3338
let controls: OrbitControls
3439
let animationFrameId: number
3540
let stats: Stats
41+
let rocketFireMesh: any
3642
3743
const initScene = () => {
3844
scene = new THREE.Scene()
3945
scene.background = new THREE.Color(sceneBackground.value)
4046
4147
// 添加坐标轴辅助器
42-
const axesHelper = new THREE.AxesHelper(5)
48+
const axesHelper = new THREE.AxesHelper(1.6)
4349
scene.add(axesHelper)
4450
51+
clock = new THREE.Clock()
52+
4553
// 初始化性能监视器
4654
stats = new Stats()
4755
stats.showPanel(0) // 0: fps, 1: ms, 2: mb, 3+: custom
@@ -98,6 +106,50 @@ const createArrowModel = () => {
98106
return group
99107
}
100108
109+
const createRocketModel = () => {
110+
const group = new THREE.Group()
111+
112+
// 箭头主体
113+
const bodyGeometry = new THREE.ConeGeometry(0.2, 0.5, 12)
114+
const bodyMaterial = new THREE.MeshStandardMaterial({
115+
color: modelColor.value,
116+
metalness: 0.6,
117+
roughness: 0.3,
118+
envMapIntensity: 1.2
119+
})
120+
const body = new THREE.Mesh(bodyGeometry, bodyMaterial)
121+
body.position.set(0, 1.05, 0)
122+
// body.rotation.x = -Math.PI / 2
123+
group.add(body)
124+
125+
const tailGeometry = new THREE.CylinderGeometry(0.2, 0.2, 1.6)
126+
const tailMaterial = new THREE.MeshStandardMaterial({
127+
color: modelColor.value,
128+
metalness: 0.6,
129+
roughness: 0.3,
130+
envMapIntensity: 1.2
131+
})
132+
const tail = new THREE.Mesh(tailGeometry, tailMaterial)
133+
tail.position.set(0, 0, 0)
134+
group.add(tail)
135+
136+
const fireRadius = 0.09;
137+
const fireHeight = 1.5;
138+
const particleCount = 800;
139+
const height = window.innerHeight;
140+
141+
const geometry0 = new particleFire.Geometry( fireRadius, fireHeight, particleCount );
142+
const material0 = new particleFire.Material( { color: 0xff2200 } );
143+
material0.setPerspective( camera.fov, height );
144+
rocketFireMesh = new THREE.Points( geometry0, material0 );
145+
rocketFireMesh.rotation.x = 3.14
146+
rocketFireMesh.position.set(0, -0.92, 0)
147+
148+
group.add(rocketFireMesh)
149+
150+
return group
151+
}
152+
101153
const createCubeModel = () => {
102154
const group = new THREE.Group()
103155
@@ -120,6 +172,9 @@ const createModel = (type: string) => {
120172
}
121173
122174
switch (type) {
175+
case 'rocket':
176+
model = createRocketModel()
177+
break
123178
case 'arrow':
124179
model = createArrowModel()
125180
break
@@ -205,6 +260,7 @@ const addLights = () => {
205260
}
206261
207262
const animate = () => {
263+
var delta = clock.getDelta();
208264
animationFrameId = requestAnimationFrame(animate)
209265
stats.begin()
210266
@@ -215,6 +271,9 @@ const animate = () => {
215271
THREE.MathUtils.degToRad(pitch.value)
216272
)
217273
}
274+
if (rocketFireMesh) {
275+
rocketFireMesh.material.update( delta );
276+
}
218277
219278
controls.update()
220279
renderer.render(scene, camera)
@@ -223,9 +282,15 @@ const animate = () => {
223282
224283
const handleResize = () => {
225284
if (container.value && camera && renderer) {
226-
camera.aspect = container.value.clientWidth / container.value.clientHeight
285+
let width = container.value.clientWidth
286+
let height = container.value.clientHeight
287+
camera.aspect = width / height
227288
camera.updateProjectionMatrix()
228-
renderer.setSize(container.value.clientWidth, container.value.clientHeight)
289+
renderer.setSize(width, height)
290+
291+
if (rocketFireMesh) {
292+
rocketFireMesh.material.setPerspective( camera.fov, height );
293+
}
229294
}
230295
}
231296

src/components/DataTable.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ onUnmounted(() => {
6464
<el-checkbox v-model="fieldStore.columnVisibility[key]" @change="fieldStore.toggleColumnVisibility()">
6565
{{ key === 'key' ? 'Key' :
6666
key === 'name' ? '字段名' :
67-
key === 'dataType' ? '类型' :
67+
key === 'dataType' ? '数据类型' :
6868
key === 'keyAddr' ? '内存地址' :
6969
key === 'keySize' ? '内存大小' :
7070
key === 'description' ? '描述' :

src/components/SerialConfig.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ const handleConenctClick = () => {
440440
<el-option label="WebSocket" value="websocket"></el-option>
441441
<el-option label="脚本" value="script"></el-option>
442442
<el-option label="Stlink" value="webstlink"></el-option>
443-
<el-option label="IMU模拟数据" value="mock"></el-option>
443+
<el-option label="模拟数据(IMU)" value="mock"></el-option>
444444
</el-option-group>
445445
</el-select>
446446
</div>
@@ -512,7 +512,7 @@ const handleConenctClick = () => {
512512
}
513513
514514
.port-list {
515-
width: 120px;
515+
width: 160px;
516516
}
517517
518518
.config-section {

src/components/SerialSend.vue

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,19 +58,23 @@ const handleIntervalChange = (value: number) => {
5858
let historyIndex = -1
5959
6060
const handleKeyDown = (e: KeyboardEvent) => {
61-
if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') {
61+
if (!e.metaKey && !e.ctrlKey && !e.shiftKey && e.key === 'Enter') {
6262
sendData()
6363
historyIndex = -1
64-
return
64+
e.preventDefault()
65+
return false
6566
}
6667
6768
const target = e.target as HTMLTextAreaElement
68-
const cursorPosition = target.selectionStart
69-
const contentBeforeCursor = sendConfig.value.content.slice(0, cursorPosition)
70-
const isFirstLine = !contentBeforeCursor.includes('\n')
71-
72-
if ((e.key === 'ArrowUp' || e.key === 'ArrowDown') && !isFirstLine) {
73-
return
69+
if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
70+
const cursorPosition = target.selectionStart
71+
const contentBeforeCursor = sendConfig.value.content.slice(0, cursorPosition)
72+
const isFirstLine = !contentBeforeCursor.includes('\n')
73+
if (historyIndex == -1 && !isFirstLine) {
74+
return
75+
}
76+
} else {
77+
historyIndex = -1
7478
}
7579
7680
if (e.key === 'ArrowUp') {
@@ -114,8 +118,11 @@ const handleKeyDown = (e: KeyboardEvent) => {
114118
</div>
115119
<el-checkbox v-model="sendConfig.addChecksum" label="校验和" class="me-2" />
116120
<el-checkbox v-model="sendConfig.autoSend" @change="toggleAutoSend" label="自动发送" class="me-2" />
117-
<el-input-number v-model="sendConfig.autoSendInterval" :min="100" :max="10000" :step="100" @change="handleIntervalChange" size="small" class="me-2" />
118-
<span>ms</span>
121+
<el-input-number v-model="sendConfig.autoSendInterval" :min="100" :max="10000" :step="100" @change="handleIntervalChange" size="small" class="me-2" title="自动发送时间间隔">
122+
<template #suffix>
123+
<span>ms</span>
124+
</template>
125+
</el-input-number>
119126
<el-button type="primary" @click="sendData" class="me-2">发送</el-button>
120127
</div>
121128
<div class="send-content">

src/utils/ScriptManager.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,17 @@ export interface Runtimer {
1212
DataSenderInterface: Function | null
1313
}
1414

15-
const demo1 = `
16-
// 处理接收的数据 数据格式:"pitch:-0.13,roll:0.00,yaw:0.07\\n"
17-
let cache = '';
15+
const demo1 = `let cache = '';
16+
17+
// 处理接收的数据
1818
async function DataReceiver(data) {
1919
cache += uint8ArrayToString(data);
20+
// 数据格式:"pitch:-0.13,roll:0.00,yaw:0.07\\n"
2021
2122
if (cache.indexOf('\\n') !== -1) {
2223
const lines = cache.split('\\n');
2324
cache = lines.pop() || '';
25+
2426
for (const line of lines) {
2527
let files = line.split(',')
2628
let data = {};
@@ -40,7 +42,9 @@ async function DataReceiver(data) {
4042
4143
// 处理发送的数据
4244
async function DataSender(data) {
43-
await sleep(100);
45+
// checksum
46+
// await sleep(10);
47+
4448
return data;
4549
}
4650
@@ -50,6 +54,7 @@ setInterval(async () => {
5054
// sendHex(bytes);
5155
}, 1000);
5256
57+
// 支持的函数
5358
// stringToUint8Array();
5459
// uint8ArrayToHexString();
5560
// uint8ArrayToString();

vite.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export default defineConfig({
1212
manualChunks: {
1313
'vendor': [],
1414
'vue': ['vue', 'vue-router', '@vueuse/core', 'pinia'],
15-
'three': ['three', 'stats.js'],
15+
'three': ['three', 'stats.js', 'three-particle-fire'],
1616
'uplot': ['uplot'],
1717
'xterm': ['xterm', 'xterm-addon-fit', 'xterm-addon-web-links', '@xterm/addon-search'],
1818
'utils': ['splitpanes', 'element-plus']

0 commit comments

Comments
 (0)