<template>
|
<view class="page">
|
<view class="status-bar"></view>
|
<view class="nav-bar">
|
<text>rs232-serial sample</text>
|
<text @click="handleEmpty">清空</text>
|
</view>
|
<view class="scroll-area">
|
<view class="record-item" v-for="(item, i) in history" :key="i"
|
:style="{color: item.prefix.includes('Rx') ? ' #3f9f3f' : '#3030ff'}">
|
<text>{{item.time}} {{item.prefix}} {{item.text}}</text>
|
</view>
|
</view>
|
<view class="control-panel">
|
<view class="row">
|
<radio-group class="radio-group" @change="receTypeChange">
|
<label class="radio-item" v-for="(item, index) in dataTypes" :key="item.value">
|
<radio style="transform:scale(0.7)" :disabled="isOpen" :value="index"
|
:checked="index === currentReceType" />
|
<view>接收{{item.name}}</view>
|
</label>
|
</radio-group>
|
</view>
|
<view class="row">
|
<radio-group class="radio-group" @change="sendTypeChange">
|
<label class="radio-item" v-for="(item, index) in dataTypes" :key="item.value">
|
<radio style="transform:scale(0.7)" :disabled="isOpen" :value="index"
|
:checked="index === currentSendType" />
|
<view>发送{{item.name}}</view>
|
</label>
|
</radio-group>
|
</view>
|
<view class="row">
|
<filter-item label="串口号" :disabled="isOpen" v-model="serialOptions.port" :data="portList" />
|
<filter-item label="波特率" :disabled="isOpen" v-model="serialOptions.baudRate" :data="baudRateList" />
|
</view>
|
<view class="row">
|
<filter-item label="数据位" :disabled="isOpen" v-model="serialOptions.dataBits" :data="dataBitsList" />
|
<filter-item label="校验位" :disabled="isOpen" v-model="serialOptions.parity" valueType="value"
|
:data="parityList" />
|
</view>
|
<view class="row">
|
<filter-item label="停止位" :disabled="isOpen" v-model="serialOptions.stopBits" :data="stopBitsList" />
|
<filter-item label="流控" :disabled="isOpen" v-model="serialOptions.flowCon" valueType="value"
|
:data="flowConList" />
|
</view>
|
<view class="row">
|
<uni-easyinput v-model="text" placeholder="请输入发送内容" />
|
</view>
|
<view class="row">
|
<button class="btn-item" @click="handleOpen">打开</button>
|
<button class="btn-item" @click="handleClose">关闭</button>
|
<button class="btn-item" type="primary" @click="handleSend">发送</button>
|
</view>
|
</view>
|
|
</view>
|
</template>
|
|
<script>
|
import FilterItem from './filter.vue';
|
import { RS232Serial, checkHasIntegration } from '@/uni_modules/shmily-rs232-serial';
|
let serialPort;
|
export default {
|
components: {
|
FilterItem
|
},
|
computed: {
|
receType() {
|
return this.dataTypes[this.currentReceType].value;
|
},
|
sendType() {
|
return this.dataTypes[this.currentSendType].value;
|
}
|
},
|
data() {
|
return {
|
isOpen: false,
|
dataTypes: [{
|
value: 'ASCII',
|
name: 'Text'
|
},
|
{
|
value: 'HEX',
|
name: 'Hex'
|
}
|
],
|
currentReceType: 0,
|
currentSendType: 0,
|
serialOptions: {
|
port: '/dev/ttyS4',
|
baudRate: '115200',
|
dataBits: '8',
|
stopBits: '1',
|
parity: 0,
|
flowCon: 0
|
},
|
portList: [],
|
baudRateList: ["0", "50", "75", "110", "134", "150", "200", "300", "600", "1200", "1800", "2400", "4800",
|
"9600", "19200", "38400", "57600", "115200", "230400", "460800", "500000", "576000", "921600", "1000000",
|
"1152000", "1500000", "2000000", "2500000", "3000000", "3500000", "4000000"
|
],
|
dataBitsList: ["8", "7", "6", "5"],
|
stopBitsList: ["1", "2"],
|
parityList: ["NONE", "ODD", "EVEN", "MARK", "SPACE"],
|
flowConList: ["NONE", "RTS/CTS", "XON/XOFF"],
|
text: '',
|
history: []
|
};
|
},
|
created() {
|
this.baudRateList = this.resolveData(this.baudRateList);
|
this.dataBitsList = this.resolveData(this.dataBitsList);
|
this.stopBitsList = this.resolveData(this.stopBitsList);
|
this.parityList = this.resolveData(this.parityList);
|
this.flowConList = this.resolveData(this.flowConList);
|
serialPort = new RS232Serial();
|
if (checkHasIntegration()) {
|
this.portList = this.resolveData(serialPort.getDeviceList());
|
} else {
|
this.showToast('需要在自定义基座中运行');
|
}
|
if (!this.portList.length) {
|
this.serialOptions.port = '';
|
}
|
},
|
methods: {
|
receTypeChange(e) {
|
this.currentReceType = e.detail.value;
|
},
|
sendTypeChange(e) {
|
this.currentSendType = e.detail.value;
|
},
|
resolveData(data) {
|
return data.map((item, i) => {
|
return {
|
text: item,
|
value: i
|
}
|
});
|
},
|
handleOpen() {
|
if (!checkHasIntegration()) {
|
this.showToast('需要在自定义基座中运行');
|
return;
|
}
|
serialPort.subscribe(this.receType, data => {
|
this.handleAddDaa('rx', data);
|
});
|
if (!this.serialOptions.port) {
|
this.showToast('请选择串口号');
|
return;
|
}
|
const options = {
|
port: this.serialOptions.port,
|
baudRate: parseInt(this.serialOptions.baudRate),
|
dataBits: parseInt(this.serialOptions.dataBits),
|
stopBits: parseInt(this.serialOptions.stopBits),
|
parity: parseInt(this.serialOptions.parity),
|
flowCon: parseInt(this.serialOptions.flowCon)
|
};
|
const success = serialPort.open(options);
|
if (success) {
|
this.isOpen = true;
|
// 防止superuser、magisk等软件跳转后看不到提示
|
setTimeout(() => {
|
this.showToast('打开成功');
|
}, 1000);
|
} else {
|
this.showToast('打开失败');
|
}
|
},
|
handleClose() {
|
if (!checkHasIntegration()) {
|
this.showToast('需要在自定义基座中运行');
|
return;
|
}
|
const success = serialPort.close();
|
if (success) {
|
this.showToast('关闭成功');
|
this.isOpen = false;
|
}
|
},
|
handleSend() {
|
if (!checkHasIntegration()) {
|
this.showToast('需要在自定义基座中运行');
|
return;
|
}
|
if (!this.text.trim()) {
|
this.showToast('请输入发送内容');
|
return;
|
}
|
if (serialPort.isOpen()) {
|
if (this.sendType === 'ASCII') {
|
serialPort.sendText(this.text);
|
} else {
|
serialPort.sendHex(this.text);
|
}
|
this.handleAddDaa('tx', this.text);
|
} else {
|
this.showToast('请先打开串口');
|
}
|
},
|
handleAddDaa(type, text) {
|
if (text.trim()) {
|
if (type === 'rx') {
|
this.history.unshift({
|
time: this.getTime(),
|
prefix: 'Rx: <==',
|
text: text.trim().replace(/\n/g, "")
|
});
|
} else {
|
this.history.unshift({
|
time: this.getTime(),
|
prefix: 'Tx: ==>',
|
text: text.trim().replace(/\n/g, "")
|
});
|
}
|
}
|
},
|
handleEmpty() {
|
this.history = [];
|
},
|
getTime() {
|
// 获取当前的时分秒,不足10的前面补0
|
const now = new Date();
|
const hour = String(now.getHours()).padStart(2, '0');
|
const minute = String(now.getMinutes()).padStart(2, '0')
|
const second = String(now.getSeconds()).padStart(2, '0')
|
const milliseconds = String(now.getMilliseconds()).padStart(3, '0')
|
return `${hour}:${minute}:${second} ${milliseconds}`;
|
},
|
showToast(text) {
|
uni.showToast({
|
title: text,
|
icon: 'none',
|
});
|
}
|
}
|
}
|
</script>
|
|
<style lang="scss" scoped>
|
.page {
|
height: 100%;
|
display: flex;
|
flex-direction: column;
|
}
|
|
.status-bar {
|
height: var(--status-bar-height);
|
background-color: #2e409f;
|
}
|
|
.nav-bar {
|
height: 44px;
|
background-color: #4050b5;
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
padding: 0 10px;
|
color: white;
|
}
|
|
.scroll-area {
|
flex: 1;
|
min-height: 1px;
|
overflow: auto;
|
background-color: #efefef;
|
|
.record-item {
|
padding: 8rpx 20rpx;
|
border-bottom: 1px solid #dddddd;
|
font-size: 12px;
|
display: flex;
|
align-items: center;
|
word-break: break-all;
|
}
|
}
|
|
.control-panel {
|
padding: 20rpx;
|
font-size: 14px;
|
|
.radio-group {
|
display: flex;
|
}
|
|
.radio-item {
|
display: flex;
|
align-items: center;
|
margin-right: 20px;
|
}
|
|
.row {
|
display: flex;
|
gap: 30rpx;
|
margin-top: 20rpx;
|
}
|
|
.btn-item {
|
font-size: 14px;
|
flex: 1;
|
}
|
}
|
</style>
|