feat: auto-scan receives 4 sequential ADC sets for multi-spectrum scan

Firmware does R→UV→Y→IR sequential scan autonomously. Miniprogram
now listens for 4 consecutive ADC notifications, storing each as a
separate spectrum group. Also listens for run_state=IDLE as scan
completion signal. Displays all 4 spectrum groups with PD1-PD7 bars.
Stores full scan data in globalData.lastScanData for diagnosis phase.
这个提交包含在:
Guoguo
2026-06-22 06:20:53 -07:00
父节点 b5c6038273
当前提交 f4e74e9460
修改 3 个文件,包含 115 行新增50 行删除
+74 -39
查看文件
@@ -1,6 +1,7 @@
var ble = require('../../services/ble') var ble = require('../../services/ble')
var SCAN_BRIGHTNESS = 128 var SCAN_TIMEOUT = 15000
var SCAN_TIMEOUT = 12000 var SPECTRUM_NAMES = ['红光', '紫外光', '黄光', '红外光']
var SPECTRUM_COUNT = 4
Page({ Page({
data: { data: {
@@ -8,8 +9,8 @@ Page({
scanning: true, scanning: true,
scanProgress: 0, scanProgress: 0,
regions: 0x1F, regions: 0x1F,
pdValues: [], spectrumIndex: 0,
pdRaw: [], spectrumData: [],
vbat: 0, vbat: 0,
battery: 0, battery: 0,
error: '' error: ''
@@ -36,41 +37,65 @@ Page({
if (this._progressTimer) { clearInterval(this._progressTimer); this._progressTimer = null } if (this._progressTimer) { clearInterval(this._progressTimer); this._progressTimer = null }
if (this._timeoutTimer) { clearTimeout(this._timeoutTimer); this._timeoutTimer = null } if (this._timeoutTimer) { clearTimeout(this._timeoutTimer); this._timeoutTimer = null }
if (this._onAdc) { ble.off('adc', this._onAdc); this._onAdc = null } if (this._onAdc) { ble.off('adc', this._onAdc); this._onAdc = null }
if (this._onRunState) { ble.off('run_state', this._onRunState); this._onRunState = null }
}, },
startScan: function () { startScan: function () {
var self = this var self = this
self._scanResults = []
if (!ble.isConnected()) { if (!ble.isConnected()) {
self.setData({ scanning: false, error: '设备未连接,请先连接设备' }) self.setData({ scanning: false, error: '设备未连接,请先连接设备' })
return return
} }
self.setData({ scanning: true, scanProgress: 0, error: '', pdValues: [] }) self.setData({ scanning: true, scanProgress: 0, error: '', spectrumData: [], spectrumIndex: 0 })
this._progressTimer = setInterval(function () { this._progressTimer = setInterval(function () {
var p = self.data.scanProgress + 1 var target = ((self._scanResults.length + 1) / SPECTRUM_COUNT) * 90
var p = self.data.scanProgress
if (p < target) p += 1
if (p > 90) p = 90 if (p > 90) p = 90
self.setData({ scanProgress: p }) self.setData({ scanProgress: p })
}, 80) }, 100)
this._onAdc = function (data) { this._onAdc = function (data) {
console.log('[SCAN] 收到ADC数据:', JSON.stringify(data)) if (!self.data.scanning) return
self._cleanup() var idx = self._scanResults.length
self.setData({ scanning: false, scanProgress: 100 }) if (idx >= SPECTRUM_COUNT) return
self._handleAdcData(data)
console.log('[SCAN] 收到第' + (idx + 1) + '组ADC (' + SPECTRUM_NAMES[idx] + '):', data.pd)
self._scanResults.push({
spectrum: SPECTRUM_NAMES[idx],
pd: data.pd.slice(0),
vbat: data.vbat,
battery: data.battery
})
self.setData({ spectrumIndex: idx + 1 })
if (self._scanResults.length >= SPECTRUM_COUNT) {
self._scanComplete()
}
} }
ble.on('adc', this._onAdc) ble.on('adc', this._onAdc)
console.log('[SCAN] 下发扫描指令: 全域亮度', SCAN_BRIGHTNESS) this._onRunState = function (data) {
if (data.run_state === 0x00 && self._scanResults.length > 0 && self.data.scanning) {
console.log('[SCAN] 设备进入IDLE,扫描结束')
self._scanComplete()
}
}
ble.on('run_state', this._onRunState)
console.log('[SCAN] 下发扫描指令,等待固件序贯扫描 R→UV→Y→IR')
ble.setParams({ ble.setParams({
region_mask: 0x1F, region_mask: self.data.regions,
wavelength: 2, wavelength: 2,
brightness: SCAN_BRIGHTNESS, brightness: 128,
hold_time: 10, hold_time: 10,
control: 0x01 control: 0x01
}).then(function () { }).then(function () {
console.log('[SCAN] 扫描指令发送成功,等待ADC回传...') console.log('[SCAN] 扫描指令发送成功')
}).catch(function (err) { }).catch(function (err) {
console.error('[SCAN] 扫描指令发送失败:', err) console.error('[SCAN] 扫描指令发送失败:', err)
self._cleanup() self._cleanup()
@@ -79,35 +104,45 @@ Page({
this._timeoutTimer = setTimeout(function () { this._timeoutTimer = setTimeout(function () {
if (!self.data.scanning) return if (!self.data.scanning) return
console.log('[SCAN] 等待ADC超时,使用默认值') console.log('[SCAN] 超时,已收到' + self._scanResults.length + '组数据')
self._cleanup() self._scanComplete()
self.setData({ scanning: false, scanProgress: 100 })
self._handleAdcData(null)
}, SCAN_TIMEOUT) }, SCAN_TIMEOUT)
}, },
_handleAdcData: function (data) { _scanComplete: function () {
var regionNames = ['右区(IO1)', '左区(IO2)', '上区(IO3)', '中区(IO4)', '下区(IO5)'] this._cleanup()
var pdValues = [] this.setData({ scanning: false, scanProgress: 100 })
this._buildDisplay()
},
if (data && data.pd && data.pd.length >= 7) { _buildDisplay: function () {
this.setData({ pdRaw: data.pd, vbat: data.vbat || 0, battery: data.battery || 0 }) var results = this._scanResults || []
for (var i = 0; i < 5; i++) { var spectrumData = []
var barW = Math.min(100, Math.round(data.pd[i] / 40.95))
pdValues.push({ region: regionNames[i], pd: data.pd[i], pdText: String(data.pd[i]), barWidth: barW })
}
pdValues.push({ region: 'PD6', pd: data.pd[5], pdText: String(data.pd[5]), barWidth: Math.min(100, Math.round(data.pd[5] / 40.95)) })
pdValues.push({ region: 'PD7', pd: data.pd[6], pdText: String(data.pd[6]), barWidth: Math.min(100, Math.round(data.pd[6] / 40.95)) })
getApp().globalData.lastScanPd = data.pd for (var s = 0; s < results.length; s++) {
getApp().globalData.lastScanVbat = data.vbat var r = results[s]
} else { var items = []
for (var j = 0; j < 5; j++) { for (var i = 0; i < 7; i++) {
pdValues.push({ region: regionNames[j], pd: 0, pdText: '未采集', barWidth: 0 }) var val = r.pd[i] || 0
items.push({
label: 'PD' + (i + 1),
value: val,
barWidth: Math.min(100, Math.round(val / 40.95))
})
} }
spectrumData.push({ name: r.spectrum, items: items })
} }
this.setData({ pdValues: pdValues }) if (results.length > 0) {
var last = results[results.length - 1]
this.setData({
vbat: last.vbat || 0,
battery: last.battery || 0
})
}
getApp().globalData.lastScanData = results
this.setData({ spectrumData: spectrumData })
}, },
onUnload: function () { onUnload: function () {
@@ -117,10 +152,10 @@ Page({
onNext: function () { onNext: function () {
var mask = this.data.regions || 0x1F var mask = this.data.regions || 0x1F
var pdRaw = this.data.pdRaw var scanData = this._scanResults || []
var pdParam = pdRaw.length > 0 ? '&pd=' + encodeURIComponent(JSON.stringify(pdRaw)) : '' var param = scanData.length > 0 ? '&scan=' + encodeURIComponent(JSON.stringify(scanData)) : ''
wx.redirectTo({ wx.redirectTo({
url: '/pages/treatment-setup/treatment-setup?regions=' + mask + pdParam url: '/pages/treatment-setup/treatment-setup?regions=' + mask + param
}) })
} }
}) })
+16 -10
查看文件
@@ -1,8 +1,8 @@
<view class="page"> <view class="page">
<view class="page-header page-header-pink" style="padding-top: {{statusBarHeight + 24}}px;"> <view class="page-header page-header-pink" style="padding-top: {{statusBarHeight + 24}}px;">
<view class="nav-back" bindtap="onBack"> 返回</view> <view class="nav-back" bindtap="onBack"> 返回</view>
<view class="page-header-title">区域扫描</view> <view class="page-header-title">多光谱扫描</view>
<view class="page-header-subtitle">{{scanning ? '正在采集数据...' : '扫描完成'}}</view> <view class="page-header-subtitle">{{scanning ? '正在采集数据 (' + spectrumIndex + '/4)...' : '扫描完成'}}</view>
</view> </view>
<view class="page-content"> <view class="page-content">
@@ -13,17 +13,19 @@
<view class="scan-progress-bar"> <view class="scan-progress-bar">
<view class="scan-progress-fill" style="width: {{scanProgress}}%"></view> <view class="scan-progress-fill" style="width: {{scanProgress}}%"></view>
</view> </view>
<view class="scan-status">全域LED已开启,亮度 128,等待PD数据回传...</view> <view class="scan-status">固件序贯扫描中:红光 → 紫外光 → 黄光 → 红外光</view>
</view> </view>
<view class="scan-result" wx:if="{{!scanning && pdValues.length > 0}}"> <view class="scan-result" wx:if="{{!scanning && spectrumData.length > 0}}">
<view class="result-title">PD 采集结果</view> <view class="spectrum-group" wx:for="{{spectrumData}}" wx:key="name">
<view class="spectrum-title">{{item.name}} (第{{index + 1}}组)</view>
<view class="pd-list"> <view class="pd-list">
<view class="pd-item" wx:for="{{pdValues}}" wx:key="region"> <view class="pd-item" wx:for="{{item.items}}" wx:for-item="pd" wx:key="label">
<view class="pd-region">{{item.region}}</view> <view class="pd-region">{{pd.label}}</view>
<view class="pd-value {{item.pd > 0 ? '' : 'pd-empty'}}">{{item.pdText}}</view> <view class="pd-value">{{pd.value}}</view>
<view class="pd-bar-bg" wx:if="{{item.pd > 0}}"> <view class="pd-bar-bg" wx:if="{{pd.value > 0}}">
<view class="pd-bar-fill" style="width: {{item.barWidth}}%"></view> <view class="pd-bar-fill" style="width: {{pd.barWidth}}%"></view>
</view>
</view> </view>
</view> </view>
</view> </view>
@@ -32,6 +34,10 @@
</view> </view>
</view> </view>
<view class="scan-result" wx:if="{{!scanning && spectrumData.length === 0 && !error}}">
<view class="empty-hint">未收到扫描数据</view>
</view>
<view class="scan-error" wx:if="{{!scanning && error}}">{{error}}</view> <view class="scan-error" wx:if="{{!scanning && error}}">{{error}}</view>
<button class="btn-primary mt-30" wx:if="{{!scanning}}" bindtap="onNext">下一步</button> <button class="btn-primary mt-30" wx:if="{{!scanning}}" bindtap="onNext">下一步</button>
@@ -121,6 +121,30 @@
text-align: center; text-align: center;
} }
.spectrum-group {
margin-bottom: 24rpx;
}
.spectrum-group:last-child {
margin-bottom: 0;
}
.spectrum-title {
font-size: 26rpx;
font-weight: 600;
color: #E6508C;
margin-bottom: 12rpx;
padding-bottom: 8rpx;
border-bottom: 2rpx solid #fdf2f8;
}
.empty-hint {
text-align: center;
color: #999;
font-size: 26rpx;
padding: 40rpx 0;
}
.scan-error { .scan-error {
text-align: center; text-align: center;
color: #ff4d4f; color: #ff4d4f;