taro-bluetooth-print 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +17 -1
- package/dist/bluetooth/index.d.ts +607 -2
- package/dist/bluetooth/index.js +2854 -94
- package/dist/bluetooth/index.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +28 -1
- package/dist/index.js.map +1 -1
- package/dist/printer/index.d.ts +1 -0
- package/dist/printer/index.js +36 -0
- package/dist/printer/index.js.map +1 -1
- package/dist/types/index.d.ts +113 -7
- package/dist/types/index.js +16 -8
- package/dist/types/index.js.map +1 -1
- package/dist/utils/events.d.ts +41 -11
- package/dist/utils/events.js +41 -7
- package/dist/utils/events.js.map +1 -1
- package/package.json +1 -1
package/dist/bluetooth/index.js
CHANGED
|
@@ -1,4 +1,49 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file Bluetooth Manager
|
|
4
|
+
* @description 蓝牙管理模块,提供蓝牙设备发现、连接、数据传输等功能
|
|
5
|
+
*
|
|
6
|
+
* @update 更新日志
|
|
7
|
+
*
|
|
8
|
+
* ## 2025-03-13
|
|
9
|
+
* ### 新增功能
|
|
10
|
+
* - 增加性能优化配置系统
|
|
11
|
+
* - 可配置缓冲池大小和策略
|
|
12
|
+
* - 支持自定义性能参数
|
|
13
|
+
* - 提供性能监控和统计
|
|
14
|
+
* - 增强缓存管理
|
|
15
|
+
* - 设备信息智能缓存
|
|
16
|
+
* - 缓冲区对象池
|
|
17
|
+
* - 自适应缓存优化
|
|
18
|
+
* - 改进数据传输
|
|
19
|
+
* - 智能分片策略
|
|
20
|
+
* - 缓冲区复用机制
|
|
21
|
+
* - 批量写入优化
|
|
22
|
+
*
|
|
23
|
+
* ### 性能优化
|
|
24
|
+
* - 内存管理优化
|
|
25
|
+
* - 引入垃圾回收机制
|
|
26
|
+
* - 内存使用监控
|
|
27
|
+
* - 资源自动释放
|
|
28
|
+
* - 传输性能优化
|
|
29
|
+
* - 动态调整传输参数
|
|
30
|
+
* - 性能数据分析
|
|
31
|
+
* - 自动优化策略
|
|
32
|
+
*
|
|
33
|
+
* ### 监控与诊断
|
|
34
|
+
* - 增强性能监控
|
|
35
|
+
* - 详细性能指标统计
|
|
36
|
+
* - 稳定性评分系统
|
|
37
|
+
* - 错误模式分析
|
|
38
|
+
* - 改进诊断工具
|
|
39
|
+
* - 内存使用分析
|
|
40
|
+
* - 性能瓶颈检测
|
|
41
|
+
* - 自动优化建议
|
|
42
|
+
*
|
|
43
|
+
* @version 2.0.0
|
|
44
|
+
* @author Your Name
|
|
45
|
+
* @copyright 2025
|
|
46
|
+
*/
|
|
2
47
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
48
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
49
|
};
|
|
@@ -8,27 +53,356 @@ const adapter_1 = require("./adapter");
|
|
|
8
53
|
const logger_1 = require("../utils/logger");
|
|
9
54
|
const events_1 = require("../utils/events");
|
|
10
55
|
const config_1 = require("../utils/config");
|
|
11
|
-
const types_1 = require("../types");
|
|
12
56
|
const taro_1 = __importDefault(require("@tarojs/taro"));
|
|
57
|
+
const types_1 = require("../types");
|
|
58
|
+
// 扩展 ErrorCode
|
|
59
|
+
const ExtendedErrorCode = Object.assign(Object.assign({}, types_1.ErrorCode), { COMMAND_QUEUE_FULL: 'COMMAND_QUEUE_FULL', COMMAND_FAILED: 'COMMAND_FAILED', QUEUE_CLEARED: 'QUEUE_CLEARED' });
|
|
13
60
|
/**
|
|
14
61
|
* 蓝牙管理器类
|
|
15
62
|
* 负责蓝牙设备的扫描、连接和通信
|
|
16
63
|
*/
|
|
17
64
|
class BluetoothManager {
|
|
65
|
+
// 加载设备历史记录
|
|
66
|
+
loadConnectionHistory() {
|
|
67
|
+
try {
|
|
68
|
+
const historyData = taro_1.default.getStorageSync('bluetooth_connection_history');
|
|
69
|
+
if (historyData) {
|
|
70
|
+
const history = JSON.parse(historyData);
|
|
71
|
+
if (Array.isArray(history)) {
|
|
72
|
+
history.forEach(device => {
|
|
73
|
+
if (device && device.deviceId) {
|
|
74
|
+
this.connectionHistory.set(device.deviceId, device);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
logger_1.logger.debug(`已加载${this.connectionHistory.size}条设备历史记录`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
logger_1.logger.warn('加载设备历史记录失败', error);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// 保存设备历史记录
|
|
86
|
+
saveConnectionHistory() {
|
|
87
|
+
try {
|
|
88
|
+
const history = Array.from(this.connectionHistory.values());
|
|
89
|
+
taro_1.default.setStorageSync('bluetooth_connection_history', JSON.stringify(history));
|
|
90
|
+
logger_1.logger.debug(`已保存${history.length}条设备历史记录`);
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
logger_1.logger.warn('保存设备历史记录失败', error);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// 更新设备连接历史
|
|
97
|
+
updateConnectionHistory(deviceId, success, device) {
|
|
98
|
+
if (!deviceId)
|
|
99
|
+
return;
|
|
100
|
+
const now = Date.now();
|
|
101
|
+
const historyEntry = this.connectionHistory.get(deviceId) || {
|
|
102
|
+
deviceId,
|
|
103
|
+
lastConnected: now,
|
|
104
|
+
connectCount: 0,
|
|
105
|
+
successRate: 1.0,
|
|
106
|
+
favorite: false
|
|
107
|
+
};
|
|
108
|
+
// 更新设备名称
|
|
109
|
+
if (device === null || device === void 0 ? void 0 : device.name) {
|
|
110
|
+
historyEntry.name = device.name;
|
|
111
|
+
}
|
|
112
|
+
// 更新连接次数和成功率
|
|
113
|
+
historyEntry.connectCount++;
|
|
114
|
+
if (success) {
|
|
115
|
+
historyEntry.lastConnected = now;
|
|
116
|
+
historyEntry.successRate = (historyEntry.successRate * (historyEntry.connectCount - 1) + 1) / historyEntry.connectCount;
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
historyEntry.successRate = (historyEntry.successRate * (historyEntry.connectCount - 1)) / historyEntry.connectCount;
|
|
120
|
+
}
|
|
121
|
+
// 限制历史记录的数量
|
|
122
|
+
if (this.connectionHistory.size > 10) {
|
|
123
|
+
// 如果超过10条,删除最旧的非收藏设备
|
|
124
|
+
let oldestId = null;
|
|
125
|
+
let oldestTime = now;
|
|
126
|
+
this.connectionHistory.forEach((entry, id) => {
|
|
127
|
+
if (!entry.favorite && entry.lastConnected < oldestTime) {
|
|
128
|
+
oldestTime = entry.lastConnected;
|
|
129
|
+
oldestId = id;
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
if (oldestId) {
|
|
133
|
+
this.connectionHistory.delete(oldestId);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// 保存更新后的记录
|
|
137
|
+
this.connectionHistory.set(deviceId, historyEntry);
|
|
138
|
+
this.saveConnectionHistory();
|
|
139
|
+
}
|
|
18
140
|
/**
|
|
19
141
|
* 创建蓝牙管理器实例
|
|
20
142
|
*/
|
|
21
143
|
constructor() {
|
|
22
144
|
this.isInitialized = false;
|
|
23
|
-
this.connectedDeviceId = null;
|
|
24
145
|
this.discoveryStarted = false;
|
|
25
|
-
this.
|
|
26
|
-
// 蓝牙服务UUID,用于打印机
|
|
146
|
+
this.connectedDeviceId = null;
|
|
27
147
|
this.serviceUUID = '49535343-FE7D-4AE5-8FA9-9FAFD205E455';
|
|
28
|
-
// 蓝牙特征值UUID,用于写入数据
|
|
29
148
|
this.characteristicUUID = '49535343-8841-43F4-A8D4-ECBE34729BB3';
|
|
149
|
+
this.commandQueue = [];
|
|
150
|
+
this.isProcessingQueue = false;
|
|
151
|
+
this.discoveredDevices = new Map();
|
|
152
|
+
this.transmissionStats = {
|
|
153
|
+
totalBytes: 0,
|
|
154
|
+
successfulBytes: 0,
|
|
155
|
+
totalCommands: 0,
|
|
156
|
+
successfulCommands: 0,
|
|
157
|
+
retryCount: 0,
|
|
158
|
+
startTime: 0,
|
|
159
|
+
endTime: 0,
|
|
160
|
+
lastTransmissionSpeed: 0
|
|
161
|
+
};
|
|
162
|
+
// 性能配置
|
|
163
|
+
this.performanceConfig = {
|
|
164
|
+
// 缓冲池配置
|
|
165
|
+
bufferPoolSize: 32,
|
|
166
|
+
maxBufferSize: 1024 * 1024,
|
|
167
|
+
minBufferSize: 512,
|
|
168
|
+
bufferSizes: [20, 64, 256, 1024],
|
|
169
|
+
// 命令处理配置
|
|
170
|
+
maxBatchSize: 20,
|
|
171
|
+
commandBatchSize: 10,
|
|
172
|
+
maxParallelCommands: 3,
|
|
173
|
+
commandTimeout: 5000,
|
|
174
|
+
maxRetries: 3,
|
|
175
|
+
retryDelay: 100,
|
|
176
|
+
// 内存使用优化
|
|
177
|
+
maxCacheSize: 50,
|
|
178
|
+
cacheTimeout: 60000,
|
|
179
|
+
gcInterval: 300000,
|
|
180
|
+
eventHistoryTrimSize: 50,
|
|
181
|
+
deviceCacheLifetime: 300000,
|
|
182
|
+
// 资源使用优化
|
|
183
|
+
maxConcurrentOperations: 5,
|
|
184
|
+
operationTimeout: 10000,
|
|
185
|
+
idleTimeout: 30000,
|
|
186
|
+
inactiveResourceTimeout: 120000
|
|
187
|
+
};
|
|
188
|
+
this.autoReconnect = false;
|
|
189
|
+
this.reconnectTimer = null;
|
|
190
|
+
this.reconnectAttempts = 0;
|
|
191
|
+
this.maxReconnectAttempts = 3;
|
|
192
|
+
this.reconnectDelay = 5000; // 5秒
|
|
193
|
+
this.currentRecoveryDelay = 1000; // 1秒
|
|
194
|
+
this.recoveryTimer = null;
|
|
195
|
+
this.lastConnectedDevice = null;
|
|
196
|
+
this.batteryCheckInterval = null;
|
|
197
|
+
// 流量控制参数,会根据传输成功率自动调整
|
|
198
|
+
this.flowControl = {
|
|
199
|
+
// 当前分片大小 (字节)
|
|
200
|
+
chunkSize: 20,
|
|
201
|
+
// 分片间延迟 (毫秒)
|
|
202
|
+
chunkDelay: 20,
|
|
203
|
+
// 命令间延迟 (毫秒)
|
|
204
|
+
commandDelay: 50,
|
|
205
|
+
// 自动调整速度
|
|
206
|
+
autoAdjust: true,
|
|
207
|
+
// 最小分片延迟
|
|
208
|
+
minChunkDelay: 5,
|
|
209
|
+
// 最大分片延迟
|
|
210
|
+
maxChunkDelay: 100,
|
|
211
|
+
// 最小分片大小
|
|
212
|
+
minChunkSize: 10,
|
|
213
|
+
// 最大分片大小
|
|
214
|
+
maxChunkSize: 200,
|
|
215
|
+
// 传输质量阈值(用于智能调整参数)
|
|
216
|
+
qualityThreshold: 0.95,
|
|
217
|
+
// 上次传输质量(成功率)
|
|
218
|
+
lastQuality: 1.0
|
|
219
|
+
};
|
|
220
|
+
// 设备连接历史管理
|
|
221
|
+
this.connectionHistory = new Map();
|
|
222
|
+
this.connectionQualityInterval = null;
|
|
223
|
+
this.QUALITY_CHECK_INTERVAL = 10000; // 10秒
|
|
224
|
+
this.qualityCheckInterval = this.QUALITY_CHECK_INTERVAL;
|
|
225
|
+
this.RSSI_WARNING_THRESHOLD = -80; // dBm
|
|
226
|
+
this.QUALITY_WARNING_THRESHOLD = 0.8;
|
|
227
|
+
this.recoveryAttempts = 0;
|
|
228
|
+
this.MAX_RECOVERY_ATTEMPTS = 3;
|
|
229
|
+
this.RECOVERY_DELAY = 1000; // 1秒
|
|
230
|
+
this.lastKnownState = null;
|
|
231
|
+
// 在类的属性定义部分添加新的计数器
|
|
232
|
+
this.connectionStartTime = 0;
|
|
233
|
+
this.flowControlAdjustments = 0;
|
|
234
|
+
this.lastFlowControlAdjustment = 0;
|
|
235
|
+
this.lastReconnectTime = 0;
|
|
236
|
+
this.queuePaused = false;
|
|
237
|
+
this.queueProcessTimer = null;
|
|
238
|
+
this.QUEUE_PROCESS_INTERVAL = 50; // 毫秒
|
|
239
|
+
this.QUEUE_MAX_SIZE = 100;
|
|
240
|
+
this.DEFAULT_COMMAND_PRIORITY = 5;
|
|
241
|
+
this.HIGH_PRIORITY = 10;
|
|
242
|
+
this.LOW_PRIORITY = 1;
|
|
243
|
+
/**
|
|
244
|
+
* 设置连接保活
|
|
245
|
+
* 定期发送探测命令保持连接活跃
|
|
246
|
+
* @param enable 是否启用
|
|
247
|
+
* @param interval 间隔时间(毫秒)
|
|
248
|
+
*/
|
|
249
|
+
this.keepAliveInterval = null;
|
|
250
|
+
// 电源管理选项
|
|
251
|
+
this.powerSavingEnabled = false;
|
|
252
|
+
this.powerSavingMode = 'balanced';
|
|
253
|
+
this.inactivityTimer = null;
|
|
254
|
+
this.DEFAULT_INACTIVITY_TIMEOUT = 60000; // 60秒不活动后进入节能模式
|
|
255
|
+
this.inactivityTimeout = this.DEFAULT_INACTIVITY_TIMEOUT;
|
|
256
|
+
this.lastActivityTime = Date.now();
|
|
257
|
+
this.batteryCheckIntervalMs = 30000; // 30秒
|
|
258
|
+
// 调试模式设置
|
|
259
|
+
this.debugMode = false;
|
|
260
|
+
this.debugLogEnabled = false;
|
|
261
|
+
this.debugEvents = [];
|
|
262
|
+
this.MAX_DEBUG_EVENTS = 100;
|
|
263
|
+
// 缓冲区池,用于减少内存分配
|
|
264
|
+
this.bufferPool = new Map();
|
|
265
|
+
// 设备信息缓存
|
|
266
|
+
this.deviceInfoCache = new Map();
|
|
267
|
+
// 连接状态缓存
|
|
268
|
+
this.connectionStateCache = {
|
|
269
|
+
isConnected: false,
|
|
270
|
+
lastStateChangeTime: 0,
|
|
271
|
+
consecutiveErrorCount: 0,
|
|
272
|
+
lastCommandTime: 0,
|
|
273
|
+
lastSuccessTime: 0
|
|
274
|
+
};
|
|
275
|
+
// 统计聚合器
|
|
276
|
+
this.statsAggregator = {
|
|
277
|
+
writeTimes: [],
|
|
278
|
+
readTimes: [],
|
|
279
|
+
discoverTimes: [],
|
|
280
|
+
connectTimes: [],
|
|
281
|
+
errorCounts: new Map()
|
|
282
|
+
};
|
|
283
|
+
// 性能监控计时器
|
|
284
|
+
this.performanceMonitorInterval = null;
|
|
30
285
|
this.adapter = (0, adapter_1.getAdapter)();
|
|
31
286
|
logger_1.logger.debug('蓝牙管理器已创建');
|
|
287
|
+
// 监听蓝牙状态变化
|
|
288
|
+
this.setupConnectionStateListener();
|
|
289
|
+
// 加载设备历史记录
|
|
290
|
+
this.loadConnectionHistory();
|
|
291
|
+
// 初始化性能优化系统
|
|
292
|
+
this.initPerformanceOptimizations();
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* 设置连接状态监听
|
|
296
|
+
* 用于检测意外断开并自动重连
|
|
297
|
+
*/
|
|
298
|
+
setupConnectionStateListener() {
|
|
299
|
+
try {
|
|
300
|
+
// 尝试注册连接状态变化监听
|
|
301
|
+
taro_1.default.onBLEConnectionStateChange(res => {
|
|
302
|
+
const { deviceId, connected } = res;
|
|
303
|
+
if (!connected && deviceId === this.connectedDeviceId) {
|
|
304
|
+
// 设备意外断开
|
|
305
|
+
logger_1.logger.warn(`设备连接意外断开: ${deviceId}`);
|
|
306
|
+
this.connectedDeviceId = null;
|
|
307
|
+
// 触发断开连接事件
|
|
308
|
+
events_1.eventManager.emit(events_1.EVENTS.BLUETOOTH_DISCONNECTED, {
|
|
309
|
+
deviceId,
|
|
310
|
+
unexpected: true
|
|
311
|
+
});
|
|
312
|
+
// 尝试恢复连接
|
|
313
|
+
this.attemptRecovery().catch(err => {
|
|
314
|
+
logger_1.logger.error('恢复连接失败', err);
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
else if (connected && deviceId === this.lastConnectedDevice) {
|
|
318
|
+
// 恢复连接
|
|
319
|
+
logger_1.logger.info(`设备连接已恢复: ${deviceId}`);
|
|
320
|
+
this.connectedDeviceId = deviceId;
|
|
321
|
+
this.resetRecoveryState();
|
|
322
|
+
// 恢复之前的状态
|
|
323
|
+
this.restoreState().catch(err => {
|
|
324
|
+
logger_1.logger.warn('状态恢复失败', err);
|
|
325
|
+
});
|
|
326
|
+
// 触发连接成功事件
|
|
327
|
+
events_1.eventManager.emit(events_1.EVENTS.BLUETOOTH_CONNECTED, {
|
|
328
|
+
deviceId,
|
|
329
|
+
reconnected: true
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
logger_1.logger.debug('已设置蓝牙连接状态监听');
|
|
334
|
+
}
|
|
335
|
+
catch (error) {
|
|
336
|
+
logger_1.logger.warn('设置蓝牙连接状态监听失败,可能不支持此功能', error);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* 安排自动重连
|
|
341
|
+
*/
|
|
342
|
+
scheduleReconnect() {
|
|
343
|
+
if (this.reconnectTimer) {
|
|
344
|
+
clearTimeout(this.reconnectTimer);
|
|
345
|
+
}
|
|
346
|
+
if (this.reconnectAttempts >= this.maxReconnectAttempts || !this.lastConnectedDevice) {
|
|
347
|
+
logger_1.logger.warn(`已达到最大重连次数(${this.maxReconnectAttempts})或没有可重连的设备`);
|
|
348
|
+
this.resetReconnectState();
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
this.reconnectAttempts++;
|
|
352
|
+
// 延迟重连,避免频繁尝试
|
|
353
|
+
const delay = this.reconnectDelay * this.reconnectAttempts; // 逐次增加延迟
|
|
354
|
+
logger_1.logger.info(`计划在${delay}ms后进行第${this.reconnectAttempts}次重连`);
|
|
355
|
+
this.reconnectTimer = setTimeout(async () => {
|
|
356
|
+
if (!this.isConnected() && this.lastConnectedDevice) {
|
|
357
|
+
logger_1.logger.info(`尝试重新连接到设备: ${this.lastConnectedDevice}(第${this.reconnectAttempts}次)`);
|
|
358
|
+
try {
|
|
359
|
+
const result = await this.connect(this.lastConnectedDevice, {
|
|
360
|
+
retries: 0,
|
|
361
|
+
timeout: 10000 // 加长超时时间
|
|
362
|
+
});
|
|
363
|
+
if (result) {
|
|
364
|
+
logger_1.logger.info(`重连成功: ${this.lastConnectedDevice}`);
|
|
365
|
+
this.resetReconnectState();
|
|
366
|
+
}
|
|
367
|
+
else {
|
|
368
|
+
logger_1.logger.warn(`重连失败: ${this.lastConnectedDevice}`);
|
|
369
|
+
this.scheduleReconnect(); // 安排下一次重连
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
catch (error) {
|
|
373
|
+
logger_1.logger.error(`重连出错: ${this.lastConnectedDevice}`, error);
|
|
374
|
+
this.scheduleReconnect(); // 安排下一次重连
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
else {
|
|
378
|
+
this.resetReconnectState();
|
|
379
|
+
}
|
|
380
|
+
}, delay);
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* 重置重连状态
|
|
384
|
+
*/
|
|
385
|
+
resetReconnectState() {
|
|
386
|
+
if (this.reconnectTimer) {
|
|
387
|
+
clearTimeout(this.reconnectTimer);
|
|
388
|
+
this.reconnectTimer = null;
|
|
389
|
+
}
|
|
390
|
+
this.reconnectAttempts = 0;
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* 启用自动重连
|
|
394
|
+
* @param enable 是否启用
|
|
395
|
+
* @param maxAttempts 最大尝试次数
|
|
396
|
+
* @param delay 初始延迟(毫秒)
|
|
397
|
+
*/
|
|
398
|
+
setAutoReconnect(enable, maxAttempts = 3, delay = 5000) {
|
|
399
|
+
this.autoReconnect = enable;
|
|
400
|
+
this.maxReconnectAttempts = maxAttempts;
|
|
401
|
+
this.reconnectDelay = delay;
|
|
402
|
+
logger_1.logger.debug(`${enable ? '启用' : '禁用'}自动重连,最大尝试次数: ${maxAttempts},初始延迟: ${delay}ms`);
|
|
403
|
+
if (!enable) {
|
|
404
|
+
this.resetReconnectState();
|
|
405
|
+
}
|
|
32
406
|
}
|
|
33
407
|
/**
|
|
34
408
|
* 初始化蓝牙模块
|
|
@@ -77,7 +451,11 @@ class BluetoothManager {
|
|
|
77
451
|
const finalOptions = {
|
|
78
452
|
timeout: options.timeout || config_1.BLUETOOTH_DEFAULTS.SCAN_TIMEOUT,
|
|
79
453
|
services: options.services || ['1812'],
|
|
80
|
-
allowDuplicatesKey: options.allowDuplicatesKey || false
|
|
454
|
+
allowDuplicatesKey: options.allowDuplicatesKey || false,
|
|
455
|
+
namePrefix: options.namePrefix || '',
|
|
456
|
+
filterByName: options.filterByName || false,
|
|
457
|
+
namePrefixes: options.namePrefixes || [],
|
|
458
|
+
onlyPrinters: options.onlyPrinters || false
|
|
81
459
|
};
|
|
82
460
|
try {
|
|
83
461
|
logger_1.logger.debug('开始搜索蓝牙设备...', finalOptions);
|
|
@@ -92,6 +470,13 @@ class BluetoothManager {
|
|
|
92
470
|
taro_1.default.onBluetoothDeviceFound(res => {
|
|
93
471
|
const devices = res.devices || [];
|
|
94
472
|
devices.forEach(device => {
|
|
473
|
+
// 过滤设备
|
|
474
|
+
if (this.shouldFilterDevice(device, finalOptions)) {
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
// 处理设备名称
|
|
478
|
+
this.processDeviceName(device);
|
|
479
|
+
// 添加到设备列表
|
|
95
480
|
this.discoveredDevices.set(device.deviceId, device);
|
|
96
481
|
// 触发设备发现事件
|
|
97
482
|
events_1.eventManager.emit(events_1.EVENTS.BLUETOOTH_DEVICE_FOUND, device);
|
|
@@ -123,6 +508,64 @@ class BluetoothManager {
|
|
|
123
508
|
return false;
|
|
124
509
|
}
|
|
125
510
|
}
|
|
511
|
+
/**
|
|
512
|
+
* 判断设备是否应该被过滤掉
|
|
513
|
+
* @param device 设备信息
|
|
514
|
+
* @param options 搜索选项
|
|
515
|
+
*/
|
|
516
|
+
shouldFilterDevice(device, options) {
|
|
517
|
+
var _a, _b, _c;
|
|
518
|
+
// 设备名称前缀过滤
|
|
519
|
+
if (options.filterByName && device.name) {
|
|
520
|
+
// 单个前缀匹配
|
|
521
|
+
if (options.namePrefix && device.name.indexOf(options.namePrefix) !== 0) {
|
|
522
|
+
return true;
|
|
523
|
+
}
|
|
524
|
+
// 多个前缀匹配(任一匹配即可)
|
|
525
|
+
if (options.namePrefixes && options.namePrefixes.length > 0) {
|
|
526
|
+
const matchesAnyPrefix = options.namePrefixes.some(prefix => device.name && device.name.indexOf(prefix) === 0);
|
|
527
|
+
if (!matchesAnyPrefix) {
|
|
528
|
+
return true;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
// 打印机设备过滤(需要符合打印机设备特征)
|
|
533
|
+
if (options.onlyPrinters) {
|
|
534
|
+
// 检查设备名称是否包含常见打印机标识
|
|
535
|
+
const commonPrinterKeywords = [
|
|
536
|
+
'print', 'prt', 'pos', 'tsc', 'gprinter', 'epson',
|
|
537
|
+
'star', 'zicox', 'hprt', 'sprt', 'zebra', 'iprint'
|
|
538
|
+
];
|
|
539
|
+
const lowerName = ((_a = device.name) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || '';
|
|
540
|
+
const hasPrinterKeyword = commonPrinterKeywords.some(keyword => lowerName.includes(keyword));
|
|
541
|
+
// 检查设备服务是否包含打印服务
|
|
542
|
+
const hasPrintService = ((_b = device.advertisServiceUUIDs) === null || _b === void 0 ? void 0 : _b.some((id) => id.toLowerCase().includes('18f0'))) ||
|
|
543
|
+
((_c = device.advertisServiceUUIDs) === null || _c === void 0 ? void 0 : _c.some((id) => id.toLowerCase().includes('1812')));
|
|
544
|
+
if (!hasPrinterKeyword && !hasPrintService) {
|
|
545
|
+
return true;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
return false;
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* 处理设备名称
|
|
552
|
+
* 有些设备名称是乱码或空,尝试修复或使用替代名称
|
|
553
|
+
*/
|
|
554
|
+
processDeviceName(device) {
|
|
555
|
+
// 如果没有名称,尝试使用设备ID的最后6位作为名称
|
|
556
|
+
if (!device.name) {
|
|
557
|
+
device.name = `未命名设备 (${device.deviceId.slice(-6)})`;
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
// 检测名称是否可能是乱码
|
|
561
|
+
const hasNonPrintableChars = /[^\x20-\x7E\u4e00-\u9fa5]/.test(device.name);
|
|
562
|
+
const isTooShort = device.name.length < 2;
|
|
563
|
+
if (hasNonPrintableChars || isTooShort) {
|
|
564
|
+
// 如果可能是乱码,使用设备ID作为替代
|
|
565
|
+
device.originalName = device.name; // 保留原始名称
|
|
566
|
+
device.name = `设备 ${device.deviceId.slice(-6)}`;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
126
569
|
/**
|
|
127
570
|
* 停止搜索蓝牙设备
|
|
128
571
|
*/
|
|
@@ -170,100 +613,44 @@ class BluetoothManager {
|
|
|
170
613
|
* @param options 连接选项
|
|
171
614
|
*/
|
|
172
615
|
async connect(deviceId, options = {}) {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
const error = new types_1.PrinterError(types_1.ErrorCode.INVALID_PARAM, '连接失败: 设备ID不能为空');
|
|
177
|
-
logger_1.logger.error(error.message);
|
|
178
|
-
events_1.eventManager.emit(events_1.EVENTS.BLUETOOTH_ERROR, error);
|
|
179
|
-
return false;
|
|
180
|
-
}
|
|
181
|
-
// 默认选项
|
|
182
|
-
const retries = (_a = options.retries) !== null && _a !== void 0 ? _a : config_1.BLUETOOTH_DEFAULTS.CONNECT_RETRIES;
|
|
183
|
-
const timeout = (_b = options.timeout) !== null && _b !== void 0 ? _b : config_1.BLUETOOTH_DEFAULTS.CONNECT_TIMEOUT;
|
|
184
|
-
// 确保蓝牙已初始化
|
|
185
|
-
if (!this.isInitialized) {
|
|
186
|
-
await this.init();
|
|
187
|
-
}
|
|
188
|
-
// 如果已连接,先断开
|
|
189
|
-
if (this.connectedDeviceId && this.connectedDeviceId !== deviceId) {
|
|
190
|
-
await this.disconnect();
|
|
191
|
-
}
|
|
192
|
-
else if (this.connectedDeviceId === deviceId) {
|
|
193
|
-
// 已经连接到相同设备
|
|
194
|
-
logger_1.logger.info(`已连接到设备: ${deviceId}`);
|
|
195
|
-
return true;
|
|
196
|
-
}
|
|
197
|
-
// 添加重试逻辑
|
|
198
|
-
let lastError = null;
|
|
199
|
-
for (let i = 0; i <= retries; i++) {
|
|
200
|
-
try {
|
|
201
|
-
// 添加超时控制
|
|
202
|
-
const connectPromise = this.adapter.connect(deviceId);
|
|
203
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
204
|
-
setTimeout(() => reject(new types_1.PrinterError(types_1.ErrorCode.TIMEOUT_ERROR, `连接超时 (${timeout}ms)`)), timeout);
|
|
205
|
-
});
|
|
206
|
-
// 使用Promise.race实现超时控制
|
|
207
|
-
const result = await Promise.race([connectPromise, timeoutPromise]);
|
|
208
|
-
if (result) {
|
|
209
|
-
this.connectedDeviceId = deviceId;
|
|
210
|
-
const message = `成功连接到设备: ${deviceId}${i > 0 ? ` (重试 ${i} 次)` : ''}`;
|
|
211
|
-
logger_1.logger.info(message);
|
|
212
|
-
// 触发连接成功事件
|
|
213
|
-
events_1.eventManager.emit(events_1.EVENTS.BLUETOOTH_CONNECTED, {
|
|
214
|
-
deviceId,
|
|
215
|
-
retryCount: i
|
|
216
|
-
});
|
|
217
|
-
return true;
|
|
218
|
-
}
|
|
616
|
+
try {
|
|
617
|
+
if (!this.adapter) {
|
|
618
|
+
throw new Error('蓝牙适配器未初始化');
|
|
219
619
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
// 等待1秒再重试
|
|
227
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
228
|
-
}
|
|
620
|
+
const result = await this.adapter.connect(deviceId);
|
|
621
|
+
if (result) {
|
|
622
|
+
this.connectedDeviceId = deviceId;
|
|
623
|
+
this.connectionStartTime = Date.now();
|
|
624
|
+
this.updateConnectionHistory(deviceId, true);
|
|
625
|
+
events_1.eventManager.emit(events_1.EVENTS.BLUETOOTH_CONNECTED, { deviceId });
|
|
229
626
|
}
|
|
627
|
+
return result;
|
|
628
|
+
}
|
|
629
|
+
catch (error) {
|
|
630
|
+
logger_1.logger.error('连接设备失败:', error);
|
|
631
|
+
this.updateConnectionHistory(deviceId, false);
|
|
632
|
+
events_1.eventManager.emit(events_1.EVENTS.BLUETOOTH_CONNECTION_FAILED, { deviceId, error });
|
|
633
|
+
return false;
|
|
230
634
|
}
|
|
231
|
-
// 所有重试都失败
|
|
232
|
-
const printerError = new types_1.PrinterError(types_1.ErrorCode.BLUETOOTH_CONNECT_FAILED, `连接蓝牙设备失败,已重试 ${retries} 次`);
|
|
233
|
-
logger_1.logger.error(printerError.message, lastError);
|
|
234
|
-
// 触发错误事件
|
|
235
|
-
events_1.eventManager.emit(events_1.EVENTS.BLUETOOTH_ERROR, printerError);
|
|
236
|
-
return false;
|
|
237
635
|
}
|
|
238
636
|
/**
|
|
239
637
|
* 断开蓝牙连接
|
|
240
638
|
*/
|
|
241
639
|
async disconnect() {
|
|
242
|
-
if (!this.connectedDeviceId) {
|
|
243
|
-
return true;
|
|
244
|
-
}
|
|
245
|
-
const deviceId = this.connectedDeviceId;
|
|
246
640
|
try {
|
|
247
|
-
|
|
248
|
-
|
|
641
|
+
if (!this.adapter || !this.connectedDeviceId) {
|
|
642
|
+
return true;
|
|
643
|
+
}
|
|
644
|
+
const result = await this.adapter.disconnect(this.connectedDeviceId);
|
|
249
645
|
if (result) {
|
|
646
|
+
this.lastConnectedDevice = this.connectedDeviceId;
|
|
250
647
|
this.connectedDeviceId = null;
|
|
251
|
-
|
|
252
|
-
// 触发断开连接事件
|
|
253
|
-
events_1.eventManager.emit(events_1.EVENTS.BLUETOOTH_DISCONNECTED, { deviceId });
|
|
254
|
-
}
|
|
255
|
-
else {
|
|
256
|
-
logger_1.logger.warn(`断开设备连接失败: ${deviceId}`);
|
|
648
|
+
events_1.eventManager.emit(events_1.EVENTS.BLUETOOTH_DISCONNECTED, { deviceId: this.lastConnectedDevice });
|
|
257
649
|
}
|
|
258
650
|
return result;
|
|
259
651
|
}
|
|
260
652
|
catch (error) {
|
|
261
|
-
|
|
262
|
-
logger_1.logger.error(printerError.message, error);
|
|
263
|
-
// 触发错误事件
|
|
264
|
-
events_1.eventManager.emit(events_1.EVENTS.BLUETOOTH_ERROR, printerError);
|
|
265
|
-
// 即使出错,也将连接状态重置为未连接
|
|
266
|
-
this.connectedDeviceId = null;
|
|
653
|
+
logger_1.logger.error('断开连接失败:', error);
|
|
267
654
|
return false;
|
|
268
655
|
}
|
|
269
656
|
}
|
|
@@ -272,25 +659,380 @@ class BluetoothManager {
|
|
|
272
659
|
* @param data 要写入的数据
|
|
273
660
|
*/
|
|
274
661
|
async writeData(data) {
|
|
275
|
-
if (!this.connectedDeviceId) {
|
|
276
|
-
const error = new types_1.PrinterError(types_1.ErrorCode.PRINTER_NOT_CONNECTED, '未连接到蓝牙设备');
|
|
277
|
-
throw error;
|
|
278
|
-
}
|
|
279
662
|
try {
|
|
280
|
-
|
|
663
|
+
if (!this.isConnected() || !this.adapter) {
|
|
664
|
+
throw new Error('设备未连接');
|
|
665
|
+
}
|
|
281
666
|
const result = await this.adapter.write(this.connectedDeviceId, this.serviceUUID, this.characteristicUUID, data);
|
|
282
|
-
if (
|
|
283
|
-
|
|
284
|
-
|
|
667
|
+
if (result) {
|
|
668
|
+
this.transmissionStats.totalBytes += data.byteLength;
|
|
669
|
+
this.transmissionStats.successfulBytes += data.byteLength;
|
|
670
|
+
this.transmissionStats.totalCommands++;
|
|
671
|
+
this.transmissionStats.successfulCommands++;
|
|
672
|
+
this.updateTransmissionStats();
|
|
285
673
|
}
|
|
286
674
|
return result;
|
|
287
675
|
}
|
|
288
676
|
catch (error) {
|
|
289
|
-
|
|
677
|
+
logger_1.logger.error('写入数据失败:', error);
|
|
678
|
+
this.transmissionStats.totalCommands++;
|
|
679
|
+
this.transmissionStats.retryCount++;
|
|
680
|
+
this.updateTransmissionStats();
|
|
681
|
+
return false;
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
* 分块写入数据
|
|
686
|
+
* @param data 要写入的数据
|
|
687
|
+
* @param chunkSize 每块大小
|
|
688
|
+
* @param delayMs 每块之间的延迟时间(ms)
|
|
689
|
+
* @returns 是否全部写入成功
|
|
690
|
+
*/
|
|
691
|
+
async writeDataInChunks(data, chunkSize = 20, delayMs = 20) {
|
|
692
|
+
// 记录开始时间
|
|
693
|
+
const startTime = Date.now();
|
|
694
|
+
const dataView = new Uint8Array(data);
|
|
695
|
+
const totalLength = dataView.length;
|
|
696
|
+
const chunks = Math.ceil(totalLength / chunkSize);
|
|
697
|
+
logger_1.logger.debug(`分片写入数据,总大小: ${totalLength} 字节,分${chunks}片发送`);
|
|
698
|
+
// 用于跟踪写入成功的片段数量
|
|
699
|
+
let successCount = 0;
|
|
700
|
+
let failedChunks = [];
|
|
701
|
+
// 为所有分片预分配缓冲区(如果可能)
|
|
702
|
+
const chunkBuffers = [];
|
|
703
|
+
for (let i = 0; i < chunks; i++) {
|
|
704
|
+
// 只有在合适大小时才使用池缓冲区
|
|
705
|
+
if (chunkSize <= 1024) {
|
|
706
|
+
chunkBuffers.push(this.getBufferFromPool(chunkSize));
|
|
707
|
+
}
|
|
708
|
+
else {
|
|
709
|
+
chunkBuffers.push(new ArrayBuffer(chunkSize));
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
try {
|
|
713
|
+
for (let i = 0; i < chunks; i++) {
|
|
714
|
+
const start = i * chunkSize;
|
|
715
|
+
const end = Math.min(start + chunkSize, totalLength);
|
|
716
|
+
const chunkLength = end - start;
|
|
717
|
+
// 使用预分配的缓冲区
|
|
718
|
+
const chunkBuffer = chunkBuffers[i];
|
|
719
|
+
const chunkView = new Uint8Array(chunkBuffer, 0, chunkLength);
|
|
720
|
+
chunkView.set(dataView.subarray(start, end));
|
|
721
|
+
try {
|
|
722
|
+
const result = await this.adapter.write(this.connectedDeviceId, this.serviceUUID, this.characteristicUUID, chunkBuffer);
|
|
723
|
+
if (result) {
|
|
724
|
+
successCount++;
|
|
725
|
+
}
|
|
726
|
+
else {
|
|
727
|
+
failedChunks.push(i);
|
|
728
|
+
logger_1.logger.warn(`第${i + 1}/${chunks}片数据写入失败`);
|
|
729
|
+
}
|
|
730
|
+
// 添加延迟,避免蓝牙堵塞
|
|
731
|
+
if (i < chunks - 1 && delayMs > 0) {
|
|
732
|
+
await new Promise(resolve => setTimeout(resolve, delayMs));
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
catch (err) {
|
|
736
|
+
failedChunks.push(i);
|
|
737
|
+
logger_1.logger.warn(`第${i + 1}/${chunks}片数据写入出错`, err);
|
|
738
|
+
// 继续处理下一片,不中断整体流程
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
// 重试失败的片段(最多重试一次)
|
|
742
|
+
if (failedChunks.length > 0) {
|
|
743
|
+
logger_1.logger.debug(`尝试重新发送${failedChunks.length}个失败的数据片段`);
|
|
744
|
+
for (const i of failedChunks) {
|
|
745
|
+
const start = i * chunkSize;
|
|
746
|
+
const end = Math.min(start + chunkSize, totalLength);
|
|
747
|
+
const chunkLength = end - start;
|
|
748
|
+
// 使用之前分配的缓冲区
|
|
749
|
+
const chunkBuffer = chunkBuffers[i];
|
|
750
|
+
try {
|
|
751
|
+
const result = await this.adapter.write(this.connectedDeviceId, this.serviceUUID, this.characteristicUUID, chunkBuffer);
|
|
752
|
+
if (result) {
|
|
753
|
+
successCount++;
|
|
754
|
+
// 从失败列表中移除
|
|
755
|
+
failedChunks = failedChunks.filter(idx => idx !== i);
|
|
756
|
+
}
|
|
757
|
+
// 添加更长的延迟进行重试
|
|
758
|
+
await new Promise(resolve => setTimeout(resolve, delayMs * 2));
|
|
759
|
+
}
|
|
760
|
+
catch (err) {
|
|
761
|
+
logger_1.logger.warn(`重试:第${i + 1}/${chunks}片数据写入仍然失败`, err);
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
// 释放所有分片缓冲区回到池
|
|
766
|
+
for (const buffer of chunkBuffers) {
|
|
767
|
+
if (buffer.byteLength <= 1024) {
|
|
768
|
+
this.returnBufferToPool(buffer);
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
const success = successCount === chunks;
|
|
772
|
+
if (!success) {
|
|
773
|
+
logger_1.logger.error(`数据写入不完整,共${chunks}片,成功${successCount}片,失败${failedChunks.length}片`);
|
|
774
|
+
// 触发蓝牙写入不完整事件
|
|
775
|
+
events_1.eventManager.emit(events_1.EVENTS.BLUETOOTH_WRITE_INCOMPLETE, {
|
|
776
|
+
total: chunks,
|
|
777
|
+
success: successCount,
|
|
778
|
+
failed: failedChunks.length
|
|
779
|
+
});
|
|
780
|
+
// 记录错误
|
|
781
|
+
this.recordError('write_chunks_incomplete');
|
|
782
|
+
}
|
|
783
|
+
else {
|
|
784
|
+
logger_1.logger.debug(`数据写入完成,共${chunks}片`);
|
|
785
|
+
this.recordSuccess();
|
|
786
|
+
}
|
|
787
|
+
// 记录操作时间
|
|
788
|
+
this.recordOperationTime('write', Date.now() - startTime);
|
|
789
|
+
return success;
|
|
790
|
+
}
|
|
791
|
+
catch (error) {
|
|
792
|
+
// 释放所有分片缓冲区回到池
|
|
793
|
+
for (const buffer of chunkBuffers) {
|
|
794
|
+
if (buffer.byteLength <= 1024) {
|
|
795
|
+
this.returnBufferToPool(buffer);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
const printerError = new types_1.PrinterError(types_1.ErrorCode.BLUETOOTH_WRITE_FAILED, '分片写入数据失败');
|
|
290
799
|
logger_1.logger.error(printerError.message, error);
|
|
800
|
+
// 触发错误事件
|
|
801
|
+
events_1.eventManager.emit(events_1.EVENTS.BLUETOOTH_ERROR, printerError);
|
|
802
|
+
// 记录错误
|
|
803
|
+
this.recordError('write_chunks_failed');
|
|
291
804
|
throw printerError;
|
|
292
805
|
}
|
|
293
806
|
}
|
|
807
|
+
/**
|
|
808
|
+
* 批量写入多个命令
|
|
809
|
+
* @param commands 命令数组
|
|
810
|
+
* @param options 选项
|
|
811
|
+
*/
|
|
812
|
+
async writeBatch(commands, options = {}) {
|
|
813
|
+
var _a, _b;
|
|
814
|
+
if (!this.isConnected()) {
|
|
815
|
+
throw new types_1.PrinterError(types_1.ErrorCode.PRINTER_NOT_CONNECTED, '未连接到蓝牙设备');
|
|
816
|
+
}
|
|
817
|
+
if (commands.length === 0) {
|
|
818
|
+
return { success: true, failed: 0 };
|
|
819
|
+
}
|
|
820
|
+
// 重置传输统计
|
|
821
|
+
this.resetTransmissionStats();
|
|
822
|
+
// 计算总字节数
|
|
823
|
+
let totalBytes = 0;
|
|
824
|
+
for (const cmd of commands) {
|
|
825
|
+
totalBytes += cmd.byteLength;
|
|
826
|
+
}
|
|
827
|
+
this.transmissionStats.totalBytes = totalBytes;
|
|
828
|
+
this.transmissionStats.totalCommands = commands.length;
|
|
829
|
+
this.transmissionStats.startTime = Date.now();
|
|
830
|
+
logger_1.logger.info(`批量发送${commands.length}条命令,总大小${totalBytes}字节,批处理大小${options.batchSize || this.performanceConfig.commandBatchSize},${options.parallel ? '启用并行' : '串行'}处理`);
|
|
831
|
+
try {
|
|
832
|
+
// 成功和失败计数
|
|
833
|
+
let successCount = 0;
|
|
834
|
+
let successfulBytes = 0;
|
|
835
|
+
if (options.parallel) {
|
|
836
|
+
// 使用有限并行性处理命令
|
|
837
|
+
// 将命令分成多个批次
|
|
838
|
+
const batches = [];
|
|
839
|
+
for (let i = 0; i < commands.length; i += options.batchSize || this.performanceConfig.commandBatchSize) {
|
|
840
|
+
batches.push(commands.slice(i, i + (options.batchSize || this.performanceConfig.commandBatchSize)));
|
|
841
|
+
}
|
|
842
|
+
// 并行处理各批次,但限制最大并行数
|
|
843
|
+
for (let i = 0; i < batches.length; i += options.maxParallel || this.performanceConfig.maxParallelCommands) {
|
|
844
|
+
const currentBatches = batches.slice(i, i + (options.maxParallel || this.performanceConfig.maxParallelCommands));
|
|
845
|
+
// 并行处理当前批次
|
|
846
|
+
const batchPromises = currentBatches.map(async (batch) => {
|
|
847
|
+
var _a;
|
|
848
|
+
const results = [];
|
|
849
|
+
for (const cmd of batch) {
|
|
850
|
+
// 根据命令大小决定是否使用分片
|
|
851
|
+
const useChunks = (_a = options.useChunks) !== null && _a !== void 0 ? _a : (cmd.byteLength > this.flowControl.chunkSize);
|
|
852
|
+
try {
|
|
853
|
+
let result;
|
|
854
|
+
if (useChunks) {
|
|
855
|
+
result = await this.writeDataInChunks(cmd, this.flowControl.chunkSize, this.flowControl.chunkDelay);
|
|
856
|
+
}
|
|
857
|
+
else {
|
|
858
|
+
result = await this.writeData(cmd);
|
|
859
|
+
}
|
|
860
|
+
results.push({ success: result, bytes: cmd.byteLength });
|
|
861
|
+
}
|
|
862
|
+
catch (err) {
|
|
863
|
+
results.push({ success: false, bytes: cmd.byteLength });
|
|
864
|
+
}
|
|
865
|
+
// 每个命令之间添加延迟
|
|
866
|
+
if (options.commandDelay) {
|
|
867
|
+
await new Promise(resolve => setTimeout(resolve, options.commandDelay));
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
return results;
|
|
871
|
+
});
|
|
872
|
+
// 等待当前批次完成
|
|
873
|
+
const batchResults = await Promise.all(batchPromises);
|
|
874
|
+
// 统计结果
|
|
875
|
+
for (const results of batchResults) {
|
|
876
|
+
for (const result of results) {
|
|
877
|
+
if (result.success) {
|
|
878
|
+
successCount++;
|
|
879
|
+
successfulBytes += result.bytes;
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
else {
|
|
886
|
+
// 串行处理所有命令
|
|
887
|
+
for (let i = 0; i < commands.length; i++) {
|
|
888
|
+
const cmd = commands[i];
|
|
889
|
+
const useChunks = (_a = options.useChunks) !== null && _a !== void 0 ? _a : (cmd.byteLength > this.flowControl.chunkSize);
|
|
890
|
+
try {
|
|
891
|
+
let result;
|
|
892
|
+
if (useChunks) {
|
|
893
|
+
result = await this.writeDataInChunks(cmd, this.flowControl.chunkSize, this.flowControl.chunkDelay);
|
|
894
|
+
}
|
|
895
|
+
else {
|
|
896
|
+
result = await this.writeData(cmd);
|
|
897
|
+
}
|
|
898
|
+
if (result) {
|
|
899
|
+
successCount++;
|
|
900
|
+
successfulBytes += cmd.byteLength;
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
catch (err) {
|
|
904
|
+
// 继续处理其他命令
|
|
905
|
+
logger_1.logger.warn(`处理第${i + 1}/${commands.length}条命令失败`, err);
|
|
906
|
+
}
|
|
907
|
+
// 每个命令之间添加延迟
|
|
908
|
+
if (options.commandDelay && i < commands.length - 1) {
|
|
909
|
+
await new Promise(resolve => setTimeout(resolve, options.commandDelay));
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
// 更新传输统计
|
|
914
|
+
this.transmissionStats.endTime = Date.now();
|
|
915
|
+
this.transmissionStats.successfulBytes = successfulBytes;
|
|
916
|
+
this.transmissionStats.successfulCommands = successCount;
|
|
917
|
+
// 计算传输速度和质量
|
|
918
|
+
const transmissionTime = this.transmissionStats.endTime - this.transmissionStats.startTime;
|
|
919
|
+
const transmissionSpeed = transmissionTime > 0 ?
|
|
920
|
+
(successfulBytes * 1000 / transmissionTime) : 0;
|
|
921
|
+
this.transmissionStats.lastTransmissionSpeed = Math.round(transmissionSpeed);
|
|
922
|
+
const quality = (successfulBytes / totalBytes) || 0;
|
|
923
|
+
this.flowControl.lastQuality = quality;
|
|
924
|
+
// 自动调整传输参数
|
|
925
|
+
if ((_b = options.autoAdjustParams) !== null && _b !== void 0 ? _b : this.flowControl.autoAdjust) {
|
|
926
|
+
this.adjustTransmissionParams(quality, transmissionSpeed);
|
|
927
|
+
}
|
|
928
|
+
const success = successCount === commands.length;
|
|
929
|
+
const failedCount = commands.length - successCount;
|
|
930
|
+
if (!success) {
|
|
931
|
+
logger_1.logger.error(`批量命令执行不完整,共${commands.length}条命令,成功${successCount}条,失败${failedCount}条`);
|
|
932
|
+
// 触发批量写入不完整事件
|
|
933
|
+
events_1.eventManager.emit(events_1.EVENTS.BLUETOOTH_BATCH_INCOMPLETE, {
|
|
934
|
+
total: commands.length,
|
|
935
|
+
success: successCount,
|
|
936
|
+
failed: failedCount,
|
|
937
|
+
transmissionStats: this.getTransmissionStats()
|
|
938
|
+
});
|
|
939
|
+
}
|
|
940
|
+
else {
|
|
941
|
+
logger_1.logger.debug(`批量命令执行完成,共${commands.length}条命令,耗时${transmissionTime}ms,速度${Math.round(transmissionSpeed)}字节/秒`);
|
|
942
|
+
// 触发传输完成事件
|
|
943
|
+
events_1.eventManager.emit(events_1.EVENTS.BLUETOOTH_TRANSMISSION_COMPLETE, {
|
|
944
|
+
total: commands.length,
|
|
945
|
+
bytes: successfulBytes,
|
|
946
|
+
transmissionStats: this.getTransmissionStats()
|
|
947
|
+
});
|
|
948
|
+
}
|
|
949
|
+
return {
|
|
950
|
+
success,
|
|
951
|
+
failed: failedCount,
|
|
952
|
+
stats: this.getTransmissionStats()
|
|
953
|
+
};
|
|
954
|
+
}
|
|
955
|
+
catch (error) {
|
|
956
|
+
logger_1.logger.error('批量命令执行出错', error);
|
|
957
|
+
throw error;
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
/**
|
|
961
|
+
* 重置传输统计数据
|
|
962
|
+
*/
|
|
963
|
+
resetTransmissionStats() {
|
|
964
|
+
this.transmissionStats = {
|
|
965
|
+
totalBytes: 0,
|
|
966
|
+
successfulBytes: 0,
|
|
967
|
+
totalCommands: 0,
|
|
968
|
+
successfulCommands: 0,
|
|
969
|
+
retryCount: 0,
|
|
970
|
+
startTime: 0,
|
|
971
|
+
endTime: 0,
|
|
972
|
+
lastTransmissionSpeed: 0
|
|
973
|
+
};
|
|
974
|
+
}
|
|
975
|
+
/**
|
|
976
|
+
* 获取传输统计信息
|
|
977
|
+
*/
|
|
978
|
+
getTransmissionStats() {
|
|
979
|
+
const stats = Object.assign({}, this.transmissionStats);
|
|
980
|
+
// 添加计算字段
|
|
981
|
+
if (stats.totalBytes > 0) {
|
|
982
|
+
stats.successRate = stats.successfulBytes / stats.totalBytes;
|
|
983
|
+
}
|
|
984
|
+
if (stats.endTime > stats.startTime) {
|
|
985
|
+
stats.duration = stats.endTime - stats.startTime;
|
|
986
|
+
stats.transmissionSpeed = Math.round(stats.successfulBytes * 1000 / stats.duration);
|
|
987
|
+
}
|
|
988
|
+
else {
|
|
989
|
+
stats.duration = 0;
|
|
990
|
+
stats.transmissionSpeed = 0;
|
|
991
|
+
}
|
|
992
|
+
return stats;
|
|
993
|
+
}
|
|
994
|
+
/**
|
|
995
|
+
* 智能调整传输参数
|
|
996
|
+
* 根据传输质量和速度优化分片大小和延迟
|
|
997
|
+
*/
|
|
998
|
+
adjustTransmissionParams(quality, speed) {
|
|
999
|
+
// 如果传输质量低于阈值,降低传输速度
|
|
1000
|
+
if (quality < this.flowControl.qualityThreshold) {
|
|
1001
|
+
// 减少分片大小
|
|
1002
|
+
this.flowControl.chunkSize = Math.max(this.flowControl.minChunkSize, this.flowControl.chunkSize - 5);
|
|
1003
|
+
// 增加延迟
|
|
1004
|
+
this.flowControl.chunkDelay = Math.min(this.flowControl.maxChunkDelay, this.flowControl.chunkDelay + 5);
|
|
1005
|
+
logger_1.logger.debug(`传输质量较低(${quality.toFixed(2)}),调整参数:分片大小=${this.flowControl.chunkSize},分片延迟=${this.flowControl.chunkDelay}ms`);
|
|
1006
|
+
}
|
|
1007
|
+
// 如果传输质量良好,尝试提高速度
|
|
1008
|
+
else if (quality > 0.98 && this.transmissionStats.retryCount === 0) {
|
|
1009
|
+
// 仅在质量很高且无重试的情况下提高速度
|
|
1010
|
+
// 试着增加分片大小
|
|
1011
|
+
if (this.flowControl.chunkSize < this.flowControl.maxChunkSize) {
|
|
1012
|
+
this.flowControl.chunkSize = Math.min(this.flowControl.maxChunkSize, this.flowControl.chunkSize + 5);
|
|
1013
|
+
}
|
|
1014
|
+
// 或减少延迟
|
|
1015
|
+
else if (this.flowControl.chunkDelay > this.flowControl.minChunkDelay) {
|
|
1016
|
+
this.flowControl.chunkDelay = Math.max(this.flowControl.minChunkDelay, this.flowControl.chunkDelay - 2);
|
|
1017
|
+
}
|
|
1018
|
+
logger_1.logger.debug(`传输质量良好(${quality.toFixed(2)}),优化参数:分片大小=${this.flowControl.chunkSize},分片延迟=${this.flowControl.chunkDelay}ms`);
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
/**
|
|
1022
|
+
* 手动设置流量控制参数
|
|
1023
|
+
*/
|
|
1024
|
+
setFlowControlParams(params) {
|
|
1025
|
+
Object.assign(this.flowControl, params);
|
|
1026
|
+
this.flowControlAdjustments++;
|
|
1027
|
+
this.lastFlowControlAdjustment = Date.now();
|
|
1028
|
+
this.saveCurrentState();
|
|
1029
|
+
}
|
|
1030
|
+
/**
|
|
1031
|
+
* 获取当前流量控制参数
|
|
1032
|
+
*/
|
|
1033
|
+
getFlowControlParams() {
|
|
1034
|
+
return Object.assign({}, this.flowControl);
|
|
1035
|
+
}
|
|
294
1036
|
/**
|
|
295
1037
|
* 检查是否已连接
|
|
296
1038
|
*/
|
|
@@ -348,6 +1090,2024 @@ class BluetoothManager {
|
|
|
348
1090
|
return false;
|
|
349
1091
|
}
|
|
350
1092
|
}
|
|
1093
|
+
/**
|
|
1094
|
+
* 获取设备信息
|
|
1095
|
+
* @param deviceId 设备ID(默认为当前连接的设备)
|
|
1096
|
+
*/
|
|
1097
|
+
async getDeviceInfo(deviceId) {
|
|
1098
|
+
var _a;
|
|
1099
|
+
try {
|
|
1100
|
+
if (!this.adapter) {
|
|
1101
|
+
throw new Error('蓝牙适配器未初始化');
|
|
1102
|
+
}
|
|
1103
|
+
const targetDeviceId = deviceId || this.connectedDeviceId;
|
|
1104
|
+
if (!targetDeviceId) {
|
|
1105
|
+
return null;
|
|
1106
|
+
}
|
|
1107
|
+
// 先检查缓存
|
|
1108
|
+
const cachedInfo = this.getCachedDeviceInfo(targetDeviceId);
|
|
1109
|
+
if (cachedInfo) {
|
|
1110
|
+
return cachedInfo;
|
|
1111
|
+
}
|
|
1112
|
+
// 从已发现设备列表中查找
|
|
1113
|
+
const discoveredDevice = this.discoveredDevices.get(targetDeviceId);
|
|
1114
|
+
if (discoveredDevice) {
|
|
1115
|
+
this.updateDeviceInfoCache(targetDeviceId, discoveredDevice);
|
|
1116
|
+
return discoveredDevice;
|
|
1117
|
+
}
|
|
1118
|
+
// 如果设备已连接,获取实时信息
|
|
1119
|
+
if (this.isConnected() && targetDeviceId === this.connectedDeviceId) {
|
|
1120
|
+
const deviceInfo = {
|
|
1121
|
+
deviceId: targetDeviceId,
|
|
1122
|
+
name: ((_a = this.connectionHistory.get(targetDeviceId)) === null || _a === void 0 ? void 0 : _a.name) || '',
|
|
1123
|
+
RSSI: -1,
|
|
1124
|
+
advertisData: new ArrayBuffer(0),
|
|
1125
|
+
manufacturerData: new ArrayBuffer(0)
|
|
1126
|
+
};
|
|
1127
|
+
this.updateDeviceInfoCache(targetDeviceId, deviceInfo);
|
|
1128
|
+
return deviceInfo;
|
|
1129
|
+
}
|
|
1130
|
+
return null;
|
|
1131
|
+
}
|
|
1132
|
+
catch (error) {
|
|
1133
|
+
logger_1.logger.error('获取设备信息失败:', error);
|
|
1134
|
+
return null;
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
/**
|
|
1138
|
+
* 获取设备电量信息
|
|
1139
|
+
* @param deviceId 设备ID(默认为当前连接的设备)
|
|
1140
|
+
*/
|
|
1141
|
+
async getBatteryLevel(deviceId) {
|
|
1142
|
+
var _a, _b;
|
|
1143
|
+
const targetId = deviceId || this.connectedDeviceId;
|
|
1144
|
+
if (!targetId) {
|
|
1145
|
+
logger_1.logger.warn('无法获取电量:未指定设备ID且未连接设备');
|
|
1146
|
+
return null;
|
|
1147
|
+
}
|
|
1148
|
+
try {
|
|
1149
|
+
// 尝试获取BLE设备的电池服务
|
|
1150
|
+
const services = await taro_1.default.getBLEDeviceServices({
|
|
1151
|
+
deviceId: targetId
|
|
1152
|
+
});
|
|
1153
|
+
// 电池服务UUID
|
|
1154
|
+
const batteryServiceUUID = '180F';
|
|
1155
|
+
const batteryCharacteristicUUID = '2A19';
|
|
1156
|
+
// 查找电池服务
|
|
1157
|
+
const batteryService = (_a = services.services) === null || _a === void 0 ? void 0 : _a.find(s => s.uuid.toUpperCase().indexOf(batteryServiceUUID) >= 0);
|
|
1158
|
+
if (!batteryService) {
|
|
1159
|
+
logger_1.logger.debug(`设备 ${targetId} 未提供电池服务`);
|
|
1160
|
+
return null;
|
|
1161
|
+
}
|
|
1162
|
+
// 获取电池服务的特征值
|
|
1163
|
+
const characteristics = await taro_1.default.getBLEDeviceCharacteristics({
|
|
1164
|
+
deviceId: targetId,
|
|
1165
|
+
serviceId: batteryService.uuid
|
|
1166
|
+
});
|
|
1167
|
+
// 查找电池电量特征值
|
|
1168
|
+
const batteryCharacteristic = (_b = characteristics.characteristics) === null || _b === void 0 ? void 0 : _b.find(c => c.uuid.toUpperCase().indexOf(batteryCharacteristicUUID) >= 0);
|
|
1169
|
+
if (!batteryCharacteristic) {
|
|
1170
|
+
logger_1.logger.debug(`设备 ${targetId} 的电池服务未提供电量特征值`);
|
|
1171
|
+
return null;
|
|
1172
|
+
}
|
|
1173
|
+
// 读取电池电量
|
|
1174
|
+
const result = await taro_1.default.readBLECharacteristicValue({
|
|
1175
|
+
deviceId: targetId,
|
|
1176
|
+
serviceId: batteryService.uuid,
|
|
1177
|
+
characteristicId: batteryCharacteristic.uuid
|
|
1178
|
+
});
|
|
1179
|
+
if (result && result.errMsg.includes('ok')) {
|
|
1180
|
+
// 获取读取到的值,此处不需要额外调用getBLECharacteristicValue
|
|
1181
|
+
// 电量值会通过特定事件(onBLECharacteristicValueChange)返回
|
|
1182
|
+
// 注册监听电量特征值变化的事件
|
|
1183
|
+
return new Promise((resolve) => {
|
|
1184
|
+
// 设置超时,防止长时间等待
|
|
1185
|
+
const timeout = setTimeout(() => {
|
|
1186
|
+
// 使用空回调函数,满足API要求
|
|
1187
|
+
taro_1.default.offBLECharacteristicValueChange(() => { });
|
|
1188
|
+
resolve(null);
|
|
1189
|
+
}, 3000);
|
|
1190
|
+
// 创建监听回调
|
|
1191
|
+
const valueChangeHandler = (res) => {
|
|
1192
|
+
if (res.deviceId === targetId &&
|
|
1193
|
+
res.serviceId === batteryService.uuid &&
|
|
1194
|
+
res.characteristicId === batteryCharacteristic.uuid) {
|
|
1195
|
+
clearTimeout(timeout);
|
|
1196
|
+
taro_1.default.offBLECharacteristicValueChange(() => { });
|
|
1197
|
+
// 解析电量值(通常是0-100的整数)
|
|
1198
|
+
const dataView = new DataView(res.value);
|
|
1199
|
+
const batteryLevel = dataView.getUint8(0);
|
|
1200
|
+
logger_1.logger.debug(`设备 ${targetId} 电量: ${batteryLevel}%`);
|
|
1201
|
+
resolve(batteryLevel);
|
|
1202
|
+
}
|
|
1203
|
+
};
|
|
1204
|
+
// 监听特征值变化
|
|
1205
|
+
taro_1.default.onBLECharacteristicValueChange(valueChangeHandler);
|
|
1206
|
+
});
|
|
1207
|
+
}
|
|
1208
|
+
return null;
|
|
1209
|
+
}
|
|
1210
|
+
catch (error) {
|
|
1211
|
+
logger_1.logger.warn(`获取设备 ${targetId} 电量失败`, error);
|
|
1212
|
+
return null;
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
/**
|
|
1216
|
+
* 设置低电量警告阈值并开始监控
|
|
1217
|
+
* @param threshold 电量阈值百分比(0-100)
|
|
1218
|
+
* @param interval 检查间隔(毫秒)
|
|
1219
|
+
*/
|
|
1220
|
+
startBatteryMonitoring(threshold = 15, interval) {
|
|
1221
|
+
if (!this.connectedDeviceId) {
|
|
1222
|
+
logger_1.logger.warn('未连接设备,无法启动电量监控');
|
|
1223
|
+
return;
|
|
1224
|
+
}
|
|
1225
|
+
// 停止之前的监控
|
|
1226
|
+
this.stopBatteryMonitoring();
|
|
1227
|
+
// 使用指定的间隔或当前设置的间隔
|
|
1228
|
+
const checkInterval = interval || this.batteryCheckIntervalMs;
|
|
1229
|
+
// 添加到实例属性
|
|
1230
|
+
this.batteryCheckInterval = setInterval(async () => {
|
|
1231
|
+
if (!this.connectedDeviceId) {
|
|
1232
|
+
this.stopBatteryMonitoring();
|
|
1233
|
+
return;
|
|
1234
|
+
}
|
|
1235
|
+
const batteryLevel = await this.getBatteryLevel();
|
|
1236
|
+
if (batteryLevel !== null) {
|
|
1237
|
+
// 触发电量更新事件
|
|
1238
|
+
events_1.eventManager.emit(events_1.EVENTS.BLUETOOTH_BATTERY_UPDATE, {
|
|
1239
|
+
deviceId: this.connectedDeviceId,
|
|
1240
|
+
level: batteryLevel
|
|
1241
|
+
});
|
|
1242
|
+
// 低电量警告
|
|
1243
|
+
if (batteryLevel <= threshold) {
|
|
1244
|
+
logger_1.logger.warn(`设备 ${this.connectedDeviceId} 电量低: ${batteryLevel}%`);
|
|
1245
|
+
// 触发低电量事件
|
|
1246
|
+
events_1.eventManager.emit(events_1.EVENTS.BLUETOOTH_LOW_BATTERY, {
|
|
1247
|
+
deviceId: this.connectedDeviceId,
|
|
1248
|
+
level: batteryLevel,
|
|
1249
|
+
threshold
|
|
1250
|
+
});
|
|
1251
|
+
// 如果启用了自动电源管理,切换到激进节能模式
|
|
1252
|
+
if (this.powerSavingEnabled && this.powerSavingMode === 'auto') {
|
|
1253
|
+
this.applyPowerMode('aggressive');
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
// 如果在自动电源管理模式下,根据电池电量调整模式
|
|
1257
|
+
if (this.powerSavingEnabled && this.powerSavingMode === 'auto') {
|
|
1258
|
+
this.detectBatteryAndAdjustPowerMode();
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
}, checkInterval);
|
|
1262
|
+
logger_1.logger.debug(`已启动电量监控,阈值: ${threshold}%,间隔: ${checkInterval}ms`);
|
|
1263
|
+
}
|
|
1264
|
+
/**
|
|
1265
|
+
* 停止电量监控
|
|
1266
|
+
*/
|
|
1267
|
+
stopBatteryMonitoring() {
|
|
1268
|
+
if (this.batteryCheckInterval) {
|
|
1269
|
+
clearInterval(this.batteryCheckInterval);
|
|
1270
|
+
this.batteryCheckInterval = null;
|
|
1271
|
+
logger_1.logger.debug('已停止电量监控');
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
/**
|
|
1275
|
+
* 诊断蓝牙连接状态
|
|
1276
|
+
* 用于排查和解决常见问题
|
|
1277
|
+
*/
|
|
1278
|
+
async diagnoseConnection() {
|
|
1279
|
+
const issues = [];
|
|
1280
|
+
const details = {
|
|
1281
|
+
deviceId: this.connectedDeviceId,
|
|
1282
|
+
isInitialized: this.isInitialized,
|
|
1283
|
+
isConnected: this.isConnected(),
|
|
1284
|
+
transmissionQuality: this.flowControl.lastQuality,
|
|
1285
|
+
batteryLevel: null,
|
|
1286
|
+
signalStrength: null
|
|
1287
|
+
};
|
|
1288
|
+
// 检查初始化状态
|
|
1289
|
+
if (!this.isInitialized) {
|
|
1290
|
+
issues.push('蓝牙适配器未初始化');
|
|
1291
|
+
}
|
|
1292
|
+
// 检查连接状态
|
|
1293
|
+
if (!this.connectedDeviceId) {
|
|
1294
|
+
issues.push('未连接到设备');
|
|
1295
|
+
}
|
|
1296
|
+
else {
|
|
1297
|
+
try {
|
|
1298
|
+
// 测试服务可用性
|
|
1299
|
+
const device = await this.getDeviceInfo();
|
|
1300
|
+
if (device) {
|
|
1301
|
+
details.device = device;
|
|
1302
|
+
// 检查设备名称
|
|
1303
|
+
if (!device.name) {
|
|
1304
|
+
issues.push('设备名称为空,可能是设备连接不稳定');
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
// 检查电池电量
|
|
1308
|
+
const batteryLevel = await this.getBatteryLevel();
|
|
1309
|
+
details.batteryLevel = batteryLevel;
|
|
1310
|
+
if (batteryLevel !== null && batteryLevel < 15) {
|
|
1311
|
+
issues.push(`设备电量低:${batteryLevel}%`);
|
|
1312
|
+
}
|
|
1313
|
+
// 获取信号强度(RSSI)
|
|
1314
|
+
try {
|
|
1315
|
+
// 获取设备信号强度信息
|
|
1316
|
+
// 注意:小程序通常需要在蓝牙设备发现阶段获取RSSI,
|
|
1317
|
+
// 这里尝试从已发现设备列表中获取
|
|
1318
|
+
const deviceInfo = await this.getDeviceInfo();
|
|
1319
|
+
if (deviceInfo && typeof deviceInfo.RSSI === 'number') {
|
|
1320
|
+
details.signalStrength = deviceInfo.RSSI;
|
|
1321
|
+
// 弱信号强度检查
|
|
1322
|
+
if (deviceInfo.RSSI < -80) {
|
|
1323
|
+
issues.push(`设备信号强度较弱:${deviceInfo.RSSI}dBm`);
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
else {
|
|
1327
|
+
logger_1.logger.debug('无法获取设备信号强度信息');
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
catch (err) {
|
|
1331
|
+
logger_1.logger.debug('获取设备信号强度失败', err);
|
|
1332
|
+
}
|
|
1333
|
+
// 测试写入能力
|
|
1334
|
+
const testData = new Uint8Array([0x00, 0x00, 0x00, 0x00]).buffer;
|
|
1335
|
+
const writeResult = await this.writeData(testData).catch(() => false);
|
|
1336
|
+
details.canWrite = writeResult;
|
|
1337
|
+
if (!writeResult) {
|
|
1338
|
+
issues.push('设备不响应数据写入命令');
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
catch (error) {
|
|
1342
|
+
issues.push(`设备状态检查出错: ${error instanceof Error ? error.message : String(error)}`);
|
|
1343
|
+
details.error = error;
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
// 检查传输统计信息
|
|
1347
|
+
if (this.transmissionStats.totalBytes > 0) {
|
|
1348
|
+
const transmissionStats = this.getTransmissionStats();
|
|
1349
|
+
details.transmissionStats = transmissionStats;
|
|
1350
|
+
if ((transmissionStats.successRate || 0) < 0.8) {
|
|
1351
|
+
issues.push(`传输成功率较低: ${((transmissionStats.successRate || 0) * 100).toFixed(1)}%`);
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
// 确定总体状态
|
|
1355
|
+
let status = 'healthy';
|
|
1356
|
+
if (issues.length > 0) {
|
|
1357
|
+
status = issues.some(issue => issue.includes('未初始化') ||
|
|
1358
|
+
issue.includes('未连接') ||
|
|
1359
|
+
issue.includes('不响应')) ? 'error' : 'warning';
|
|
1360
|
+
}
|
|
1361
|
+
logger_1.logger.info(`设备状态诊断:${status}`, issues);
|
|
1362
|
+
// 如果有问题但不严重,尝试自动修复
|
|
1363
|
+
if (status === 'warning' && this.isConnected()) {
|
|
1364
|
+
this.tryOptimizeConnection();
|
|
1365
|
+
}
|
|
1366
|
+
return {
|
|
1367
|
+
status,
|
|
1368
|
+
issues,
|
|
1369
|
+
details
|
|
1370
|
+
};
|
|
1371
|
+
}
|
|
1372
|
+
/**
|
|
1373
|
+
* 尝试优化连接状态
|
|
1374
|
+
* 自动执行一些修复和优化操作
|
|
1375
|
+
*/
|
|
1376
|
+
async tryOptimizeConnection() {
|
|
1377
|
+
if (!this.connectedDeviceId)
|
|
1378
|
+
return;
|
|
1379
|
+
logger_1.logger.debug('尝试优化蓝牙连接...');
|
|
1380
|
+
try {
|
|
1381
|
+
// 1. 重置特征值通知状态
|
|
1382
|
+
await taro_1.default.notifyBLECharacteristicValueChange({
|
|
1383
|
+
deviceId: this.connectedDeviceId,
|
|
1384
|
+
serviceId: this.serviceUUID,
|
|
1385
|
+
characteristicId: this.characteristicUUID,
|
|
1386
|
+
state: false
|
|
1387
|
+
}).catch(() => null);
|
|
1388
|
+
await new Promise(resolve => setTimeout(resolve, 200));
|
|
1389
|
+
// 2. 清理缓存数据
|
|
1390
|
+
const testData = new Uint8Array([0x00, 0x1B, 0x40]).buffer; // ESC @ 初始化指令
|
|
1391
|
+
await this.writeData(testData).catch(() => false);
|
|
1392
|
+
// 3. 测试新的流量控制参数
|
|
1393
|
+
this.setFlowControlParams({
|
|
1394
|
+
chunkSize: 20,
|
|
1395
|
+
chunkDelay: 30,
|
|
1396
|
+
autoAdjust: true
|
|
1397
|
+
});
|
|
1398
|
+
logger_1.logger.debug('连接优化完成');
|
|
1399
|
+
}
|
|
1400
|
+
catch (error) {
|
|
1401
|
+
logger_1.logger.warn('连接优化失败', error);
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
setKeepAlive(enable, interval = 30000) {
|
|
1405
|
+
// 清除现有的保活定时器
|
|
1406
|
+
if (this.keepAliveInterval) {
|
|
1407
|
+
clearInterval(this.keepAliveInterval);
|
|
1408
|
+
this.keepAliveInterval = null;
|
|
1409
|
+
}
|
|
1410
|
+
if (!enable) {
|
|
1411
|
+
logger_1.logger.debug('已禁用连接保活');
|
|
1412
|
+
return;
|
|
1413
|
+
}
|
|
1414
|
+
logger_1.logger.debug(`启用连接保活,间隔: ${interval}ms`);
|
|
1415
|
+
// 设置新的保活定时器
|
|
1416
|
+
this.keepAliveInterval = setInterval(async () => {
|
|
1417
|
+
if (!this.isConnected()) {
|
|
1418
|
+
logger_1.logger.debug('设备未连接,暂停保活');
|
|
1419
|
+
return;
|
|
1420
|
+
}
|
|
1421
|
+
try {
|
|
1422
|
+
// 发送空命令保持连接
|
|
1423
|
+
const keepAliveData = new Uint8Array([0x00]).buffer;
|
|
1424
|
+
await this.writeData(keepAliveData);
|
|
1425
|
+
logger_1.logger.debug('发送保活数据包');
|
|
1426
|
+
}
|
|
1427
|
+
catch (error) {
|
|
1428
|
+
logger_1.logger.warn('保活数据发送失败', error);
|
|
1429
|
+
// 如果保活失败且配置了自动重连,尝试重新连接
|
|
1430
|
+
if (this.autoReconnect && this.connectedDeviceId) {
|
|
1431
|
+
logger_1.logger.info('保活失败,尝试重新连接...');
|
|
1432
|
+
this.connectedDeviceId = null;
|
|
1433
|
+
this.lastConnectedDevice = this.connectedDeviceId;
|
|
1434
|
+
this.scheduleReconnect();
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
}, interval);
|
|
1438
|
+
}
|
|
1439
|
+
/**
|
|
1440
|
+
* 清理连接相关资源
|
|
1441
|
+
* 在组件卸载或页面关闭时调用
|
|
1442
|
+
*/
|
|
1443
|
+
cleanup() {
|
|
1444
|
+
// 清理队列资源
|
|
1445
|
+
if (this.queueProcessTimer) {
|
|
1446
|
+
clearTimeout(this.queueProcessTimer);
|
|
1447
|
+
this.queueProcessTimer = null;
|
|
1448
|
+
}
|
|
1449
|
+
this.clearCommandQueue(true);
|
|
1450
|
+
// 调用原来的清理代码
|
|
1451
|
+
logger_1.logger.debug('清理蓝牙连接资源...');
|
|
1452
|
+
// 清理电量监控
|
|
1453
|
+
this.stopBatteryMonitoring();
|
|
1454
|
+
// 清理保活定时器
|
|
1455
|
+
if (this.keepAliveInterval) {
|
|
1456
|
+
clearInterval(this.keepAliveInterval);
|
|
1457
|
+
this.keepAliveInterval = null;
|
|
1458
|
+
}
|
|
1459
|
+
// 清理连接质量监控
|
|
1460
|
+
this.stopQualityMonitoring();
|
|
1461
|
+
// 清理重连定时器
|
|
1462
|
+
this.resetReconnectState();
|
|
1463
|
+
// 清理恢复计时器
|
|
1464
|
+
this.resetRecoveryState();
|
|
1465
|
+
// 关闭自动重连
|
|
1466
|
+
this.autoReconnect = false;
|
|
1467
|
+
// 断开连接但不触发重连
|
|
1468
|
+
if (this.connectedDeviceId) {
|
|
1469
|
+
this.disconnect().catch(err => {
|
|
1470
|
+
logger_1.logger.warn('清理时断开连接失败', err);
|
|
1471
|
+
});
|
|
1472
|
+
}
|
|
1473
|
+
// 清理电源管理资源
|
|
1474
|
+
if (this.inactivityTimer) {
|
|
1475
|
+
clearTimeout(this.inactivityTimer);
|
|
1476
|
+
this.inactivityTimer = null;
|
|
1477
|
+
}
|
|
1478
|
+
// 清理性能监控资源
|
|
1479
|
+
if (this.performanceMonitorInterval) {
|
|
1480
|
+
clearInterval(this.performanceMonitorInterval);
|
|
1481
|
+
this.performanceMonitorInterval = null;
|
|
1482
|
+
}
|
|
1483
|
+
// 释放缓冲区池
|
|
1484
|
+
for (const size of this.performanceConfig.bufferSizes) {
|
|
1485
|
+
this.bufferPool.set(size, []);
|
|
1486
|
+
}
|
|
1487
|
+
// 清空缓存
|
|
1488
|
+
this.deviceInfoCache.clear();
|
|
1489
|
+
// 清理统计数据
|
|
1490
|
+
this.statsAggregator.writeTimes = [];
|
|
1491
|
+
this.statsAggregator.readTimes = [];
|
|
1492
|
+
this.statsAggregator.connectTimes = [];
|
|
1493
|
+
this.statsAggregator.discoverTimes = [];
|
|
1494
|
+
this.statsAggregator.errorCounts.clear();
|
|
1495
|
+
}
|
|
1496
|
+
/**
|
|
1497
|
+
* 获取收藏的设备列表
|
|
1498
|
+
*/
|
|
1499
|
+
getFavoriteDevices() {
|
|
1500
|
+
const favorites = [];
|
|
1501
|
+
this.connectionHistory.forEach(history => {
|
|
1502
|
+
if (history.favorite) {
|
|
1503
|
+
favorites.push({
|
|
1504
|
+
deviceId: history.deviceId,
|
|
1505
|
+
name: history.name || `设备 ${history.deviceId.slice(-6)}`
|
|
1506
|
+
});
|
|
1507
|
+
}
|
|
1508
|
+
});
|
|
1509
|
+
return favorites;
|
|
1510
|
+
}
|
|
1511
|
+
/**
|
|
1512
|
+
* 设置设备收藏状态
|
|
1513
|
+
* @param deviceId 设备ID
|
|
1514
|
+
* @param favorite 是否收藏
|
|
1515
|
+
*/
|
|
1516
|
+
setDeviceFavorite(deviceId, favorite) {
|
|
1517
|
+
const historyEntry = this.connectionHistory.get(deviceId);
|
|
1518
|
+
if (historyEntry) {
|
|
1519
|
+
historyEntry.favorite = favorite;
|
|
1520
|
+
this.connectionHistory.set(deviceId, historyEntry);
|
|
1521
|
+
this.saveConnectionHistory();
|
|
1522
|
+
logger_1.logger.debug(`设备 ${deviceId} ${favorite ? '已加入' : '已移出'}收藏列表`);
|
|
1523
|
+
return true;
|
|
1524
|
+
}
|
|
1525
|
+
return false;
|
|
1526
|
+
}
|
|
1527
|
+
/**
|
|
1528
|
+
* 获取最近连接的设备列表
|
|
1529
|
+
* @param limit 最大数量
|
|
1530
|
+
*/
|
|
1531
|
+
getRecentDevices(limit = 5) {
|
|
1532
|
+
// 按最后连接时间排序
|
|
1533
|
+
const sortedHistory = Array.from(this.connectionHistory.values())
|
|
1534
|
+
.sort((a, b) => b.lastConnected - a.lastConnected)
|
|
1535
|
+
.slice(0, limit);
|
|
1536
|
+
return sortedHistory.map(history => ({
|
|
1537
|
+
deviceId: history.deviceId,
|
|
1538
|
+
name: history.name || `设备 ${history.deviceId.slice(-6)}`
|
|
1539
|
+
}));
|
|
1540
|
+
}
|
|
1541
|
+
/**
|
|
1542
|
+
* 清除设备历史记录
|
|
1543
|
+
* @param deviceId 指定设备ID,不指定则清除所有
|
|
1544
|
+
*/
|
|
1545
|
+
clearDeviceHistory(deviceId) {
|
|
1546
|
+
if (deviceId) {
|
|
1547
|
+
this.connectionHistory.delete(deviceId);
|
|
1548
|
+
}
|
|
1549
|
+
else {
|
|
1550
|
+
this.connectionHistory.clear();
|
|
1551
|
+
}
|
|
1552
|
+
this.saveConnectionHistory();
|
|
1553
|
+
logger_1.logger.debug(deviceId ? `已清除设备 ${deviceId} 的历史记录` : '已清除所有设备历史记录');
|
|
1554
|
+
}
|
|
1555
|
+
/**
|
|
1556
|
+
* 启动连接质量监控
|
|
1557
|
+
*/
|
|
1558
|
+
startQualityMonitoring() {
|
|
1559
|
+
if (this.connectionQualityInterval) {
|
|
1560
|
+
clearInterval(this.connectionQualityInterval);
|
|
1561
|
+
}
|
|
1562
|
+
logger_1.logger.debug('启动连接质量监控');
|
|
1563
|
+
this.connectionQualityInterval = setInterval(async () => {
|
|
1564
|
+
if (!this.isConnected()) {
|
|
1565
|
+
return;
|
|
1566
|
+
}
|
|
1567
|
+
try {
|
|
1568
|
+
const deviceInfo = await this.getDeviceInfo();
|
|
1569
|
+
const signalStrength = deviceInfo === null || deviceInfo === void 0 ? void 0 : deviceInfo.RSSI;
|
|
1570
|
+
const transmissionQuality = this.flowControl.lastQuality;
|
|
1571
|
+
const qualityInfo = {
|
|
1572
|
+
deviceId: this.connectedDeviceId,
|
|
1573
|
+
signalStrength,
|
|
1574
|
+
transmissionQuality,
|
|
1575
|
+
timestamp: Date.now()
|
|
1576
|
+
};
|
|
1577
|
+
// 触发质量更新事件
|
|
1578
|
+
events_1.eventManager.emit(events_1.EVENTS.BLUETOOTH_QUALITY_UPDATE, qualityInfo);
|
|
1579
|
+
// 检查信号强度
|
|
1580
|
+
if (typeof signalStrength === 'number' && signalStrength < this.RSSI_WARNING_THRESHOLD) {
|
|
1581
|
+
logger_1.logger.warn(`蓝牙信号强度较弱: ${signalStrength}dBm`);
|
|
1582
|
+
events_1.eventManager.emit(events_1.EVENTS.BLUETOOTH_WEAK_SIGNAL, {
|
|
1583
|
+
deviceId: this.connectedDeviceId,
|
|
1584
|
+
signalStrength,
|
|
1585
|
+
threshold: this.RSSI_WARNING_THRESHOLD
|
|
1586
|
+
});
|
|
1587
|
+
}
|
|
1588
|
+
// 检查传输质量
|
|
1589
|
+
if (transmissionQuality < this.QUALITY_WARNING_THRESHOLD) {
|
|
1590
|
+
logger_1.logger.warn(`传输质量较差: ${(transmissionQuality * 100).toFixed(1)}%`);
|
|
1591
|
+
events_1.eventManager.emit(events_1.EVENTS.BLUETOOTH_POOR_QUALITY, {
|
|
1592
|
+
deviceId: this.connectedDeviceId,
|
|
1593
|
+
quality: transmissionQuality,
|
|
1594
|
+
threshold: this.QUALITY_WARNING_THRESHOLD
|
|
1595
|
+
});
|
|
1596
|
+
// 尝试优化连接
|
|
1597
|
+
await this.tryOptimizeConnection();
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
catch (error) {
|
|
1601
|
+
logger_1.logger.warn('连接质量检查失败', error);
|
|
1602
|
+
}
|
|
1603
|
+
}, this.qualityCheckInterval);
|
|
1604
|
+
}
|
|
1605
|
+
/**
|
|
1606
|
+
* 停止连接质量监控
|
|
1607
|
+
*/
|
|
1608
|
+
stopQualityMonitoring() {
|
|
1609
|
+
if (this.connectionQualityInterval) {
|
|
1610
|
+
clearInterval(this.connectionQualityInterval);
|
|
1611
|
+
this.connectionQualityInterval = null;
|
|
1612
|
+
logger_1.logger.debug('已停止连接质量监控');
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
/**
|
|
1616
|
+
* 保存当前状态
|
|
1617
|
+
*/
|
|
1618
|
+
saveCurrentState() {
|
|
1619
|
+
this.lastKnownState = {
|
|
1620
|
+
flowControl: Object.assign({}, this.flowControl),
|
|
1621
|
+
batteryLevel: null,
|
|
1622
|
+
signalStrength: null,
|
|
1623
|
+
transmissionStats: Object.assign({}, this.transmissionStats)
|
|
1624
|
+
};
|
|
1625
|
+
// 尝试获取最新的电量和信号强度
|
|
1626
|
+
this.getBatteryLevel().then(level => {
|
|
1627
|
+
if (this.lastKnownState) {
|
|
1628
|
+
this.lastKnownState.batteryLevel = level;
|
|
1629
|
+
}
|
|
1630
|
+
});
|
|
1631
|
+
this.getDeviceInfo().then(info => {
|
|
1632
|
+
if (this.lastKnownState && (info === null || info === void 0 ? void 0 : info.RSSI)) {
|
|
1633
|
+
this.lastKnownState.signalStrength = info.RSSI;
|
|
1634
|
+
}
|
|
1635
|
+
});
|
|
1636
|
+
}
|
|
1637
|
+
/**
|
|
1638
|
+
* 恢复之前的状态
|
|
1639
|
+
*/
|
|
1640
|
+
async restoreState() {
|
|
1641
|
+
if (!this.lastKnownState || !this.isConnected()) {
|
|
1642
|
+
return false;
|
|
1643
|
+
}
|
|
1644
|
+
try {
|
|
1645
|
+
// 恢复流量控制参数
|
|
1646
|
+
this.flowControl = Object.assign({}, this.lastKnownState.flowControl);
|
|
1647
|
+
// 验证连接是否正常
|
|
1648
|
+
const testData = new Uint8Array([0x00]).buffer;
|
|
1649
|
+
const writeResult = await this.writeData(testData);
|
|
1650
|
+
if (!writeResult) {
|
|
1651
|
+
throw new Error('连接状态验证失败');
|
|
1652
|
+
}
|
|
1653
|
+
// 重新启动监控
|
|
1654
|
+
this.startQualityMonitoring();
|
|
1655
|
+
this.startBatteryMonitoring();
|
|
1656
|
+
logger_1.logger.info('成功恢复设备状态');
|
|
1657
|
+
return true;
|
|
1658
|
+
}
|
|
1659
|
+
catch (error) {
|
|
1660
|
+
logger_1.logger.warn('恢复设备状态失败', error);
|
|
1661
|
+
return false;
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
/**
|
|
1665
|
+
* 智能恢复连接
|
|
1666
|
+
*/
|
|
1667
|
+
async attemptRecovery() {
|
|
1668
|
+
if (this.recoveryAttempts >= this.MAX_RECOVERY_ATTEMPTS) {
|
|
1669
|
+
logger_1.logger.warn('达到最大恢复尝试次数');
|
|
1670
|
+
return false;
|
|
1671
|
+
}
|
|
1672
|
+
this.recoveryAttempts++;
|
|
1673
|
+
this.currentRecoveryDelay = Math.min(5000, this.currentRecoveryDelay + 500);
|
|
1674
|
+
try {
|
|
1675
|
+
// 1. 尝试重新初始化蓝牙
|
|
1676
|
+
if (!this.isInitialized) {
|
|
1677
|
+
const initResult = await this.init();
|
|
1678
|
+
if (!initResult) {
|
|
1679
|
+
throw new Error('蓝牙初始化失败');
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
// 2. 尝试重新连接
|
|
1683
|
+
if (!this.isConnected() && this.lastConnectedDevice) {
|
|
1684
|
+
const connectResult = await this.connect(this.lastConnectedDevice, {
|
|
1685
|
+
timeout: 5000,
|
|
1686
|
+
retries: 1
|
|
1687
|
+
});
|
|
1688
|
+
if (!connectResult) {
|
|
1689
|
+
throw new Error('重新连接失败');
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
// 3. 恢复之前的状态
|
|
1693
|
+
const restoreResult = await this.restoreState();
|
|
1694
|
+
if (!restoreResult) {
|
|
1695
|
+
throw new Error('状态恢复失败');
|
|
1696
|
+
}
|
|
1697
|
+
logger_1.logger.info('连接恢复成功');
|
|
1698
|
+
this.resetRecoveryState();
|
|
1699
|
+
return true;
|
|
1700
|
+
}
|
|
1701
|
+
catch (error) {
|
|
1702
|
+
logger_1.logger.error('恢复失败:', error);
|
|
1703
|
+
return false;
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
/**
|
|
1707
|
+
* 安排恢复尝试
|
|
1708
|
+
*/
|
|
1709
|
+
scheduleRecovery(delay) {
|
|
1710
|
+
const backoffDelay = this.currentRecoveryDelay * Math.pow(2, this.recoveryAttempts - 1);
|
|
1711
|
+
if (this.recoveryTimer) {
|
|
1712
|
+
clearTimeout(this.recoveryTimer);
|
|
1713
|
+
}
|
|
1714
|
+
this.recoveryTimer = setTimeout(() => {
|
|
1715
|
+
this.attemptRecovery();
|
|
1716
|
+
}, backoffDelay);
|
|
1717
|
+
}
|
|
1718
|
+
/**
|
|
1719
|
+
* 重置恢复状态
|
|
1720
|
+
*/
|
|
1721
|
+
resetRecoveryState() {
|
|
1722
|
+
this.recoveryAttempts = 0;
|
|
1723
|
+
if (this.recoveryTimer) {
|
|
1724
|
+
clearTimeout(this.recoveryTimer);
|
|
1725
|
+
this.recoveryTimer = null;
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
/**
|
|
1729
|
+
* 获取设备性能报告
|
|
1730
|
+
*/
|
|
1731
|
+
async getPerformanceReport() {
|
|
1732
|
+
const deviceInfo = await this.getDeviceInfo();
|
|
1733
|
+
const batteryLevel = await this.getBatteryLevel();
|
|
1734
|
+
const stats = this.getTransmissionStats();
|
|
1735
|
+
return {
|
|
1736
|
+
device: {
|
|
1737
|
+
id: this.connectedDeviceId,
|
|
1738
|
+
name: deviceInfo === null || deviceInfo === void 0 ? void 0 : deviceInfo.name,
|
|
1739
|
+
signalStrength: deviceInfo === null || deviceInfo === void 0 ? void 0 : deviceInfo.RSSI,
|
|
1740
|
+
batteryLevel: batteryLevel || undefined
|
|
1741
|
+
},
|
|
1742
|
+
connection: {
|
|
1743
|
+
uptime: this.getConnectionUptime(),
|
|
1744
|
+
reconnections: this.recoveryAttempts,
|
|
1745
|
+
lastReconnectTime: this.lastReconnectTime,
|
|
1746
|
+
quality: this.flowControl.lastQuality
|
|
1747
|
+
},
|
|
1748
|
+
transmission: {
|
|
1749
|
+
totalBytesSent: stats.totalBytes,
|
|
1750
|
+
averageSpeed: stats.transmissionSpeed || 0,
|
|
1751
|
+
successRate: stats.successRate || 0,
|
|
1752
|
+
errorRate: stats.totalBytes > 0 ?
|
|
1753
|
+
(stats.totalBytes - stats.successfulBytes) / stats.totalBytes : 0,
|
|
1754
|
+
retryCount: stats.retryCount
|
|
1755
|
+
},
|
|
1756
|
+
flowControl: {
|
|
1757
|
+
current: Object.assign({}, this.flowControl),
|
|
1758
|
+
adjustments: this.flowControlAdjustments,
|
|
1759
|
+
lastAdjustmentTime: this.lastFlowControlAdjustment
|
|
1760
|
+
}
|
|
1761
|
+
};
|
|
1762
|
+
}
|
|
1763
|
+
/**
|
|
1764
|
+
* 获取连接运行时间(毫秒)
|
|
1765
|
+
*/
|
|
1766
|
+
getConnectionUptime() {
|
|
1767
|
+
if (!this.connectionStartTime || !this.isConnected()) {
|
|
1768
|
+
return 0;
|
|
1769
|
+
}
|
|
1770
|
+
return Date.now() - this.connectionStartTime;
|
|
1771
|
+
}
|
|
1772
|
+
/**
|
|
1773
|
+
* 分析并优化传输性能
|
|
1774
|
+
*/
|
|
1775
|
+
analyzeAndOptimizePerformance() {
|
|
1776
|
+
const stats = this.getTransmissionStats();
|
|
1777
|
+
const quality = this.flowControl.lastQuality;
|
|
1778
|
+
// 性能分析
|
|
1779
|
+
const analysis = {
|
|
1780
|
+
transmissionEfficiency: stats.successRate || 0,
|
|
1781
|
+
throughput: stats.transmissionSpeed || 0,
|
|
1782
|
+
stability: quality,
|
|
1783
|
+
retryRate: stats.totalCommands > 0 ?
|
|
1784
|
+
stats.retryCount / stats.totalCommands : 0
|
|
1785
|
+
};
|
|
1786
|
+
logger_1.logger.debug('性能分析:', analysis);
|
|
1787
|
+
// 根据分析结果优化参数
|
|
1788
|
+
if (analysis.transmissionEfficiency < 0.9) {
|
|
1789
|
+
// 传输效率低,减小分片大小
|
|
1790
|
+
this.setFlowControlParams({
|
|
1791
|
+
chunkSize: Math.max(this.flowControl.minChunkSize, this.flowControl.chunkSize - 10)
|
|
1792
|
+
});
|
|
1793
|
+
}
|
|
1794
|
+
else if (analysis.stability > 0.95 && analysis.retryRate < 0.1) {
|
|
1795
|
+
// 性能良好,尝试提高传输速度
|
|
1796
|
+
this.setFlowControlParams({
|
|
1797
|
+
chunkSize: Math.min(this.flowControl.maxChunkSize, this.flowControl.chunkSize + 5),
|
|
1798
|
+
chunkDelay: Math.max(this.flowControl.minChunkDelay, this.flowControl.chunkDelay - 2)
|
|
1799
|
+
});
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
/**
|
|
1803
|
+
* 诊断并修复常见问题
|
|
1804
|
+
*/
|
|
1805
|
+
async diagnoseAndRepair() {
|
|
1806
|
+
const issues = [];
|
|
1807
|
+
const repairs = [];
|
|
1808
|
+
let success = true;
|
|
1809
|
+
try {
|
|
1810
|
+
// 1. 检查初始化状态
|
|
1811
|
+
if (!this.isInitialized) {
|
|
1812
|
+
issues.push('蓝牙未初始化');
|
|
1813
|
+
logger_1.logger.info('尝试初始化蓝牙...');
|
|
1814
|
+
const initResult = await this.init();
|
|
1815
|
+
if (initResult) {
|
|
1816
|
+
repairs.push('成功初始化蓝牙');
|
|
1817
|
+
}
|
|
1818
|
+
else {
|
|
1819
|
+
success = false;
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
// 2. 检查连接状态
|
|
1823
|
+
if (!this.isConnected()) {
|
|
1824
|
+
issues.push('设备未连接');
|
|
1825
|
+
if (this.lastConnectedDevice) {
|
|
1826
|
+
logger_1.logger.info('尝试重新连接...');
|
|
1827
|
+
const connectResult = await this.connect(this.lastConnectedDevice);
|
|
1828
|
+
if (connectResult) {
|
|
1829
|
+
repairs.push('成功重新连接到设备');
|
|
1830
|
+
}
|
|
1831
|
+
else {
|
|
1832
|
+
success = false;
|
|
1833
|
+
}
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
// 3. 检查信号强度
|
|
1837
|
+
const deviceInfo = await this.getDeviceInfo();
|
|
1838
|
+
if ((deviceInfo === null || deviceInfo === void 0 ? void 0 : deviceInfo.RSSI) && deviceInfo.RSSI < this.RSSI_WARNING_THRESHOLD) {
|
|
1839
|
+
issues.push(`信号强度较弱: ${deviceInfo.RSSI}dBm`);
|
|
1840
|
+
repairs.push('建议靠近设备或排除信号干扰');
|
|
1841
|
+
}
|
|
1842
|
+
// 4. 检查传输质量
|
|
1843
|
+
const stats = this.getTransmissionStats();
|
|
1844
|
+
if ((stats.successRate || 0) < 0.9) {
|
|
1845
|
+
issues.push(`传输成功率较低: ${((stats.successRate || 0) * 100).toFixed(1)}%`);
|
|
1846
|
+
logger_1.logger.info('尝试优化传输参数...');
|
|
1847
|
+
this.analyzeAndOptimizePerformance();
|
|
1848
|
+
repairs.push('已优化传输参数');
|
|
1849
|
+
}
|
|
1850
|
+
// 5. 检查电池状态
|
|
1851
|
+
const batteryLevel = await this.getBatteryLevel();
|
|
1852
|
+
if (batteryLevel !== null && batteryLevel < 20) {
|
|
1853
|
+
issues.push(`设备电量低: ${batteryLevel}%`);
|
|
1854
|
+
repairs.push('建议及时充电');
|
|
1855
|
+
}
|
|
1856
|
+
// 6. 验证写入功能
|
|
1857
|
+
if (this.isConnected()) {
|
|
1858
|
+
const testData = new Uint8Array([0x00]).buffer;
|
|
1859
|
+
const writeResult = await this.writeData(testData).catch(() => false);
|
|
1860
|
+
if (!writeResult) {
|
|
1861
|
+
issues.push('数据写入测试失败');
|
|
1862
|
+
logger_1.logger.info('尝试重置连接...');
|
|
1863
|
+
await this.disconnect();
|
|
1864
|
+
await this.connect(this.lastConnectedDevice);
|
|
1865
|
+
repairs.push('已重置连接');
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
// 确定状态
|
|
1869
|
+
let status = 'healthy';
|
|
1870
|
+
if (issues.length > 0) {
|
|
1871
|
+
status = success ? 'warning' : 'error';
|
|
1872
|
+
}
|
|
1873
|
+
return {
|
|
1874
|
+
status,
|
|
1875
|
+
issues,
|
|
1876
|
+
repairs,
|
|
1877
|
+
success
|
|
1878
|
+
};
|
|
1879
|
+
}
|
|
1880
|
+
catch (error) {
|
|
1881
|
+
logger_1.logger.error('诊断过程出错', error);
|
|
1882
|
+
return {
|
|
1883
|
+
status: 'error',
|
|
1884
|
+
issues: [...issues, '诊断过程出错'],
|
|
1885
|
+
repairs,
|
|
1886
|
+
success: false
|
|
1887
|
+
};
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
/**
|
|
1891
|
+
* 添加命令到队列
|
|
1892
|
+
* @param command 命令数据
|
|
1893
|
+
* @param options 队列选项
|
|
1894
|
+
*/
|
|
1895
|
+
queueCommand(command, options = {}) {
|
|
1896
|
+
var _a, _b, _c;
|
|
1897
|
+
// 默认选项
|
|
1898
|
+
const priority = (_a = options.priority) !== null && _a !== void 0 ? _a : this.DEFAULT_COMMAND_PRIORITY;
|
|
1899
|
+
const maxRetries = (_b = options.maxRetries) !== null && _b !== void 0 ? _b : 2;
|
|
1900
|
+
const useChunks = (_c = options.useChunks) !== null && _c !== void 0 ? _c : (command.byteLength > this.flowControl.chunkSize);
|
|
1901
|
+
const description = options.description;
|
|
1902
|
+
// 创建唯一ID
|
|
1903
|
+
const id = `cmd_${Date.now()}_${Math.floor(Math.random() * 10000)}`;
|
|
1904
|
+
// 检查队列大小
|
|
1905
|
+
if (this.commandQueue.length >= this.QUEUE_MAX_SIZE) {
|
|
1906
|
+
logger_1.logger.warn(`命令队列已满(${this.QUEUE_MAX_SIZE}),拒绝新命令`);
|
|
1907
|
+
return Promise.reject(new types_1.PrinterError(types_1.ErrorCode.COMMAND_QUEUE_FULL, `命令队列已满,最大容量: ${this.QUEUE_MAX_SIZE}`));
|
|
1908
|
+
}
|
|
1909
|
+
// 创建Promise并添加到队列
|
|
1910
|
+
return new Promise((resolve, reject) => {
|
|
1911
|
+
this.commandQueue.push({
|
|
1912
|
+
id,
|
|
1913
|
+
command,
|
|
1914
|
+
priority,
|
|
1915
|
+
timestamp: Date.now(),
|
|
1916
|
+
retries: 0,
|
|
1917
|
+
maxRetries,
|
|
1918
|
+
resolve,
|
|
1919
|
+
reject,
|
|
1920
|
+
useChunks,
|
|
1921
|
+
description
|
|
1922
|
+
});
|
|
1923
|
+
// 按优先级排序队列
|
|
1924
|
+
this.sortQueue();
|
|
1925
|
+
logger_1.logger.debug(`命令已加入队列: ID=${id}, 大小=${command.byteLength}字节, 优先级=${priority}${description ? ', 描述=' + description : ''}`);
|
|
1926
|
+
// 启动队列处理
|
|
1927
|
+
this.startQueueProcessing();
|
|
1928
|
+
});
|
|
1929
|
+
}
|
|
1930
|
+
/**
|
|
1931
|
+
* 启动队列处理
|
|
1932
|
+
*/
|
|
1933
|
+
startQueueProcessing() {
|
|
1934
|
+
if (this.isProcessingQueue || this.queuePaused) {
|
|
1935
|
+
return;
|
|
1936
|
+
}
|
|
1937
|
+
this.isProcessingQueue = true;
|
|
1938
|
+
// 设置定时器处理队列
|
|
1939
|
+
this.processQueue();
|
|
1940
|
+
}
|
|
1941
|
+
/**
|
|
1942
|
+
* 处理命令队列
|
|
1943
|
+
*/
|
|
1944
|
+
async processQueue() {
|
|
1945
|
+
if (this.queuePaused) {
|
|
1946
|
+
this.isProcessingQueue = false;
|
|
1947
|
+
return;
|
|
1948
|
+
}
|
|
1949
|
+
// 检查是否有命令需要处理
|
|
1950
|
+
if (this.commandQueue.length === 0) {
|
|
1951
|
+
this.isProcessingQueue = false;
|
|
1952
|
+
return;
|
|
1953
|
+
}
|
|
1954
|
+
// 检查是否已连接
|
|
1955
|
+
if (!this.isConnected()) {
|
|
1956
|
+
logger_1.logger.warn('命令队列处理暂停: 设备未连接');
|
|
1957
|
+
this.isProcessingQueue = false;
|
|
1958
|
+
// 当设备重新连接时,会自动恢复队列处理
|
|
1959
|
+
return;
|
|
1960
|
+
}
|
|
1961
|
+
try {
|
|
1962
|
+
// 获取队首命令
|
|
1963
|
+
const cmd = this.commandQueue[0];
|
|
1964
|
+
logger_1.logger.debug(`处理队列命令: ID=${cmd.id}, 大小=${cmd.command.byteLength}字节${cmd.retries > 0 ? ', 重试=' + cmd.retries : ''}`);
|
|
1965
|
+
// 发送命令
|
|
1966
|
+
let result;
|
|
1967
|
+
if (cmd.useChunks) {
|
|
1968
|
+
result = await this.writeDataInChunks(cmd.command, this.flowControl.chunkSize, this.flowControl.chunkDelay);
|
|
1969
|
+
}
|
|
1970
|
+
else {
|
|
1971
|
+
result = await this.writeData(cmd.command);
|
|
1972
|
+
}
|
|
1973
|
+
if (result) {
|
|
1974
|
+
// 命令发送成功
|
|
1975
|
+
logger_1.logger.debug(`队列命令成功: ID=${cmd.id}`);
|
|
1976
|
+
cmd.resolve(true);
|
|
1977
|
+
this.commandQueue.shift(); // 移除队首命令
|
|
1978
|
+
}
|
|
1979
|
+
else {
|
|
1980
|
+
// 命令发送失败
|
|
1981
|
+
cmd.retries++;
|
|
1982
|
+
if (cmd.retries <= cmd.maxRetries) {
|
|
1983
|
+
logger_1.logger.debug(`队列命令失败,将重试: ID=${cmd.id}, 重试=${cmd.retries}/${cmd.maxRetries}`);
|
|
1984
|
+
// 重试时将命令移到队尾,以免阻塞其他命令
|
|
1985
|
+
const failedCmd = this.commandQueue.shift();
|
|
1986
|
+
// 等待延迟后再重试
|
|
1987
|
+
setTimeout(() => {
|
|
1988
|
+
this.commandQueue.push(failedCmd);
|
|
1989
|
+
this.sortQueue();
|
|
1990
|
+
}, 1000); // 等待1秒后重试
|
|
1991
|
+
}
|
|
1992
|
+
else {
|
|
1993
|
+
logger_1.logger.warn(`队列命令失败,超过最大重试次数: ID=${cmd.id}`);
|
|
1994
|
+
cmd.reject(new types_1.PrinterError(types_1.ErrorCode.COMMAND_FAILED, `命令执行失败,已重试${cmd.retries - 1}次`));
|
|
1995
|
+
this.commandQueue.shift(); // 移除队首命令
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
1999
|
+
catch (error) {
|
|
2000
|
+
// 处理错误
|
|
2001
|
+
const cmd = this.commandQueue[0];
|
|
2002
|
+
logger_1.logger.error(`队列命令执行出错: ID=${cmd.id}`, error);
|
|
2003
|
+
cmd.reject(error);
|
|
2004
|
+
this.commandQueue.shift(); // 移除队首命令
|
|
2005
|
+
}
|
|
2006
|
+
finally {
|
|
2007
|
+
// 继续处理队列中的下一条命令
|
|
2008
|
+
if (this.commandQueue.length > 0) {
|
|
2009
|
+
// 添加短延迟,避免过快发送
|
|
2010
|
+
this.queueProcessTimer = setTimeout(() => {
|
|
2011
|
+
this.processQueue();
|
|
2012
|
+
}, this.QUEUE_PROCESS_INTERVAL);
|
|
2013
|
+
}
|
|
2014
|
+
else {
|
|
2015
|
+
this.isProcessingQueue = false;
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
2019
|
+
/**
|
|
2020
|
+
* 按优先级排序队列
|
|
2021
|
+
*/
|
|
2022
|
+
sortQueue() {
|
|
2023
|
+
this.commandQueue.sort((a, b) => {
|
|
2024
|
+
// 首先按优先级排序(高优先级在前)
|
|
2025
|
+
if (a.priority !== b.priority) {
|
|
2026
|
+
return b.priority - a.priority;
|
|
2027
|
+
}
|
|
2028
|
+
// 其次按时间戳排序(先进先出)
|
|
2029
|
+
return a.timestamp - b.timestamp;
|
|
2030
|
+
});
|
|
2031
|
+
}
|
|
2032
|
+
/**
|
|
2033
|
+
* 暂停队列处理
|
|
2034
|
+
*/
|
|
2035
|
+
pauseCommandQueue() {
|
|
2036
|
+
this.queuePaused = true;
|
|
2037
|
+
logger_1.logger.info('命令队列处理已暂停');
|
|
2038
|
+
if (this.queueProcessTimer) {
|
|
2039
|
+
clearTimeout(this.queueProcessTimer);
|
|
2040
|
+
this.queueProcessTimer = null;
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
/**
|
|
2044
|
+
* 恢复队列处理
|
|
2045
|
+
*/
|
|
2046
|
+
resumeCommandQueue() {
|
|
2047
|
+
this.queuePaused = false;
|
|
2048
|
+
logger_1.logger.info(`命令队列处理已恢复,队列中有${this.commandQueue.length}条命令`);
|
|
2049
|
+
if (this.commandQueue.length > 0 && !this.isProcessingQueue) {
|
|
2050
|
+
this.startQueueProcessing();
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
/**
|
|
2054
|
+
* 清空命令队列
|
|
2055
|
+
* @param rejectRemaining 是否拒绝剩余命令
|
|
2056
|
+
*/
|
|
2057
|
+
clearCommandQueue(rejectRemaining = true) {
|
|
2058
|
+
const remainingCount = this.commandQueue.length;
|
|
2059
|
+
if (remainingCount === 0) {
|
|
2060
|
+
return 0;
|
|
2061
|
+
}
|
|
2062
|
+
if (rejectRemaining) {
|
|
2063
|
+
// 拒绝所有剩余命令
|
|
2064
|
+
const error = new types_1.PrinterError(types_1.ErrorCode.QUEUE_CLEARED, '命令队列已被清空');
|
|
2065
|
+
this.commandQueue.forEach(cmd => {
|
|
2066
|
+
cmd.reject(error);
|
|
2067
|
+
});
|
|
2068
|
+
}
|
|
2069
|
+
this.commandQueue = [];
|
|
2070
|
+
logger_1.logger.info(`命令队列已清空,丢弃了${remainingCount}条命令`);
|
|
2071
|
+
return remainingCount;
|
|
2072
|
+
}
|
|
2073
|
+
/**
|
|
2074
|
+
* 获取队列状态
|
|
2075
|
+
*/
|
|
2076
|
+
getQueueStatus() {
|
|
2077
|
+
const highPriorityCount = this.commandQueue.filter(cmd => cmd.priority >= this.HIGH_PRIORITY).length;
|
|
2078
|
+
const lowPriorityCount = this.commandQueue.filter(cmd => cmd.priority <= this.LOW_PRIORITY).length;
|
|
2079
|
+
const normalPriorityCount = this.commandQueue.length - highPriorityCount - lowPriorityCount;
|
|
2080
|
+
return {
|
|
2081
|
+
queueLength: this.commandQueue.length,
|
|
2082
|
+
isPaused: this.queuePaused,
|
|
2083
|
+
isProcessing: this.isProcessingQueue,
|
|
2084
|
+
highPriorityCount,
|
|
2085
|
+
normalPriorityCount,
|
|
2086
|
+
lowPriorityCount
|
|
2087
|
+
};
|
|
2088
|
+
}
|
|
2089
|
+
// 修改原有写入方法,使用队列系统
|
|
2090
|
+
async writeCommands(commands, options = {}) {
|
|
2091
|
+
var _a;
|
|
2092
|
+
if (!this.isConnected()) {
|
|
2093
|
+
const error = new types_1.PrinterError(types_1.ErrorCode.PRINTER_NOT_CONNECTED, '未连接到蓝牙设备');
|
|
2094
|
+
throw error;
|
|
2095
|
+
}
|
|
2096
|
+
if (commands.length === 0) {
|
|
2097
|
+
return { success: true, failed: 0 };
|
|
2098
|
+
}
|
|
2099
|
+
// 重置传输统计
|
|
2100
|
+
this.resetTransmissionStats();
|
|
2101
|
+
// 计算总字节数
|
|
2102
|
+
let totalBytes = 0;
|
|
2103
|
+
for (const cmd of commands) {
|
|
2104
|
+
totalBytes += cmd.byteLength;
|
|
2105
|
+
}
|
|
2106
|
+
this.transmissionStats.totalBytes = totalBytes;
|
|
2107
|
+
this.transmissionStats.totalCommands = commands.length;
|
|
2108
|
+
this.transmissionStats.startTime = Date.now();
|
|
2109
|
+
logger_1.logger.info(`通过队列发送${commands.length}条命令,总大小${totalBytes}字节`);
|
|
2110
|
+
// 将所有命令添加到队列
|
|
2111
|
+
const promises = commands.map((cmd, index) => {
|
|
2112
|
+
var _a, _b;
|
|
2113
|
+
return this.queueCommand(cmd, {
|
|
2114
|
+
priority: options.highPriority ? this.HIGH_PRIORITY : this.DEFAULT_COMMAND_PRIORITY,
|
|
2115
|
+
maxRetries: (_a = options.retries) !== null && _a !== void 0 ? _a : 1,
|
|
2116
|
+
useChunks: (_b = options.useChunks) !== null && _b !== void 0 ? _b : true,
|
|
2117
|
+
description: `批量命令 ${index + 1}/${commands.length}`
|
|
2118
|
+
});
|
|
2119
|
+
});
|
|
2120
|
+
// 等待所有命令完成
|
|
2121
|
+
try {
|
|
2122
|
+
const results = await Promise.allSettled(promises);
|
|
2123
|
+
// 统计成功和失败
|
|
2124
|
+
let successCount = 0;
|
|
2125
|
+
let successfulBytes = 0;
|
|
2126
|
+
results.forEach((result, index) => {
|
|
2127
|
+
if (result.status === 'fulfilled' && result.value) {
|
|
2128
|
+
successCount++;
|
|
2129
|
+
successfulBytes += commands[index].byteLength;
|
|
2130
|
+
}
|
|
2131
|
+
});
|
|
2132
|
+
// 更新传输统计
|
|
2133
|
+
this.transmissionStats.endTime = Date.now();
|
|
2134
|
+
this.transmissionStats.successfulBytes = successfulBytes;
|
|
2135
|
+
this.transmissionStats.successfulCommands = successCount;
|
|
2136
|
+
// 计算传输速度和质量
|
|
2137
|
+
const transmissionTime = this.transmissionStats.endTime - this.transmissionStats.startTime;
|
|
2138
|
+
const transmissionSpeed = transmissionTime > 0 ?
|
|
2139
|
+
(successfulBytes * 1000 / transmissionTime) : 0;
|
|
2140
|
+
this.transmissionStats.lastTransmissionSpeed = Math.round(transmissionSpeed);
|
|
2141
|
+
const quality = (successfulBytes / totalBytes) || 0;
|
|
2142
|
+
this.flowControl.lastQuality = quality;
|
|
2143
|
+
// 自动调整传输参数
|
|
2144
|
+
if ((_a = options.autoAdjustParams) !== null && _a !== void 0 ? _a : this.flowControl.autoAdjust) {
|
|
2145
|
+
this.adjustTransmissionParams(quality, transmissionSpeed);
|
|
2146
|
+
}
|
|
2147
|
+
const success = successCount === commands.length;
|
|
2148
|
+
const failedCount = commands.length - successCount;
|
|
2149
|
+
if (!success) {
|
|
2150
|
+
logger_1.logger.error(`队列命令批量执行不完整,共${commands.length}条命令,成功${successCount}条,失败${failedCount}条`);
|
|
2151
|
+
// 触发批量写入不完整事件
|
|
2152
|
+
events_1.eventManager.emit(events_1.EVENTS.BLUETOOTH_BATCH_INCOMPLETE, {
|
|
2153
|
+
total: commands.length,
|
|
2154
|
+
success: successCount,
|
|
2155
|
+
failed: failedCount,
|
|
2156
|
+
transmissionStats: this.getTransmissionStats()
|
|
2157
|
+
});
|
|
2158
|
+
}
|
|
2159
|
+
else {
|
|
2160
|
+
logger_1.logger.debug(`队列命令批量执行完成,共${commands.length}条命令,耗时${transmissionTime}ms,速度${Math.round(transmissionSpeed)}字节/秒`);
|
|
2161
|
+
// 触发传输完成事件
|
|
2162
|
+
events_1.eventManager.emit(events_1.EVENTS.BLUETOOTH_TRANSMISSION_COMPLETE, {
|
|
2163
|
+
total: commands.length,
|
|
2164
|
+
bytes: successfulBytes,
|
|
2165
|
+
transmissionStats: this.getTransmissionStats()
|
|
2166
|
+
});
|
|
2167
|
+
}
|
|
2168
|
+
return {
|
|
2169
|
+
success,
|
|
2170
|
+
failed: failedCount,
|
|
2171
|
+
stats: this.getTransmissionStats()
|
|
2172
|
+
};
|
|
2173
|
+
}
|
|
2174
|
+
catch (error) {
|
|
2175
|
+
logger_1.logger.error('队列命令批量执行出错', error);
|
|
2176
|
+
throw error;
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2179
|
+
/**
|
|
2180
|
+
* 设置电源管理模式
|
|
2181
|
+
* @param enabled 是否启用节能模式
|
|
2182
|
+
* @param mode 节能模式类型
|
|
2183
|
+
* @param inactivityTimeout 不活动超时时间(毫秒)
|
|
2184
|
+
*/
|
|
2185
|
+
setPowerManagement(enabled, mode = 'balanced', inactivityTimeout = this.DEFAULT_INACTIVITY_TIMEOUT) {
|
|
2186
|
+
this.powerSavingEnabled = enabled;
|
|
2187
|
+
this.powerSavingMode = mode;
|
|
2188
|
+
this.inactivityTimeout = inactivityTimeout;
|
|
2189
|
+
// 清除现有定时器
|
|
2190
|
+
if (this.inactivityTimer) {
|
|
2191
|
+
clearTimeout(this.inactivityTimer);
|
|
2192
|
+
this.inactivityTimer = null;
|
|
2193
|
+
}
|
|
2194
|
+
if (enabled) {
|
|
2195
|
+
this.resetActivityTimer();
|
|
2196
|
+
logger_1.logger.info(`电源管理已启用,模式: ${mode}, 不活动超时: ${inactivityTimeout}ms`);
|
|
2197
|
+
if (mode === 'auto') {
|
|
2198
|
+
// 自动模式下,尝试根据设备电池电量决定节能策略
|
|
2199
|
+
this.detectBatteryAndAdjustPowerMode();
|
|
2200
|
+
}
|
|
2201
|
+
else {
|
|
2202
|
+
// 直接应用指定模式
|
|
2203
|
+
this.applyPowerMode(mode);
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
else {
|
|
2207
|
+
// 禁用节能模式,应用性能模式
|
|
2208
|
+
this.applyPowerMode('performance');
|
|
2209
|
+
logger_1.logger.info('电源管理已禁用,使用性能模式');
|
|
2210
|
+
}
|
|
2211
|
+
}
|
|
2212
|
+
/**
|
|
2213
|
+
* 更新活动状态,重置不活动计时器
|
|
2214
|
+
*/
|
|
2215
|
+
resetActivityTimer() {
|
|
2216
|
+
this.lastActivityTime = Date.now();
|
|
2217
|
+
if (!this.powerSavingEnabled) {
|
|
2218
|
+
return;
|
|
2219
|
+
}
|
|
2220
|
+
// 清除现有定时器
|
|
2221
|
+
if (this.inactivityTimer) {
|
|
2222
|
+
clearTimeout(this.inactivityTimer);
|
|
2223
|
+
}
|
|
2224
|
+
// 设置新定时器
|
|
2225
|
+
this.inactivityTimer = setTimeout(() => {
|
|
2226
|
+
this.handleInactivity();
|
|
2227
|
+
}, this.inactivityTimeout);
|
|
2228
|
+
}
|
|
2229
|
+
/**
|
|
2230
|
+
* 处理不活动状态
|
|
2231
|
+
*/
|
|
2232
|
+
handleInactivity() {
|
|
2233
|
+
if (!this.isConnected() || !this.powerSavingEnabled) {
|
|
2234
|
+
return;
|
|
2235
|
+
}
|
|
2236
|
+
const inactiveTime = Date.now() - this.lastActivityTime;
|
|
2237
|
+
logger_1.logger.debug(`设备不活动时间: ${Math.round(inactiveTime / 1000)}秒, 进入节能模式`);
|
|
2238
|
+
// 根据当前模式应用节能策略
|
|
2239
|
+
if (this.powerSavingMode === 'auto') {
|
|
2240
|
+
// 自动模式下应用平衡模式
|
|
2241
|
+
this.applyPowerMode('balanced');
|
|
2242
|
+
}
|
|
2243
|
+
else if (this.powerSavingMode === 'performance') {
|
|
2244
|
+
// 如果当前是性能模式,则切换到平衡模式
|
|
2245
|
+
this.applyPowerMode('balanced');
|
|
2246
|
+
}
|
|
2247
|
+
else {
|
|
2248
|
+
// 应用当前模式
|
|
2249
|
+
this.applyPowerMode(this.powerSavingMode);
|
|
2250
|
+
}
|
|
2251
|
+
// 减少电池检查频率
|
|
2252
|
+
this.adjustBatteryCheckInterval(60000); // 1分钟检查一次
|
|
2253
|
+
}
|
|
2254
|
+
/**
|
|
2255
|
+
* 根据电池电量自动调整电源模式
|
|
2256
|
+
*/
|
|
2257
|
+
async detectBatteryAndAdjustPowerMode() {
|
|
2258
|
+
if (!this.isConnected() || !this.powerSavingEnabled) {
|
|
2259
|
+
return;
|
|
2260
|
+
}
|
|
2261
|
+
try {
|
|
2262
|
+
const batteryLevel = await this.getBatteryLevel();
|
|
2263
|
+
if (batteryLevel === null) {
|
|
2264
|
+
// 无法获取电池电量,使用平衡模式
|
|
2265
|
+
this.applyPowerMode('balanced');
|
|
2266
|
+
return;
|
|
2267
|
+
}
|
|
2268
|
+
if (batteryLevel <= 15) {
|
|
2269
|
+
// 电量不足15%,使用激进节能模式
|
|
2270
|
+
this.applyPowerMode('aggressive');
|
|
2271
|
+
logger_1.logger.info(`设备电量低(${batteryLevel}%),切换到激进节能模式`);
|
|
2272
|
+
}
|
|
2273
|
+
else if (batteryLevel <= 30) {
|
|
2274
|
+
// 电量不足30%,使用平衡模式
|
|
2275
|
+
this.applyPowerMode('balanced');
|
|
2276
|
+
logger_1.logger.debug(`设备电量适中(${batteryLevel}%),使用平衡节能模式`);
|
|
2277
|
+
}
|
|
2278
|
+
else {
|
|
2279
|
+
// 电量充足,使用性能模式
|
|
2280
|
+
this.applyPowerMode('performance');
|
|
2281
|
+
logger_1.logger.debug(`设备电量充足(${batteryLevel}%),使用性能模式`);
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2284
|
+
catch (error) {
|
|
2285
|
+
logger_1.logger.warn('获取电池电量失败,使用平衡模式', error);
|
|
2286
|
+
this.applyPowerMode('balanced');
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
2289
|
+
/**
|
|
2290
|
+
* 应用指定的电源模式
|
|
2291
|
+
* @param mode 电源模式
|
|
2292
|
+
*/
|
|
2293
|
+
applyPowerMode(mode) {
|
|
2294
|
+
switch (mode) {
|
|
2295
|
+
case 'aggressive':
|
|
2296
|
+
this.qualityCheckInterval = 30000; // 30秒检查一次质量
|
|
2297
|
+
this.flowControl.chunkSize = 10;
|
|
2298
|
+
this.flowControl.delayBetweenChunks = 50;
|
|
2299
|
+
break;
|
|
2300
|
+
case 'balanced':
|
|
2301
|
+
this.qualityCheckInterval = 20000; // 20秒检查一次质量
|
|
2302
|
+
this.flowControl.chunkSize = 20;
|
|
2303
|
+
this.flowControl.delayBetweenChunks = 20;
|
|
2304
|
+
break;
|
|
2305
|
+
case 'performance':
|
|
2306
|
+
this.qualityCheckInterval = 10000; // 10秒检查一次质量
|
|
2307
|
+
this.flowControl.chunkSize = 40;
|
|
2308
|
+
this.flowControl.delayBetweenChunks = 10;
|
|
2309
|
+
break;
|
|
2310
|
+
}
|
|
2311
|
+
// 更新监控间隔
|
|
2312
|
+
if (this.connectionQualityInterval) {
|
|
2313
|
+
clearInterval(this.connectionQualityInterval);
|
|
2314
|
+
this.startQualityMonitoring();
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2317
|
+
/**
|
|
2318
|
+
* 调整电池检查间隔
|
|
2319
|
+
*/
|
|
2320
|
+
adjustBatteryCheckInterval(interval) {
|
|
2321
|
+
this.batteryCheckIntervalMs = interval;
|
|
2322
|
+
// 如果已启动电池监控,重新启动以应用新间隔
|
|
2323
|
+
if (this.batteryCheckInterval) {
|
|
2324
|
+
this.stopBatteryMonitoring();
|
|
2325
|
+
this.startBatteryMonitoring();
|
|
2326
|
+
}
|
|
2327
|
+
}
|
|
2328
|
+
/**
|
|
2329
|
+
* 启用调试模式
|
|
2330
|
+
* @param enabled 是否启用
|
|
2331
|
+
* @param logToConsole 是否将调试信息记录到控制台
|
|
2332
|
+
*/
|
|
2333
|
+
setDebugMode(enabled, logToConsole = false) {
|
|
2334
|
+
this.debugMode = enabled;
|
|
2335
|
+
this.debugLogEnabled = logToConsole;
|
|
2336
|
+
if (enabled) {
|
|
2337
|
+
this.debugEvents = []; // 清空之前的事件
|
|
2338
|
+
logger_1.logger.info(`蓝牙调试模式已${enabled ? '启用' : '禁用'}${logToConsole ? ',将记录到控制台' : ''}`);
|
|
2339
|
+
}
|
|
2340
|
+
}
|
|
2341
|
+
/**
|
|
2342
|
+
* 记录调试事件
|
|
2343
|
+
* @param type 事件类型
|
|
2344
|
+
* @param data 事件数据
|
|
2345
|
+
*/
|
|
2346
|
+
logDebugEvent(type, data) {
|
|
2347
|
+
if (!this.debugMode) {
|
|
2348
|
+
return;
|
|
2349
|
+
}
|
|
2350
|
+
// 添加到事件队列
|
|
2351
|
+
this.debugEvents.push({
|
|
2352
|
+
type,
|
|
2353
|
+
data,
|
|
2354
|
+
timestamp: Date.now()
|
|
2355
|
+
});
|
|
2356
|
+
// 限制队列大小
|
|
2357
|
+
if (this.debugEvents.length > this.MAX_DEBUG_EVENTS) {
|
|
2358
|
+
this.debugEvents.shift();
|
|
2359
|
+
}
|
|
2360
|
+
// 输出到控制台
|
|
2361
|
+
if (this.debugLogEnabled) {
|
|
2362
|
+
console.log(`[蓝牙调试] ${type}:`, data);
|
|
2363
|
+
}
|
|
2364
|
+
}
|
|
2365
|
+
/**
|
|
2366
|
+
* 获取调试事件日志
|
|
2367
|
+
* @param limit 最大返回数量,0表示全部
|
|
2368
|
+
*/
|
|
2369
|
+
getDebugEvents(limit = 0) {
|
|
2370
|
+
if (limit <= 0 || limit >= this.debugEvents.length) {
|
|
2371
|
+
return [...this.debugEvents];
|
|
2372
|
+
}
|
|
2373
|
+
return this.debugEvents.slice(-limit);
|
|
2374
|
+
}
|
|
2375
|
+
/**
|
|
2376
|
+
* 清除调试事件日志
|
|
2377
|
+
*/
|
|
2378
|
+
clearDebugEvents() {
|
|
2379
|
+
this.debugEvents = [];
|
|
2380
|
+
logger_1.logger.debug('调试事件日志已清空');
|
|
2381
|
+
}
|
|
2382
|
+
/**
|
|
2383
|
+
* 导出诊断报告
|
|
2384
|
+
* @returns 包含详细诊断信息的对象
|
|
2385
|
+
*/
|
|
2386
|
+
async exportDiagnosticReport() {
|
|
2387
|
+
// 收集设备信息
|
|
2388
|
+
const deviceInfo = await this.getDeviceInfo();
|
|
2389
|
+
const batteryLevel = await this.getBatteryLevel();
|
|
2390
|
+
const healthInfo = await this.diagnoseConnection();
|
|
2391
|
+
// 收集性能信息
|
|
2392
|
+
const performance = await this.getPerformanceReport();
|
|
2393
|
+
// 收集事件历史
|
|
2394
|
+
const events = this.debugMode ? this.getDebugEvents() : [];
|
|
2395
|
+
// 收集错误历史
|
|
2396
|
+
const errors = this.debugEvents
|
|
2397
|
+
.filter(event => event.type.includes('error') || event.type.includes('failed'))
|
|
2398
|
+
.map(event => ({
|
|
2399
|
+
type: event.type,
|
|
2400
|
+
data: event.data,
|
|
2401
|
+
timestamp: event.timestamp
|
|
2402
|
+
}));
|
|
2403
|
+
// 构建诊断报告
|
|
2404
|
+
const report = {
|
|
2405
|
+
timestamp: Date.now(),
|
|
2406
|
+
device: {
|
|
2407
|
+
id: this.connectedDeviceId,
|
|
2408
|
+
name: deviceInfo === null || deviceInfo === void 0 ? void 0 : deviceInfo.name,
|
|
2409
|
+
info: deviceInfo,
|
|
2410
|
+
batteryLevel,
|
|
2411
|
+
health: healthInfo
|
|
2412
|
+
},
|
|
2413
|
+
adapter: {
|
|
2414
|
+
initialized: this.isInitialized,
|
|
2415
|
+
discoveryActive: this.discoveryStarted,
|
|
2416
|
+
discoveredDevices: Array.from(this.discoveredDevices.values()).map(d => ({
|
|
2417
|
+
id: d.deviceId,
|
|
2418
|
+
name: d.name,
|
|
2419
|
+
rssi: d.RSSI
|
|
2420
|
+
}))
|
|
2421
|
+
},
|
|
2422
|
+
connection: {
|
|
2423
|
+
isConnected: this.isConnected(),
|
|
2424
|
+
uptime: this.getConnectionUptime(),
|
|
2425
|
+
reconnectAttempts: this.recoveryAttempts,
|
|
2426
|
+
lastReconnectTime: this.lastReconnectTime,
|
|
2427
|
+
serviceUUID: this.serviceUUID,
|
|
2428
|
+
characteristicUUID: this.characteristicUUID
|
|
2429
|
+
},
|
|
2430
|
+
performance,
|
|
2431
|
+
errors,
|
|
2432
|
+
events,
|
|
2433
|
+
config: {
|
|
2434
|
+
flowControl: this.getFlowControlParams(),
|
|
2435
|
+
powerSaving: {
|
|
2436
|
+
enabled: this.powerSavingEnabled,
|
|
2437
|
+
mode: this.powerSavingMode,
|
|
2438
|
+
inactivityTimeout: this.inactivityTimeout
|
|
2439
|
+
},
|
|
2440
|
+
queue: this.getQueueStatus(),
|
|
2441
|
+
autoReconnect: this.autoReconnect,
|
|
2442
|
+
maxReconnectAttempts: this.maxReconnectAttempts
|
|
2443
|
+
}
|
|
2444
|
+
};
|
|
2445
|
+
// 记录报告生成事件
|
|
2446
|
+
this.logDebugEvent('diagnostic_report_generated', {
|
|
2447
|
+
timestamp: report.timestamp,
|
|
2448
|
+
deviceId: this.connectedDeviceId
|
|
2449
|
+
});
|
|
2450
|
+
return report;
|
|
2451
|
+
}
|
|
2452
|
+
/**
|
|
2453
|
+
* 自动检测和解决常见问题
|
|
2454
|
+
* @returns 自动修复结果
|
|
2455
|
+
*/
|
|
2456
|
+
async autoTroubleshoot() {
|
|
2457
|
+
// 首先诊断连接
|
|
2458
|
+
const diagnosis = await this.diagnoseAndRepair();
|
|
2459
|
+
// 如果诊断修复失败,尝试更强力的修复方法
|
|
2460
|
+
if (!diagnosis.success) {
|
|
2461
|
+
logger_1.logger.info('常规诊断修复失败,尝试更强力的修复方法...');
|
|
2462
|
+
const issues = [...diagnosis.issues];
|
|
2463
|
+
const fixes = [...diagnosis.repairs];
|
|
2464
|
+
let success = false;
|
|
2465
|
+
try {
|
|
2466
|
+
// 1. 强制重置连接
|
|
2467
|
+
if (this.connectedDeviceId) {
|
|
2468
|
+
await this.disconnect();
|
|
2469
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
2470
|
+
}
|
|
2471
|
+
// 2. 重新初始化蓝牙适配器
|
|
2472
|
+
await this.destroy();
|
|
2473
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
2474
|
+
const initResult = await this.init();
|
|
2475
|
+
if (initResult) {
|
|
2476
|
+
fixes.push('已重置蓝牙适配器');
|
|
2477
|
+
// 3. 如果有上次连接的设备,尝试重新连接
|
|
2478
|
+
if (this.lastConnectedDevice) {
|
|
2479
|
+
const connectResult = await this.connect(this.lastConnectedDevice, {
|
|
2480
|
+
retries: 2,
|
|
2481
|
+
timeout: 10000
|
|
2482
|
+
});
|
|
2483
|
+
if (connectResult) {
|
|
2484
|
+
fixes.push(`已重新连接到设备: ${this.lastConnectedDevice}`);
|
|
2485
|
+
success = true;
|
|
2486
|
+
}
|
|
2487
|
+
else {
|
|
2488
|
+
issues.push('强制重连失败');
|
|
2489
|
+
}
|
|
2490
|
+
}
|
|
2491
|
+
else {
|
|
2492
|
+
issues.push('没有可重连的设备');
|
|
2493
|
+
}
|
|
2494
|
+
}
|
|
2495
|
+
else {
|
|
2496
|
+
issues.push('重置蓝牙适配器失败');
|
|
2497
|
+
}
|
|
2498
|
+
}
|
|
2499
|
+
catch (error) {
|
|
2500
|
+
issues.push(`自动修复过程出错: ${error instanceof Error ? error.message : String(error)}`);
|
|
2501
|
+
}
|
|
2502
|
+
// 记录自动修复结果
|
|
2503
|
+
this.logDebugEvent('auto_troubleshoot_result', {
|
|
2504
|
+
success,
|
|
2505
|
+
issues,
|
|
2506
|
+
fixes
|
|
2507
|
+
});
|
|
2508
|
+
return {
|
|
2509
|
+
issues,
|
|
2510
|
+
fixes,
|
|
2511
|
+
success,
|
|
2512
|
+
remainingIssues: success ? [] : issues
|
|
2513
|
+
};
|
|
2514
|
+
}
|
|
2515
|
+
// 记录自动修复结果
|
|
2516
|
+
this.logDebugEvent('auto_troubleshoot_result', {
|
|
2517
|
+
success: diagnosis.success,
|
|
2518
|
+
issues: diagnosis.issues,
|
|
2519
|
+
fixes: diagnosis.repairs
|
|
2520
|
+
});
|
|
2521
|
+
return {
|
|
2522
|
+
issues: diagnosis.issues,
|
|
2523
|
+
fixes: diagnosis.repairs,
|
|
2524
|
+
success: diagnosis.success,
|
|
2525
|
+
remainingIssues: diagnosis.success ? [] : diagnosis.issues
|
|
2526
|
+
};
|
|
2527
|
+
}
|
|
2528
|
+
/**
|
|
2529
|
+
* 模拟蓝牙环境,用于在没有真实设备的情况下进行测试
|
|
2530
|
+
* @param mockOptions 模拟选项
|
|
2531
|
+
*/
|
|
2532
|
+
enableMockEnvironment(mockOptions = {}) {
|
|
2533
|
+
var _a, _b, _c, _d;
|
|
2534
|
+
// 在生产环境中,此代码会被移除
|
|
2535
|
+
if (process.env.NODE_ENV === 'production') {
|
|
2536
|
+
logger_1.logger.warn('模拟环境不能在生产环境中启用');
|
|
2537
|
+
return;
|
|
2538
|
+
}
|
|
2539
|
+
// 默认选项
|
|
2540
|
+
const options = {
|
|
2541
|
+
simulateConnection: (_a = mockOptions.simulateConnection) !== null && _a !== void 0 ? _a : true,
|
|
2542
|
+
simulateDelay: (_b = mockOptions.simulateDelay) !== null && _b !== void 0 ? _b : 100,
|
|
2543
|
+
simulateErrors: (_c = mockOptions.simulateErrors) !== null && _c !== void 0 ? _c : false,
|
|
2544
|
+
errorRate: (_d = mockOptions.errorRate) !== null && _d !== void 0 ? _d : 0.1
|
|
2545
|
+
};
|
|
2546
|
+
logger_1.logger.info('启用蓝牙模拟环境', options);
|
|
2547
|
+
// 记录调试事件
|
|
2548
|
+
this.logDebugEvent('mock_environment_enabled', options);
|
|
2549
|
+
// 模拟蓝牙设备
|
|
2550
|
+
const mockDevice = {
|
|
2551
|
+
deviceId: 'mock_device_001',
|
|
2552
|
+
name: '模拟蓝牙打印机',
|
|
2553
|
+
RSSI: -60
|
|
2554
|
+
};
|
|
2555
|
+
// 覆盖方法以模拟蓝牙行为
|
|
2556
|
+
if (options.simulateConnection) {
|
|
2557
|
+
// 劫持实例方法
|
|
2558
|
+
const originalConnect = this.connect.bind(this);
|
|
2559
|
+
this.connect = async (deviceId) => {
|
|
2560
|
+
this.logDebugEvent('mock_connect', { deviceId });
|
|
2561
|
+
await new Promise(resolve => setTimeout(resolve, options.simulateDelay));
|
|
2562
|
+
// 模拟随机错误
|
|
2563
|
+
if (options.simulateErrors && Math.random() < options.errorRate) {
|
|
2564
|
+
this.logDebugEvent('mock_connect_error', { deviceId });
|
|
2565
|
+
return false;
|
|
2566
|
+
}
|
|
2567
|
+
this.connectedDeviceId = deviceId;
|
|
2568
|
+
this.logDebugEvent('mock_connect_success', { deviceId });
|
|
2569
|
+
return true;
|
|
2570
|
+
};
|
|
2571
|
+
// 添加模拟设备到已发现设备列表
|
|
2572
|
+
this.discoveredDevices.set(mockDevice.deviceId, mockDevice);
|
|
2573
|
+
}
|
|
2574
|
+
// 警告提示
|
|
2575
|
+
console.warn('蓝牙模拟环境已启用,这不会与真实设备通信');
|
|
2576
|
+
}
|
|
2577
|
+
/**
|
|
2578
|
+
* 获取连接活动日志
|
|
2579
|
+
* 用于分析连接行为和调试问题
|
|
2580
|
+
* @param maxEntries 最大条目数
|
|
2581
|
+
*/
|
|
2582
|
+
getConnectionActivityLog(maxEntries = 50) {
|
|
2583
|
+
return this.debugEvents
|
|
2584
|
+
.filter(event => event.type.includes('connect') ||
|
|
2585
|
+
event.type.includes('disconnect') ||
|
|
2586
|
+
event.type.includes('write') ||
|
|
2587
|
+
event.type.includes('discover'))
|
|
2588
|
+
.slice(-maxEntries);
|
|
2589
|
+
}
|
|
2590
|
+
/**
|
|
2591
|
+
* 初始化性能优化系统
|
|
2592
|
+
*/
|
|
2593
|
+
initPerformanceOptimizations() {
|
|
2594
|
+
// 初始化缓冲区池
|
|
2595
|
+
this.initBufferPool();
|
|
2596
|
+
// 启动性能监控
|
|
2597
|
+
this.startPerformanceMonitoring();
|
|
2598
|
+
// 启动垃圾回收计时器
|
|
2599
|
+
this.startGarbageCollector();
|
|
2600
|
+
logger_1.logger.debug('已初始化性能优化系统');
|
|
2601
|
+
}
|
|
2602
|
+
/**
|
|
2603
|
+
* 初始化缓冲区池
|
|
2604
|
+
*/
|
|
2605
|
+
initBufferPool() {
|
|
2606
|
+
// 为每种大小创建缓冲区池
|
|
2607
|
+
for (const size of this.performanceConfig.bufferSizes) {
|
|
2608
|
+
const buffers = [];
|
|
2609
|
+
for (let i = 0; i < this.performanceConfig.bufferPoolSize; i++) {
|
|
2610
|
+
buffers.push(new ArrayBuffer(size));
|
|
2611
|
+
}
|
|
2612
|
+
this.bufferPool.set(size, buffers);
|
|
2613
|
+
}
|
|
2614
|
+
logger_1.logger.debug(`缓冲区池已初始化,支持 ${this.performanceConfig.bufferSizes.join(', ')} 字节大小`);
|
|
2615
|
+
}
|
|
2616
|
+
/**
|
|
2617
|
+
* 从缓冲区池获取缓冲区
|
|
2618
|
+
* @param size 需要的缓冲区大小
|
|
2619
|
+
*/
|
|
2620
|
+
getBufferFromPool(size) {
|
|
2621
|
+
// 找到最接近且不小于请求大小的缓冲区类型
|
|
2622
|
+
const availableSizes = [...this.performanceConfig.bufferSizes].sort((a, b) => a - b);
|
|
2623
|
+
let bestFitSize = availableSizes.find(s => s >= size) || availableSizes[availableSizes.length - 1];
|
|
2624
|
+
// 如果找不到合适的大小,直接创建新缓冲区
|
|
2625
|
+
if (bestFitSize < size) {
|
|
2626
|
+
return new ArrayBuffer(size);
|
|
2627
|
+
}
|
|
2628
|
+
// 从池中获取
|
|
2629
|
+
const pool = this.bufferPool.get(bestFitSize);
|
|
2630
|
+
if (pool && pool.length > 0) {
|
|
2631
|
+
return pool.pop();
|
|
2632
|
+
}
|
|
2633
|
+
// 池为空,创建新缓冲区
|
|
2634
|
+
return new ArrayBuffer(bestFitSize);
|
|
2635
|
+
}
|
|
2636
|
+
/**
|
|
2637
|
+
* 将缓冲区归还池
|
|
2638
|
+
* @param buffer 要归还的缓冲区
|
|
2639
|
+
*/
|
|
2640
|
+
returnBufferToPool(buffer) {
|
|
2641
|
+
const size = buffer.byteLength;
|
|
2642
|
+
// 检查是否是支持的大小
|
|
2643
|
+
if (!this.performanceConfig.bufferSizes.includes(size)) {
|
|
2644
|
+
return; // 不支持的大小,丢弃
|
|
2645
|
+
}
|
|
2646
|
+
// 获取对应的池
|
|
2647
|
+
const pool = this.bufferPool.get(size);
|
|
2648
|
+
if (pool && pool.length < this.performanceConfig.bufferPoolSize * 2) {
|
|
2649
|
+
pool.push(buffer);
|
|
2650
|
+
}
|
|
2651
|
+
}
|
|
2652
|
+
/**
|
|
2653
|
+
* 启动性能监控
|
|
2654
|
+
*/
|
|
2655
|
+
startPerformanceMonitoring() {
|
|
2656
|
+
if (this.performanceMonitorInterval) {
|
|
2657
|
+
clearInterval(this.performanceMonitorInterval);
|
|
2658
|
+
}
|
|
2659
|
+
this.performanceMonitorInterval = setInterval(() => {
|
|
2660
|
+
this.analyzePerformanceMetrics();
|
|
2661
|
+
}, 60000); // 每分钟分析一次
|
|
2662
|
+
}
|
|
2663
|
+
/**
|
|
2664
|
+
* 分析性能指标并进行自动优化
|
|
2665
|
+
*/
|
|
2666
|
+
analyzePerformanceMetrics() {
|
|
2667
|
+
if (!this.isConnected()) {
|
|
2668
|
+
return;
|
|
2669
|
+
}
|
|
2670
|
+
try {
|
|
2671
|
+
// 计算平均写入时间
|
|
2672
|
+
const avgWriteTime = this.calculateAverage(this.statsAggregator.writeTimes);
|
|
2673
|
+
// 计算连接稳定性
|
|
2674
|
+
const stabilityScore = this.calculateStabilityScore();
|
|
2675
|
+
// 分析错误模式
|
|
2676
|
+
const mostCommonError = this.getMostCommonError();
|
|
2677
|
+
// 超过阈值时自动优化
|
|
2678
|
+
if (avgWriteTime > 100) { // 写入平均超过100ms
|
|
2679
|
+
// 减小批量大小,增加间隔
|
|
2680
|
+
this.performanceConfig.commandBatchSize = Math.max(1, this.performanceConfig.commandBatchSize - 1);
|
|
2681
|
+
this.flowControl.chunkDelay = Math.min(this.flowControl.maxChunkDelay, this.flowControl.chunkDelay + 5);
|
|
2682
|
+
}
|
|
2683
|
+
else if (avgWriteTime < 20 && stabilityScore > 0.9) { // 写入速度快且稳定
|
|
2684
|
+
// 增大批量大小,减少间隔
|
|
2685
|
+
this.performanceConfig.commandBatchSize = Math.min(20, this.performanceConfig.commandBatchSize + 1);
|
|
2686
|
+
this.flowControl.chunkDelay = Math.max(this.flowControl.minChunkDelay, this.flowControl.chunkDelay - 2);
|
|
2687
|
+
}
|
|
2688
|
+
// 根据错误模式调整
|
|
2689
|
+
if (mostCommonError) {
|
|
2690
|
+
if (mostCommonError.includes('timeout')) {
|
|
2691
|
+
// 超时问题,调整重试间隔
|
|
2692
|
+
this.currentRecoveryDelay = Math.min(5000, this.currentRecoveryDelay + 500);
|
|
2693
|
+
}
|
|
2694
|
+
else if (mostCommonError.includes('failed')) {
|
|
2695
|
+
// 写入失败,可能是数据问题
|
|
2696
|
+
this.flowControl.chunkSize = Math.max(this.flowControl.minChunkSize, this.flowControl.chunkSize - 5);
|
|
2697
|
+
}
|
|
2698
|
+
}
|
|
2699
|
+
// 清理收集的统计数据
|
|
2700
|
+
this.trimPerformanceStats();
|
|
2701
|
+
logger_1.logger.debug('性能自动优化完成', {
|
|
2702
|
+
avgWriteTime,
|
|
2703
|
+
stabilityScore,
|
|
2704
|
+
commandBatchSize: this.performanceConfig.commandBatchSize,
|
|
2705
|
+
chunkDelay: this.flowControl.chunkDelay,
|
|
2706
|
+
chunkSize: this.flowControl.chunkSize
|
|
2707
|
+
});
|
|
2708
|
+
}
|
|
2709
|
+
catch (error) {
|
|
2710
|
+
logger_1.logger.warn('性能指标分析失败', error);
|
|
2711
|
+
}
|
|
2712
|
+
}
|
|
2713
|
+
/**
|
|
2714
|
+
* 计算稳定性分数
|
|
2715
|
+
*/
|
|
2716
|
+
calculateStabilityScore() {
|
|
2717
|
+
if (this.statsAggregator.writeTimes.length === 0) {
|
|
2718
|
+
return 1.0;
|
|
2719
|
+
}
|
|
2720
|
+
// 计算成功率
|
|
2721
|
+
const successRate = this.transmissionStats.successfulBytes / Math.max(1, this.transmissionStats.totalBytes);
|
|
2722
|
+
// 计算错误率
|
|
2723
|
+
const errorRate = this.connectionStateCache.consecutiveErrorCount / Math.max(1, this.statsAggregator.writeTimes.length);
|
|
2724
|
+
// 计算写入时间的标准差(时间波动性)
|
|
2725
|
+
const avgWriteTime = this.calculateAverage(this.statsAggregator.writeTimes);
|
|
2726
|
+
const stdDevWriteTime = this.calculateStdDev(this.statsAggregator.writeTimes, avgWriteTime);
|
|
2727
|
+
const normalizedStdDev = stdDevWriteTime / Math.max(1, avgWriteTime);
|
|
2728
|
+
// 综合评分 (0-1之间,越高越稳定)
|
|
2729
|
+
return 0.4 * successRate + 0.3 * (1 - errorRate) + 0.3 * (1 - Math.min(1, normalizedStdDev));
|
|
2730
|
+
}
|
|
2731
|
+
/**
|
|
2732
|
+
* 获取最常见的错误类型
|
|
2733
|
+
*/
|
|
2734
|
+
getMostCommonError() {
|
|
2735
|
+
const errorCounts = {};
|
|
2736
|
+
let maxCount = 0;
|
|
2737
|
+
let mostCommonError = null;
|
|
2738
|
+
for (const [error, count] of this.statsAggregator.errorCounts.entries()) {
|
|
2739
|
+
errorCounts[error] = (errorCounts[error] || 0) + count;
|
|
2740
|
+
if (count > maxCount) {
|
|
2741
|
+
maxCount = count;
|
|
2742
|
+
mostCommonError = error;
|
|
2743
|
+
}
|
|
2744
|
+
}
|
|
2745
|
+
return mostCommonError;
|
|
2746
|
+
}
|
|
2747
|
+
/**
|
|
2748
|
+
* 裁剪性能统计数据
|
|
2749
|
+
*/
|
|
2750
|
+
trimPerformanceStats() {
|
|
2751
|
+
// 保留最新的N个数据点
|
|
2752
|
+
const keepCount = 100;
|
|
2753
|
+
if (this.statsAggregator.writeTimes.length > keepCount) {
|
|
2754
|
+
this.statsAggregator.writeTimes = this.statsAggregator.writeTimes.slice(-keepCount);
|
|
2755
|
+
}
|
|
2756
|
+
if (this.statsAggregator.readTimes.length > keepCount) {
|
|
2757
|
+
this.statsAggregator.readTimes = this.statsAggregator.readTimes.slice(-keepCount);
|
|
2758
|
+
}
|
|
2759
|
+
if (this.statsAggregator.connectTimes.length > keepCount) {
|
|
2760
|
+
this.statsAggregator.connectTimes = this.statsAggregator.connectTimes.slice(-keepCount);
|
|
2761
|
+
}
|
|
2762
|
+
if (this.statsAggregator.discoverTimes.length > keepCount) {
|
|
2763
|
+
this.statsAggregator.discoverTimes = this.statsAggregator.discoverTimes.slice(-keepCount);
|
|
2764
|
+
}
|
|
2765
|
+
// 定期清理错误计数
|
|
2766
|
+
if (this.statsAggregator.errorCounts.size > 20) {
|
|
2767
|
+
// 只保留出现频率较高的错误
|
|
2768
|
+
const entries = [...this.statsAggregator.errorCounts.entries()]
|
|
2769
|
+
.sort((a, b) => b[1] - a[1])
|
|
2770
|
+
.slice(0, 10);
|
|
2771
|
+
this.statsAggregator.errorCounts = new Map(entries);
|
|
2772
|
+
}
|
|
2773
|
+
}
|
|
2774
|
+
/**
|
|
2775
|
+
* 计算数组平均值
|
|
2776
|
+
*/
|
|
2777
|
+
calculateAverage(arr) {
|
|
2778
|
+
if (arr.length === 0)
|
|
2779
|
+
return 0;
|
|
2780
|
+
return arr.reduce((sum, val) => sum + val, 0) / arr.length;
|
|
2781
|
+
}
|
|
2782
|
+
/**
|
|
2783
|
+
* 计算标准差
|
|
2784
|
+
*/
|
|
2785
|
+
calculateStdDev(arr, avg) {
|
|
2786
|
+
if (arr.length === 0)
|
|
2787
|
+
return 0;
|
|
2788
|
+
const mean = avg !== undefined ? avg : this.calculateAverage(arr);
|
|
2789
|
+
const squareDiffs = arr.map(value => {
|
|
2790
|
+
const diff = value - mean;
|
|
2791
|
+
return diff * diff;
|
|
2792
|
+
});
|
|
2793
|
+
return Math.sqrt(this.calculateAverage(squareDiffs));
|
|
2794
|
+
}
|
|
2795
|
+
/**
|
|
2796
|
+
* 启动垃圾回收计时器
|
|
2797
|
+
*/
|
|
2798
|
+
startGarbageCollector() {
|
|
2799
|
+
setInterval(() => {
|
|
2800
|
+
this.performGarbageCollection();
|
|
2801
|
+
}, this.performanceConfig.gcInterval);
|
|
2802
|
+
}
|
|
2803
|
+
/**
|
|
2804
|
+
* 执行垃圾回收
|
|
2805
|
+
*/
|
|
2806
|
+
performGarbageCollection() {
|
|
2807
|
+
try {
|
|
2808
|
+
// 清理设备信息缓存
|
|
2809
|
+
const now = Date.now();
|
|
2810
|
+
for (const [deviceId, entry] of this.deviceInfoCache.entries()) {
|
|
2811
|
+
if (now - entry.timestamp > this.performanceConfig.deviceCacheLifetime) {
|
|
2812
|
+
this.deviceInfoCache.delete(deviceId);
|
|
2813
|
+
}
|
|
2814
|
+
}
|
|
2815
|
+
// 清理调试事件
|
|
2816
|
+
if (this.debugEvents.length > this.performanceConfig.eventHistoryTrimSize) {
|
|
2817
|
+
this.debugEvents = this.debugEvents.slice(-this.performanceConfig.eventHistoryTrimSize / 2);
|
|
2818
|
+
}
|
|
2819
|
+
// 优化缓冲区池
|
|
2820
|
+
for (const [size, pool] of this.bufferPool.entries()) {
|
|
2821
|
+
if (pool.length > this.performanceConfig.bufferPoolSize * 1.5) {
|
|
2822
|
+
this.bufferPool.set(size, pool.slice(0, this.performanceConfig.bufferPoolSize));
|
|
2823
|
+
}
|
|
2824
|
+
}
|
|
2825
|
+
// 如果长时间无活动,释放更多资源
|
|
2826
|
+
if (Date.now() - this.lastActivityTime > this.performanceConfig.inactiveResourceTimeout) {
|
|
2827
|
+
// 停止不必要的监控
|
|
2828
|
+
this.stopQualityMonitoring();
|
|
2829
|
+
// 清空缓冲区池
|
|
2830
|
+
for (const size of this.performanceConfig.bufferSizes) {
|
|
2831
|
+
this.bufferPool.set(size, []);
|
|
2832
|
+
}
|
|
2833
|
+
logger_1.logger.debug('长时间无活动,已释放资源');
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2836
|
+
catch (error) {
|
|
2837
|
+
logger_1.logger.warn('执行垃圾回收失败', error);
|
|
2838
|
+
}
|
|
2839
|
+
}
|
|
2840
|
+
/**
|
|
2841
|
+
* 获取缓存的设备信息
|
|
2842
|
+
*/
|
|
2843
|
+
getCachedDeviceInfo(deviceId) {
|
|
2844
|
+
const cached = this.deviceInfoCache.get(deviceId);
|
|
2845
|
+
if (cached && Date.now() - cached.timestamp < this.performanceConfig.deviceCacheLifetime) {
|
|
2846
|
+
return cached.info;
|
|
2847
|
+
}
|
|
2848
|
+
return null;
|
|
2849
|
+
}
|
|
2850
|
+
/**
|
|
2851
|
+
* 更新设备信息缓存
|
|
2852
|
+
*/
|
|
2853
|
+
updateDeviceInfoCache(deviceId, info) {
|
|
2854
|
+
this.deviceInfoCache.set(deviceId, {
|
|
2855
|
+
info,
|
|
2856
|
+
timestamp: Date.now()
|
|
2857
|
+
});
|
|
2858
|
+
}
|
|
2859
|
+
/**
|
|
2860
|
+
* 记录操作耗时
|
|
2861
|
+
*/
|
|
2862
|
+
recordOperationTime(operation, timeMs) {
|
|
2863
|
+
switch (operation) {
|
|
2864
|
+
case 'write':
|
|
2865
|
+
this.statsAggregator.writeTimes.push(timeMs);
|
|
2866
|
+
break;
|
|
2867
|
+
case 'read':
|
|
2868
|
+
this.statsAggregator.readTimes.push(timeMs);
|
|
2869
|
+
break;
|
|
2870
|
+
case 'connect':
|
|
2871
|
+
this.statsAggregator.connectTimes.push(timeMs);
|
|
2872
|
+
break;
|
|
2873
|
+
case 'discover':
|
|
2874
|
+
this.statsAggregator.discoverTimes.push(timeMs);
|
|
2875
|
+
break;
|
|
2876
|
+
}
|
|
2877
|
+
}
|
|
2878
|
+
/**
|
|
2879
|
+
* 记录错误
|
|
2880
|
+
*/
|
|
2881
|
+
recordError(errorType) {
|
|
2882
|
+
const count = this.statsAggregator.errorCounts.get(errorType) || 0;
|
|
2883
|
+
this.statsAggregator.errorCounts.set(errorType, count + 1);
|
|
2884
|
+
// 更新连续错误计数
|
|
2885
|
+
this.connectionStateCache.consecutiveErrorCount++;
|
|
2886
|
+
}
|
|
2887
|
+
/**
|
|
2888
|
+
* 记录成功操作
|
|
2889
|
+
*/
|
|
2890
|
+
recordSuccess() {
|
|
2891
|
+
// 重置连续错误计数
|
|
2892
|
+
this.connectionStateCache.consecutiveErrorCount = 0;
|
|
2893
|
+
this.connectionStateCache.lastSuccessTime = Date.now();
|
|
2894
|
+
}
|
|
2895
|
+
/**
|
|
2896
|
+
* 设置性能配置参数
|
|
2897
|
+
* @param config 性能配置
|
|
2898
|
+
*/
|
|
2899
|
+
setPerformanceConfig(config) {
|
|
2900
|
+
this.performanceConfig = Object.assign(Object.assign({}, this.performanceConfig), config);
|
|
2901
|
+
// 如果修改了缓冲区大小,重新初始化缓冲区池
|
|
2902
|
+
if (config.bufferSizes || config.bufferPoolSize) {
|
|
2903
|
+
this.initBufferPool();
|
|
2904
|
+
}
|
|
2905
|
+
logger_1.logger.debug('已更新性能配置', this.performanceConfig);
|
|
2906
|
+
}
|
|
2907
|
+
/**
|
|
2908
|
+
* 获取当前性能配置
|
|
2909
|
+
*/
|
|
2910
|
+
getPerformanceConfig() {
|
|
2911
|
+
return Object.assign({}, this.performanceConfig);
|
|
2912
|
+
}
|
|
2913
|
+
/**
|
|
2914
|
+
* 获取性能统计信息
|
|
2915
|
+
*/
|
|
2916
|
+
getPerformanceStats() {
|
|
2917
|
+
// 计算各操作的统计信息
|
|
2918
|
+
const writeAvg = this.calculateAverage(this.statsAggregator.writeTimes);
|
|
2919
|
+
const readAvg = this.calculateAverage(this.statsAggregator.readTimes);
|
|
2920
|
+
const connectAvg = this.calculateAverage(this.statsAggregator.connectTimes);
|
|
2921
|
+
const discoverAvg = this.calculateAverage(this.statsAggregator.discoverTimes);
|
|
2922
|
+
return {
|
|
2923
|
+
operations: {
|
|
2924
|
+
write: {
|
|
2925
|
+
count: this.statsAggregator.writeTimes.length,
|
|
2926
|
+
avgTime: writeAvg,
|
|
2927
|
+
stdDev: this.calculateStdDev(this.statsAggregator.writeTimes, writeAvg)
|
|
2928
|
+
},
|
|
2929
|
+
read: {
|
|
2930
|
+
count: this.statsAggregator.readTimes.length,
|
|
2931
|
+
avgTime: readAvg,
|
|
2932
|
+
stdDev: this.calculateStdDev(this.statsAggregator.readTimes, readAvg)
|
|
2933
|
+
},
|
|
2934
|
+
connect: {
|
|
2935
|
+
count: this.statsAggregator.connectTimes.length,
|
|
2936
|
+
avgTime: connectAvg,
|
|
2937
|
+
stdDev: this.calculateStdDev(this.statsAggregator.connectTimes, connectAvg)
|
|
2938
|
+
},
|
|
2939
|
+
discover: {
|
|
2940
|
+
count: this.statsAggregator.discoverTimes.length,
|
|
2941
|
+
avgTime: discoverAvg,
|
|
2942
|
+
stdDev: this.calculateStdDev(this.statsAggregator.discoverTimes, discoverAvg)
|
|
2943
|
+
}
|
|
2944
|
+
},
|
|
2945
|
+
memoryUsage: {
|
|
2946
|
+
bufferPoolSize: [...this.bufferPool.values()].reduce((total, pool) => total + pool.length, 0),
|
|
2947
|
+
deviceCacheSize: this.deviceInfoCache.size,
|
|
2948
|
+
eventHistorySize: this.debugEvents.length
|
|
2949
|
+
},
|
|
2950
|
+
stability: {
|
|
2951
|
+
score: this.calculateStabilityScore(),
|
|
2952
|
+
consecutiveErrors: this.connectionStateCache.consecutiveErrorCount,
|
|
2953
|
+
errorDistribution: Object.fromEntries(this.statsAggregator.errorCounts)
|
|
2954
|
+
}
|
|
2955
|
+
};
|
|
2956
|
+
}
|
|
2957
|
+
// 添加高级缓存相关方法
|
|
2958
|
+
/**
|
|
2959
|
+
* 预热缓存,提前加载常用数据到缓存
|
|
2960
|
+
* 在应用启动时或需要准备大量操作前调用,可提高后续操作速度
|
|
2961
|
+
*/
|
|
2962
|
+
async preloadCache() {
|
|
2963
|
+
try {
|
|
2964
|
+
// 预加载最近使用的设备信息
|
|
2965
|
+
const recentDevices = Array.from(this.connectionHistory.entries())
|
|
2966
|
+
.sort((a, b) => b[1].lastConnected - a[1].lastConnected)
|
|
2967
|
+
.slice(0, 5);
|
|
2968
|
+
for (const [deviceId] of recentDevices) {
|
|
2969
|
+
const deviceInfo = await this.getDeviceInfo(deviceId);
|
|
2970
|
+
if (deviceInfo) {
|
|
2971
|
+
this.updateDeviceInfoCache(deviceId, deviceInfo);
|
|
2972
|
+
}
|
|
2973
|
+
}
|
|
2974
|
+
// 初始化常用大小的缓冲区池
|
|
2975
|
+
this.initBufferPool();
|
|
2976
|
+
logger_1.logger.info('缓存预加载完成');
|
|
2977
|
+
}
|
|
2978
|
+
catch (error) {
|
|
2979
|
+
logger_1.logger.error('缓存预加载失败:', error);
|
|
2980
|
+
}
|
|
2981
|
+
}
|
|
2982
|
+
/**
|
|
2983
|
+
* 清理缓存,释放内存
|
|
2984
|
+
* @param type 指定要清理的缓存类型,默认全部
|
|
2985
|
+
*/
|
|
2986
|
+
clearCache(type) {
|
|
2987
|
+
if (!type || type === 'all' || type === 'device') {
|
|
2988
|
+
this.deviceInfoCache.clear();
|
|
2989
|
+
logger_1.logger.debug('设备信息缓存已清空');
|
|
2990
|
+
}
|
|
2991
|
+
if (!type || type === 'all' || type === 'buffer') {
|
|
2992
|
+
for (const size of this.performanceConfig.bufferSizes) {
|
|
2993
|
+
this.bufferPool.set(size, []);
|
|
2994
|
+
}
|
|
2995
|
+
logger_1.logger.debug('缓冲区池已清空');
|
|
2996
|
+
}
|
|
2997
|
+
if (!type || type === 'all' || type === 'stats') {
|
|
2998
|
+
this.statsAggregator.writeTimes = [];
|
|
2999
|
+
this.statsAggregator.readTimes = [];
|
|
3000
|
+
this.statsAggregator.connectTimes = [];
|
|
3001
|
+
this.statsAggregator.discoverTimes = [];
|
|
3002
|
+
this.statsAggregator.errorCounts.clear();
|
|
3003
|
+
logger_1.logger.debug('性能统计缓存已清空');
|
|
3004
|
+
}
|
|
3005
|
+
if (type === 'all') {
|
|
3006
|
+
// 触发垃圾回收
|
|
3007
|
+
this.performGarbageCollection();
|
|
3008
|
+
}
|
|
3009
|
+
}
|
|
3010
|
+
/**
|
|
3011
|
+
* 优化缓存大小,根据当前情况调整缓存配置
|
|
3012
|
+
*/
|
|
3013
|
+
optimizeCache() {
|
|
3014
|
+
logger_1.logger.debug('正在优化缓存...');
|
|
3015
|
+
// 分析缓存使用情况
|
|
3016
|
+
const deviceCacheSize = this.deviceInfoCache.size;
|
|
3017
|
+
const bufferPoolSize = [...this.bufferPool.values()].reduce((total, pool) => total + pool.length, 0);
|
|
3018
|
+
const debugEventSize = this.debugEvents.length;
|
|
3019
|
+
// 根据使用情况调整缓存配置
|
|
3020
|
+
if (deviceCacheSize > 100) {
|
|
3021
|
+
// 设备缓存过大,减少生命周期
|
|
3022
|
+
this.performanceConfig.deviceCacheLifetime = Math.max(60000, this.performanceConfig.deviceCacheLifetime / 2);
|
|
3023
|
+
}
|
|
3024
|
+
else if (deviceCacheSize < 10) {
|
|
3025
|
+
// 设备缓存使用率低,适当增加生命周期
|
|
3026
|
+
this.performanceConfig.deviceCacheLifetime = Math.min(600000, this.performanceConfig.deviceCacheLifetime * 1.5);
|
|
3027
|
+
}
|
|
3028
|
+
// 调整缓冲区池大小
|
|
3029
|
+
if (bufferPoolSize > this.performanceConfig.bufferPoolSize * 3) {
|
|
3030
|
+
// 缓冲区使用太多,减少
|
|
3031
|
+
for (const [size, pool] of this.bufferPool.entries()) {
|
|
3032
|
+
this.bufferPool.set(size, pool.slice(0, this.performanceConfig.bufferPoolSize / 2));
|
|
3033
|
+
}
|
|
3034
|
+
}
|
|
3035
|
+
else if (bufferPoolSize < this.performanceConfig.bufferPoolSize / 2) {
|
|
3036
|
+
// 缓冲区使用率低,增加一些常用大小的缓冲区
|
|
3037
|
+
const mostUsedSizes = this.findMostUsedBufferSizes();
|
|
3038
|
+
for (const size of mostUsedSizes) {
|
|
3039
|
+
const pool = this.bufferPool.get(size) || [];
|
|
3040
|
+
const addCount = this.performanceConfig.bufferPoolSize - pool.length;
|
|
3041
|
+
for (let i = 0; i < addCount; i++) {
|
|
3042
|
+
pool.push(new ArrayBuffer(size));
|
|
3043
|
+
}
|
|
3044
|
+
this.bufferPool.set(size, pool);
|
|
3045
|
+
}
|
|
3046
|
+
}
|
|
3047
|
+
logger_1.logger.debug('缓存优化完成');
|
|
3048
|
+
}
|
|
3049
|
+
/**
|
|
3050
|
+
* 找出最常用的缓冲区大小
|
|
3051
|
+
*/
|
|
3052
|
+
findMostUsedBufferSizes() {
|
|
3053
|
+
// 这里可以基于历史使用情况进行分析
|
|
3054
|
+
// 简化实现,直接返回最小的两种大小
|
|
3055
|
+
return this.performanceConfig.bufferSizes.slice(0, 2);
|
|
3056
|
+
}
|
|
3057
|
+
/**
|
|
3058
|
+
* 获取当前蓝牙内存使用情况
|
|
3059
|
+
*/
|
|
3060
|
+
getMemoryUsage() {
|
|
3061
|
+
// 计算缓冲区池内存使用
|
|
3062
|
+
const bufferPools = [];
|
|
3063
|
+
let totalBufferMemory = 0;
|
|
3064
|
+
for (const [size, pool] of this.bufferPool.entries()) {
|
|
3065
|
+
const poolMemory = size * pool.length;
|
|
3066
|
+
totalBufferMemory += poolMemory;
|
|
3067
|
+
bufferPools.push({
|
|
3068
|
+
size,
|
|
3069
|
+
count: pool.length,
|
|
3070
|
+
memoryUsage: poolMemory
|
|
3071
|
+
});
|
|
3072
|
+
}
|
|
3073
|
+
// 估算缓存内存使用
|
|
3074
|
+
// 每个设备信息条目约占1KB内存
|
|
3075
|
+
const deviceCacheMemory = this.deviceInfoCache.size * 1024;
|
|
3076
|
+
// 每个调试事件约占0.5KB内存
|
|
3077
|
+
const debugEventsMemory = this.debugEvents.length * 512;
|
|
3078
|
+
// 统计数据约占10KB
|
|
3079
|
+
const statsMemory = 10240;
|
|
3080
|
+
const cacheMemory = deviceCacheMemory + debugEventsMemory + statsMemory;
|
|
3081
|
+
return {
|
|
3082
|
+
bufferPools,
|
|
3083
|
+
totalBufferMemory,
|
|
3084
|
+
cacheMemory,
|
|
3085
|
+
totalMemoryUsage: totalBufferMemory + cacheMemory
|
|
3086
|
+
};
|
|
3087
|
+
}
|
|
3088
|
+
updateTransmissionStats() {
|
|
3089
|
+
const now = Date.now();
|
|
3090
|
+
this.transmissionStats.endTime = now;
|
|
3091
|
+
// 计算成功率
|
|
3092
|
+
if (this.transmissionStats.totalCommands > 0) {
|
|
3093
|
+
this.transmissionStats.successRate = this.transmissionStats.successfulCommands / this.transmissionStats.totalCommands;
|
|
3094
|
+
}
|
|
3095
|
+
// 计算传输时长
|
|
3096
|
+
if (this.transmissionStats.startTime > 0) {
|
|
3097
|
+
this.transmissionStats.duration = now - this.transmissionStats.startTime;
|
|
3098
|
+
}
|
|
3099
|
+
// 计算传输速度 (bytes/second)
|
|
3100
|
+
if (this.transmissionStats.duration && this.transmissionStats.duration > 0) {
|
|
3101
|
+
this.transmissionStats.transmissionSpeed = (this.transmissionStats.successfulBytes * 1000) / this.transmissionStats.duration;
|
|
3102
|
+
this.transmissionStats.lastTransmissionSpeed = this.transmissionStats.transmissionSpeed;
|
|
3103
|
+
}
|
|
3104
|
+
}
|
|
3105
|
+
// 合并事件历史记录
|
|
3106
|
+
mergeEventHistory(history, maxEntries = 100) {
|
|
3107
|
+
return history
|
|
3108
|
+
.sort((a, b) => b.timestamp - a.timestamp)
|
|
3109
|
+
.slice(-maxEntries);
|
|
3110
|
+
}
|
|
351
3111
|
}
|
|
352
3112
|
exports.BluetoothManager = BluetoothManager;
|
|
353
3113
|
//# sourceMappingURL=index.js.map
|