ultimatedarktower 2.3.0 → 3.0.0
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/CHANGELOG.md +100 -46
- package/README.md +85 -56
- package/dist/esm/index.mjs +274 -246
- package/dist/src/UltimateDarkTower.d.ts +21 -6
- package/dist/src/UltimateDarkTower.js +39 -41
- package/dist/src/UltimateDarkTower.js.map +1 -1
- package/dist/src/adapters/NodeBluetoothAdapter.js.map +1 -1
- package/dist/src/adapters/WebBluetoothAdapter.js.map +1 -1
- package/dist/src/udtBleConnection.d.ts +4 -4
- package/dist/src/udtBleConnection.js +13 -12
- package/dist/src/udtBleConnection.js.map +1 -1
- package/dist/src/udtBluetoothAdapter.d.ts +2 -2
- package/dist/src/udtBluetoothAdapterFactory.js.map +1 -1
- package/dist/src/udtCommandFactory.d.ts +6 -0
- package/dist/src/udtCommandFactory.js +26 -22
- package/dist/src/udtCommandFactory.js.map +1 -1
- package/dist/src/udtCommandQueue.d.ts +2 -2
- package/dist/src/udtCommandQueue.js +2 -3
- package/dist/src/udtCommandQueue.js.map +1 -1
- package/dist/src/udtConstants.d.ts +1 -8
- package/dist/src/udtConstants.js +6 -6
- package/dist/src/udtConstants.js.map +1 -1
- package/dist/src/udtHelpers.js +8 -9
- package/dist/src/udtHelpers.js.map +1 -1
- package/dist/src/udtLogger.d.ts +1 -0
- package/dist/src/udtLogger.js +24 -2
- package/dist/src/udtLogger.js.map +1 -1
- package/dist/src/udtTowerCommands.d.ts +2 -2
- package/dist/src/udtTowerCommands.js +17 -14
- package/dist/src/udtTowerCommands.js.map +1 -1
- package/dist/src/udtTowerResponse.d.ts +9 -5
- package/dist/src/udtTowerResponse.js +5 -6
- package/dist/src/udtTowerResponse.js.map +1 -1
- package/dist/src/udtTowerState.js +4 -4
- package/dist/src/udtTowerState.js.map +1 -1
- package/package.json +18 -15
package/dist/esm/index.mjs
CHANGED
|
@@ -6,8 +6,7 @@ var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
|
6
6
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
7
7
|
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
8
8
|
}) : x)(function(x) {
|
|
9
|
-
if (typeof require !== "undefined")
|
|
10
|
-
return require.apply(this, arguments);
|
|
9
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
11
10
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
12
11
|
});
|
|
13
12
|
var __esm = (fn, res) => function __init() {
|
|
@@ -31,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
30
|
var UART_SERVICE_UUID, UART_TX_CHARACTERISTIC_UUID, UART_RX_CHARACTERISTIC_UUID, TOWER_DEVICE_NAME, DIS_SERVICE_UUID, DIS_MANUFACTURER_NAME_UUID, DIS_MODEL_NUMBER_UUID, DIS_SERIAL_NUMBER_UUID, DIS_HARDWARE_REVISION_UUID, DIS_FIRMWARE_REVISION_UUID, DIS_SOFTWARE_REVISION_UUID, DIS_SYSTEM_ID_UUID, DIS_IEEE_REGULATORY_UUID, DIS_PNP_ID_UUID, TOWER_COMMAND_PACKET_SIZE, TOWER_STATE_DATA_SIZE, TOWER_COMMAND_HEADER_SIZE, TOWER_STATE_RESPONSE_MIN_LENGTH, TOWER_STATE_DATA_OFFSET, TOWER_COMMAND_TYPE_TOWER_STATE, DEFAULT_CONNECTION_MONITORING_FREQUENCY, DEFAULT_CONNECTION_MONITORING_TIMEOUT, DEFAULT_BATTERY_HEARTBEAT_TIMEOUT, BATTERY_STATUS_FREQUENCY, DEFAULT_RETRY_SEND_COMMAND_MAX, TOWER_SIDES_COUNT, TOWER_COMMANDS, TC, DRUM_PACKETS, GLYPHS, AUDIO_COMMAND_POS, SKULL_DROP_COUNT_POS, drumPositionCmds, LIGHT_EFFECTS, TOWER_LIGHT_SEQUENCES, TOWER_MESSAGES, VOLTAGE_LEVELS, TOWER_LAYERS, RING_LIGHT_POSITIONS, LEDGE_BASE_LIGHT_POSITIONS, LED_CHANNEL_LOOKUP, LAYER_TO_POSITION, LIGHT_INDEX_TO_DIRECTION, STATE_DATA_LENGTH, TOWER_AUDIO_LIBRARY, VOLUME_DESCRIPTIONS, VOLUME_ICONS;
|
|
32
31
|
var init_udtConstants = __esm({
|
|
33
32
|
"src/udtConstants.ts"() {
|
|
33
|
+
"use strict";
|
|
34
34
|
UART_SERVICE_UUID = "6e400001-b5a3-f393-e0a9-e50e24dcca9e";
|
|
35
35
|
UART_TX_CHARACTERISTIC_UUID = "6e400002-b5a3-f393-e0a9-e50e24dcca9e";
|
|
36
36
|
UART_RX_CHARACTERISTIC_UUID = "6e400003-b5a3-f393-e0a9-e50e24dcca9e";
|
|
@@ -362,160 +362,11 @@ var init_udtConstants = __esm({
|
|
|
362
362
|
}
|
|
363
363
|
});
|
|
364
364
|
|
|
365
|
-
// src/udtTowerState.ts
|
|
366
|
-
var udtTowerState_exports = {};
|
|
367
|
-
__export(udtTowerState_exports, {
|
|
368
|
-
LAYER_TO_POSITION: () => LAYER_TO_POSITION,
|
|
369
|
-
LEDGE_BASE_LIGHT_POSITIONS: () => LEDGE_BASE_LIGHT_POSITIONS,
|
|
370
|
-
LED_CHANNEL_LOOKUP: () => LED_CHANNEL_LOOKUP,
|
|
371
|
-
LIGHT_INDEX_TO_DIRECTION: () => LIGHT_INDEX_TO_DIRECTION,
|
|
372
|
-
RING_LIGHT_POSITIONS: () => RING_LIGHT_POSITIONS,
|
|
373
|
-
STATE_DATA_LENGTH: () => STATE_DATA_LENGTH,
|
|
374
|
-
TOWER_LAYERS: () => TOWER_LAYERS,
|
|
375
|
-
isCalibrated: () => isCalibrated,
|
|
376
|
-
rtdt_pack_state: () => rtdt_pack_state,
|
|
377
|
-
rtdt_unpack_state: () => rtdt_unpack_state
|
|
378
|
-
});
|
|
379
|
-
function rtdt_unpack_state(data) {
|
|
380
|
-
const state = {
|
|
381
|
-
drum: [
|
|
382
|
-
{ jammed: false, calibrated: false, position: 0, playSound: false, reverse: false },
|
|
383
|
-
{ jammed: false, calibrated: false, position: 0, playSound: false, reverse: false },
|
|
384
|
-
{ jammed: false, calibrated: false, position: 0, playSound: false, reverse: false }
|
|
385
|
-
],
|
|
386
|
-
layer: [
|
|
387
|
-
{ light: [{ effect: 0, loop: false }, { effect: 0, loop: false }, { effect: 0, loop: false }, { effect: 0, loop: false }] },
|
|
388
|
-
{ light: [{ effect: 0, loop: false }, { effect: 0, loop: false }, { effect: 0, loop: false }, { effect: 0, loop: false }] },
|
|
389
|
-
{ light: [{ effect: 0, loop: false }, { effect: 0, loop: false }, { effect: 0, loop: false }, { effect: 0, loop: false }] },
|
|
390
|
-
{ light: [{ effect: 0, loop: false }, { effect: 0, loop: false }, { effect: 0, loop: false }, { effect: 0, loop: false }] },
|
|
391
|
-
{ light: [{ effect: 0, loop: false }, { effect: 0, loop: false }, { effect: 0, loop: false }, { effect: 0, loop: false }] },
|
|
392
|
-
{ light: [{ effect: 0, loop: false }, { effect: 0, loop: false }, { effect: 0, loop: false }, { effect: 0, loop: false }] }
|
|
393
|
-
],
|
|
394
|
-
audio: { sample: 0, loop: false, volume: 0 },
|
|
395
|
-
beam: { count: 0, fault: false },
|
|
396
|
-
led_sequence: 0
|
|
397
|
-
};
|
|
398
|
-
state.drum[0].jammed = !!(data[0] & 8);
|
|
399
|
-
state.drum[0].calibrated = !!(data[0] & 16);
|
|
400
|
-
state.drum[1].jammed = !!(data[1] & 1);
|
|
401
|
-
state.drum[1].calibrated = !!(data[1] & 2);
|
|
402
|
-
state.drum[2].jammed = !!(data[1] & 32);
|
|
403
|
-
state.drum[2].calibrated = !!(data[1] & 64);
|
|
404
|
-
state.drum[0].position = (data[0] & 6) >> 1;
|
|
405
|
-
state.drum[1].position = (data[0] & 192) >> 6;
|
|
406
|
-
state.drum[2].position = (data[1] & 24) >> 3;
|
|
407
|
-
state.drum[0].playSound = !!(data[0] & 1);
|
|
408
|
-
state.drum[1].playSound = !!(data[0] & 32);
|
|
409
|
-
state.drum[2].playSound = !!(data[1] & 4);
|
|
410
|
-
state.layer[0].light[0].effect = (data[2] & 224) >> 5;
|
|
411
|
-
state.layer[0].light[0].loop = !!(data[2] & 16);
|
|
412
|
-
state.layer[0].light[1].effect = (data[2] & 14) >> 1;
|
|
413
|
-
state.layer[0].light[1].loop = !!(data[2] & 1);
|
|
414
|
-
state.layer[0].light[2].effect = (data[3] & 224) >> 5;
|
|
415
|
-
state.layer[0].light[2].loop = !!(data[3] & 16);
|
|
416
|
-
state.layer[0].light[3].effect = (data[3] & 14) >> 1;
|
|
417
|
-
state.layer[0].light[3].loop = !!(data[3] & 1);
|
|
418
|
-
state.layer[1].light[0].effect = (data[4] & 224) >> 5;
|
|
419
|
-
state.layer[1].light[0].loop = !!(data[4] & 16);
|
|
420
|
-
state.layer[1].light[1].effect = (data[4] & 14) >> 1;
|
|
421
|
-
state.layer[1].light[1].loop = !!(data[4] & 1);
|
|
422
|
-
state.layer[1].light[2].effect = (data[5] & 224) >> 5;
|
|
423
|
-
state.layer[1].light[2].loop = !!(data[5] & 16);
|
|
424
|
-
state.layer[1].light[3].effect = (data[5] & 14) >> 1;
|
|
425
|
-
state.layer[1].light[3].loop = !!(data[5] & 1);
|
|
426
|
-
state.layer[2].light[0].effect = (data[6] & 224) >> 5;
|
|
427
|
-
state.layer[2].light[0].loop = !!(data[6] & 16);
|
|
428
|
-
state.layer[2].light[1].effect = (data[6] & 14) >> 1;
|
|
429
|
-
state.layer[2].light[1].loop = !!(data[6] & 1);
|
|
430
|
-
state.layer[2].light[2].effect = (data[7] & 224) >> 5;
|
|
431
|
-
state.layer[2].light[2].loop = !!(data[7] & 16);
|
|
432
|
-
state.layer[2].light[3].effect = (data[7] & 14) >> 1;
|
|
433
|
-
state.layer[2].light[3].loop = !!(data[7] & 1);
|
|
434
|
-
state.layer[3].light[0].effect = (data[8] & 224) >> 5;
|
|
435
|
-
state.layer[3].light[0].loop = !!(data[8] & 16);
|
|
436
|
-
state.layer[3].light[1].effect = (data[8] & 14) >> 1;
|
|
437
|
-
state.layer[3].light[1].loop = !!(data[8] & 1);
|
|
438
|
-
state.layer[3].light[2].effect = (data[9] & 224) >> 5;
|
|
439
|
-
state.layer[3].light[2].loop = !!(data[9] & 16);
|
|
440
|
-
state.layer[3].light[3].effect = (data[9] & 14) >> 1;
|
|
441
|
-
state.layer[3].light[3].loop = !!(data[9] & 1);
|
|
442
|
-
state.layer[4].light[0].effect = (data[10] & 224) >> 5;
|
|
443
|
-
state.layer[4].light[0].loop = !!(data[10] & 16);
|
|
444
|
-
state.layer[4].light[1].effect = (data[10] & 14) >> 1;
|
|
445
|
-
state.layer[4].light[1].loop = !!(data[10] & 1);
|
|
446
|
-
state.layer[4].light[2].effect = (data[11] & 224) >> 5;
|
|
447
|
-
state.layer[4].light[2].loop = !!(data[11] & 16);
|
|
448
|
-
state.layer[4].light[3].effect = (data[11] & 14) >> 1;
|
|
449
|
-
state.layer[4].light[3].loop = !!(data[11] & 1);
|
|
450
|
-
state.layer[5].light[0].effect = (data[12] & 224) >> 5;
|
|
451
|
-
state.layer[5].light[0].loop = !!(data[12] & 16);
|
|
452
|
-
state.layer[5].light[1].effect = (data[12] & 14) >> 1;
|
|
453
|
-
state.layer[5].light[1].loop = !!(data[12] & 1);
|
|
454
|
-
state.layer[5].light[2].effect = (data[13] & 224) >> 5;
|
|
455
|
-
state.layer[5].light[2].loop = !!(data[13] & 16);
|
|
456
|
-
state.layer[5].light[3].effect = (data[13] & 14) >> 1;
|
|
457
|
-
state.layer[5].light[3].loop = !!(data[13] & 1);
|
|
458
|
-
state.audio.sample = data[14] & 127;
|
|
459
|
-
state.audio.loop = !!(data[14] & 128);
|
|
460
|
-
state.beam.count = data[15] << 8 | data[16];
|
|
461
|
-
state.beam.fault = !!(data[17] & 1);
|
|
462
|
-
state.drum[0].reverse = !!(data[17] & 2);
|
|
463
|
-
state.drum[1].reverse = !!(data[17] & 4);
|
|
464
|
-
state.drum[2].reverse = !!(data[17] & 8);
|
|
465
|
-
state.audio.volume = (data[17] & 240) >> 4;
|
|
466
|
-
state.led_sequence = data[18];
|
|
467
|
-
return state;
|
|
468
|
-
}
|
|
469
|
-
function rtdt_pack_state(data, len, state) {
|
|
470
|
-
if (!data || len < STATE_DATA_LENGTH)
|
|
471
|
-
return false;
|
|
472
|
-
data.fill(0, 0, STATE_DATA_LENGTH);
|
|
473
|
-
data[0] |= (state.drum[0].playSound ? 1 : 0) | (state.drum[0].position & 3) << 1 | (state.drum[0].jammed ? 1 : 0) << 3 | (state.drum[0].calibrated ? 1 : 0) << 4 | (state.drum[1].playSound ? 1 : 0) << 5 | (state.drum[1].position & 3) << 6;
|
|
474
|
-
data[1] |= (state.drum[1].jammed ? 1 : 0) | (state.drum[1].calibrated ? 1 : 0) << 1 | (state.drum[2].playSound ? 1 : 0) << 2 | (state.drum[2].position & 3) << 3 | (state.drum[2].jammed ? 1 : 0) << 5 | (state.drum[2].calibrated ? 1 : 0) << 6;
|
|
475
|
-
data[2] |= state.layer[0].light[0].effect << 5 | (state.layer[0].light[0].loop ? 1 : 0) << 4;
|
|
476
|
-
data[2] |= state.layer[0].light[1].effect << 1 | (state.layer[0].light[1].loop ? 1 : 0);
|
|
477
|
-
data[3] |= state.layer[0].light[2].effect << 5 | (state.layer[0].light[2].loop ? 1 : 0) << 4;
|
|
478
|
-
data[3] |= state.layer[0].light[3].effect << 1 | (state.layer[0].light[3].loop ? 1 : 0);
|
|
479
|
-
data[4] |= state.layer[1].light[0].effect << 5 | (state.layer[1].light[0].loop ? 1 : 0) << 4;
|
|
480
|
-
data[4] |= state.layer[1].light[1].effect << 1 | (state.layer[1].light[1].loop ? 1 : 0);
|
|
481
|
-
data[5] |= state.layer[1].light[2].effect << 5 | (state.layer[1].light[2].loop ? 1 : 0) << 4;
|
|
482
|
-
data[5] |= state.layer[1].light[3].effect << 1 | (state.layer[1].light[3].loop ? 1 : 0);
|
|
483
|
-
data[6] |= state.layer[2].light[0].effect << 5 | (state.layer[2].light[0].loop ? 1 : 0) << 4;
|
|
484
|
-
data[6] |= state.layer[2].light[1].effect << 1 | (state.layer[2].light[1].loop ? 1 : 0);
|
|
485
|
-
data[7] |= state.layer[2].light[2].effect << 5 | (state.layer[2].light[2].loop ? 1 : 0) << 4;
|
|
486
|
-
data[7] |= state.layer[2].light[3].effect << 1 | (state.layer[2].light[3].loop ? 1 : 0);
|
|
487
|
-
data[8] |= state.layer[3].light[0].effect << 5 | (state.layer[3].light[0].loop ? 1 : 0) << 4;
|
|
488
|
-
data[8] |= state.layer[3].light[1].effect << 1 | (state.layer[3].light[1].loop ? 1 : 0);
|
|
489
|
-
data[9] |= state.layer[3].light[2].effect << 5 | (state.layer[3].light[2].loop ? 1 : 0) << 4;
|
|
490
|
-
data[9] |= state.layer[3].light[3].effect << 1 | (state.layer[3].light[3].loop ? 1 : 0);
|
|
491
|
-
data[10] |= state.layer[4].light[0].effect << 5 | (state.layer[4].light[0].loop ? 1 : 0) << 4;
|
|
492
|
-
data[10] |= state.layer[4].light[1].effect << 1 | (state.layer[4].light[1].loop ? 1 : 0);
|
|
493
|
-
data[11] |= state.layer[4].light[2].effect << 5 | (state.layer[4].light[2].loop ? 1 : 0) << 4;
|
|
494
|
-
data[11] |= state.layer[4].light[3].effect << 1 | (state.layer[4].light[3].loop ? 1 : 0);
|
|
495
|
-
data[12] |= state.layer[5].light[0].effect << 5 | (state.layer[5].light[0].loop ? 1 : 0) << 4;
|
|
496
|
-
data[12] |= state.layer[5].light[1].effect << 1 | (state.layer[5].light[1].loop ? 1 : 0);
|
|
497
|
-
data[13] |= state.layer[5].light[2].effect << 5 | (state.layer[5].light[2].loop ? 1 : 0) << 4;
|
|
498
|
-
data[13] |= state.layer[5].light[3].effect << 1 | (state.layer[5].light[3].loop ? 1 : 0);
|
|
499
|
-
data[14] = state.audio.sample | (state.audio.loop ? 1 : 0) << 7;
|
|
500
|
-
data[15] = state.beam.count >> 8;
|
|
501
|
-
data[16] = state.beam.count & 255;
|
|
502
|
-
data[17] = state.audio.volume << 4 | (state.beam.fault ? 1 : 0) | (state.drum[0].reverse ? 1 : 0) << 1 | (state.drum[1].reverse ? 1 : 0) << 2 | (state.drum[2].reverse ? 1 : 0) << 3;
|
|
503
|
-
data[18] = state.led_sequence;
|
|
504
|
-
return true;
|
|
505
|
-
}
|
|
506
|
-
function isCalibrated(state) {
|
|
507
|
-
return state.drum.every((drum) => drum.calibrated);
|
|
508
|
-
}
|
|
509
|
-
var init_udtTowerState = __esm({
|
|
510
|
-
"src/udtTowerState.ts"() {
|
|
511
|
-
init_udtConstants();
|
|
512
|
-
}
|
|
513
|
-
});
|
|
514
|
-
|
|
515
365
|
// src/udtBluetoothAdapter.ts
|
|
516
366
|
var BluetoothError, BluetoothConnectionError, BluetoothDeviceNotFoundError, BluetoothUserCancelledError, BluetoothTimeoutError;
|
|
517
367
|
var init_udtBluetoothAdapter = __esm({
|
|
518
368
|
"src/udtBluetoothAdapter.ts"() {
|
|
369
|
+
"use strict";
|
|
519
370
|
BluetoothError = class extends Error {
|
|
520
371
|
constructor(message, originalError) {
|
|
521
372
|
super(message);
|
|
@@ -558,6 +409,7 @@ __export(WebBluetoothAdapter_exports, {
|
|
|
558
409
|
var WebBluetoothAdapter;
|
|
559
410
|
var init_WebBluetoothAdapter = __esm({
|
|
560
411
|
"src/adapters/WebBluetoothAdapter.ts"() {
|
|
412
|
+
"use strict";
|
|
561
413
|
init_udtConstants();
|
|
562
414
|
init_udtBluetoothAdapter();
|
|
563
415
|
WebBluetoothAdapter = class {
|
|
@@ -720,6 +572,7 @@ __export(NodeBluetoothAdapter_exports, {
|
|
|
720
572
|
var noble, NodeBluetoothAdapter;
|
|
721
573
|
var init_NodeBluetoothAdapter = __esm({
|
|
722
574
|
"src/adapters/NodeBluetoothAdapter.ts"() {
|
|
575
|
+
"use strict";
|
|
723
576
|
init_udtBluetoothAdapter();
|
|
724
577
|
init_udtConstants();
|
|
725
578
|
try {
|
|
@@ -813,8 +666,7 @@ var init_NodeBluetoothAdapter = __esm({
|
|
|
813
666
|
}
|
|
814
667
|
}
|
|
815
668
|
async disconnect() {
|
|
816
|
-
if (!this.peripheral)
|
|
817
|
-
return;
|
|
669
|
+
if (!this.peripheral) return;
|
|
818
670
|
try {
|
|
819
671
|
if (this.rxCharacteristic) {
|
|
820
672
|
if (this.boundDataHandler) {
|
|
@@ -916,8 +768,7 @@ var init_NodeBluetoothAdapter = __esm({
|
|
|
916
768
|
return cUuid === normalizedUuid || cUuid === shortUuid;
|
|
917
769
|
}
|
|
918
770
|
);
|
|
919
|
-
if (!char)
|
|
920
|
-
continue;
|
|
771
|
+
if (!char) continue;
|
|
921
772
|
try {
|
|
922
773
|
const buffer = await char.readAsync();
|
|
923
774
|
if (binary) {
|
|
@@ -1006,7 +857,139 @@ var init_NodeBluetoothAdapter = __esm({
|
|
|
1006
857
|
|
|
1007
858
|
// src/UltimateDarkTower.ts
|
|
1008
859
|
init_udtConstants();
|
|
1009
|
-
|
|
860
|
+
|
|
861
|
+
// src/udtTowerState.ts
|
|
862
|
+
init_udtConstants();
|
|
863
|
+
function rtdt_unpack_state(data) {
|
|
864
|
+
const state = {
|
|
865
|
+
drum: [
|
|
866
|
+
{ jammed: false, calibrated: false, position: 0, playSound: false, reverse: false },
|
|
867
|
+
{ jammed: false, calibrated: false, position: 0, playSound: false, reverse: false },
|
|
868
|
+
{ jammed: false, calibrated: false, position: 0, playSound: false, reverse: false }
|
|
869
|
+
],
|
|
870
|
+
layer: [
|
|
871
|
+
{ light: [{ effect: 0, loop: false }, { effect: 0, loop: false }, { effect: 0, loop: false }, { effect: 0, loop: false }] },
|
|
872
|
+
{ light: [{ effect: 0, loop: false }, { effect: 0, loop: false }, { effect: 0, loop: false }, { effect: 0, loop: false }] },
|
|
873
|
+
{ light: [{ effect: 0, loop: false }, { effect: 0, loop: false }, { effect: 0, loop: false }, { effect: 0, loop: false }] },
|
|
874
|
+
{ light: [{ effect: 0, loop: false }, { effect: 0, loop: false }, { effect: 0, loop: false }, { effect: 0, loop: false }] },
|
|
875
|
+
{ light: [{ effect: 0, loop: false }, { effect: 0, loop: false }, { effect: 0, loop: false }, { effect: 0, loop: false }] },
|
|
876
|
+
{ light: [{ effect: 0, loop: false }, { effect: 0, loop: false }, { effect: 0, loop: false }, { effect: 0, loop: false }] }
|
|
877
|
+
],
|
|
878
|
+
audio: { sample: 0, loop: false, volume: 0 },
|
|
879
|
+
beam: { count: 0, fault: false },
|
|
880
|
+
led_sequence: 0
|
|
881
|
+
};
|
|
882
|
+
state.drum[0].jammed = !!(data[0] & 8);
|
|
883
|
+
state.drum[0].calibrated = !!(data[0] & 16);
|
|
884
|
+
state.drum[1].jammed = !!(data[1] & 1);
|
|
885
|
+
state.drum[1].calibrated = !!(data[1] & 2);
|
|
886
|
+
state.drum[2].jammed = !!(data[1] & 32);
|
|
887
|
+
state.drum[2].calibrated = !!(data[1] & 64);
|
|
888
|
+
state.drum[0].position = (data[0] & 6) >> 1;
|
|
889
|
+
state.drum[1].position = (data[0] & 192) >> 6;
|
|
890
|
+
state.drum[2].position = (data[1] & 24) >> 3;
|
|
891
|
+
state.drum[0].playSound = !!(data[0] & 1);
|
|
892
|
+
state.drum[1].playSound = !!(data[0] & 32);
|
|
893
|
+
state.drum[2].playSound = !!(data[1] & 4);
|
|
894
|
+
state.layer[0].light[0].effect = (data[2] & 224) >> 5;
|
|
895
|
+
state.layer[0].light[0].loop = !!(data[2] & 16);
|
|
896
|
+
state.layer[0].light[1].effect = (data[2] & 14) >> 1;
|
|
897
|
+
state.layer[0].light[1].loop = !!(data[2] & 1);
|
|
898
|
+
state.layer[0].light[2].effect = (data[3] & 224) >> 5;
|
|
899
|
+
state.layer[0].light[2].loop = !!(data[3] & 16);
|
|
900
|
+
state.layer[0].light[3].effect = (data[3] & 14) >> 1;
|
|
901
|
+
state.layer[0].light[3].loop = !!(data[3] & 1);
|
|
902
|
+
state.layer[1].light[0].effect = (data[4] & 224) >> 5;
|
|
903
|
+
state.layer[1].light[0].loop = !!(data[4] & 16);
|
|
904
|
+
state.layer[1].light[1].effect = (data[4] & 14) >> 1;
|
|
905
|
+
state.layer[1].light[1].loop = !!(data[4] & 1);
|
|
906
|
+
state.layer[1].light[2].effect = (data[5] & 224) >> 5;
|
|
907
|
+
state.layer[1].light[2].loop = !!(data[5] & 16);
|
|
908
|
+
state.layer[1].light[3].effect = (data[5] & 14) >> 1;
|
|
909
|
+
state.layer[1].light[3].loop = !!(data[5] & 1);
|
|
910
|
+
state.layer[2].light[0].effect = (data[6] & 224) >> 5;
|
|
911
|
+
state.layer[2].light[0].loop = !!(data[6] & 16);
|
|
912
|
+
state.layer[2].light[1].effect = (data[6] & 14) >> 1;
|
|
913
|
+
state.layer[2].light[1].loop = !!(data[6] & 1);
|
|
914
|
+
state.layer[2].light[2].effect = (data[7] & 224) >> 5;
|
|
915
|
+
state.layer[2].light[2].loop = !!(data[7] & 16);
|
|
916
|
+
state.layer[2].light[3].effect = (data[7] & 14) >> 1;
|
|
917
|
+
state.layer[2].light[3].loop = !!(data[7] & 1);
|
|
918
|
+
state.layer[3].light[0].effect = (data[8] & 224) >> 5;
|
|
919
|
+
state.layer[3].light[0].loop = !!(data[8] & 16);
|
|
920
|
+
state.layer[3].light[1].effect = (data[8] & 14) >> 1;
|
|
921
|
+
state.layer[3].light[1].loop = !!(data[8] & 1);
|
|
922
|
+
state.layer[3].light[2].effect = (data[9] & 224) >> 5;
|
|
923
|
+
state.layer[3].light[2].loop = !!(data[9] & 16);
|
|
924
|
+
state.layer[3].light[3].effect = (data[9] & 14) >> 1;
|
|
925
|
+
state.layer[3].light[3].loop = !!(data[9] & 1);
|
|
926
|
+
state.layer[4].light[0].effect = (data[10] & 224) >> 5;
|
|
927
|
+
state.layer[4].light[0].loop = !!(data[10] & 16);
|
|
928
|
+
state.layer[4].light[1].effect = (data[10] & 14) >> 1;
|
|
929
|
+
state.layer[4].light[1].loop = !!(data[10] & 1);
|
|
930
|
+
state.layer[4].light[2].effect = (data[11] & 224) >> 5;
|
|
931
|
+
state.layer[4].light[2].loop = !!(data[11] & 16);
|
|
932
|
+
state.layer[4].light[3].effect = (data[11] & 14) >> 1;
|
|
933
|
+
state.layer[4].light[3].loop = !!(data[11] & 1);
|
|
934
|
+
state.layer[5].light[0].effect = (data[12] & 224) >> 5;
|
|
935
|
+
state.layer[5].light[0].loop = !!(data[12] & 16);
|
|
936
|
+
state.layer[5].light[1].effect = (data[12] & 14) >> 1;
|
|
937
|
+
state.layer[5].light[1].loop = !!(data[12] & 1);
|
|
938
|
+
state.layer[5].light[2].effect = (data[13] & 224) >> 5;
|
|
939
|
+
state.layer[5].light[2].loop = !!(data[13] & 16);
|
|
940
|
+
state.layer[5].light[3].effect = (data[13] & 14) >> 1;
|
|
941
|
+
state.layer[5].light[3].loop = !!(data[13] & 1);
|
|
942
|
+
state.audio.sample = data[14] & 127;
|
|
943
|
+
state.audio.loop = !!(data[14] & 128);
|
|
944
|
+
state.beam.count = data[15] << 8 | data[16];
|
|
945
|
+
state.beam.fault = !!(data[17] & 1);
|
|
946
|
+
state.drum[0].reverse = !!(data[17] & 2);
|
|
947
|
+
state.drum[1].reverse = !!(data[17] & 4);
|
|
948
|
+
state.drum[2].reverse = !!(data[17] & 8);
|
|
949
|
+
state.audio.volume = (data[17] & 240) >> 4;
|
|
950
|
+
state.led_sequence = data[18];
|
|
951
|
+
return state;
|
|
952
|
+
}
|
|
953
|
+
function rtdt_pack_state(data, len, state) {
|
|
954
|
+
if (!data || len < STATE_DATA_LENGTH)
|
|
955
|
+
return false;
|
|
956
|
+
data.fill(0, 0, STATE_DATA_LENGTH);
|
|
957
|
+
data[0] |= (state.drum[0].playSound ? 1 : 0) | (state.drum[0].position & 3) << 1 | (state.drum[0].jammed ? 1 : 0) << 3 | (state.drum[0].calibrated ? 1 : 0) << 4 | (state.drum[1].playSound ? 1 : 0) << 5 | (state.drum[1].position & 3) << 6;
|
|
958
|
+
data[1] |= (state.drum[1].jammed ? 1 : 0) | (state.drum[1].calibrated ? 1 : 0) << 1 | (state.drum[2].playSound ? 1 : 0) << 2 | (state.drum[2].position & 3) << 3 | (state.drum[2].jammed ? 1 : 0) << 5 | (state.drum[2].calibrated ? 1 : 0) << 6;
|
|
959
|
+
data[2] |= state.layer[0].light[0].effect << 5 | (state.layer[0].light[0].loop ? 1 : 0) << 4;
|
|
960
|
+
data[2] |= state.layer[0].light[1].effect << 1 | (state.layer[0].light[1].loop ? 1 : 0);
|
|
961
|
+
data[3] |= state.layer[0].light[2].effect << 5 | (state.layer[0].light[2].loop ? 1 : 0) << 4;
|
|
962
|
+
data[3] |= state.layer[0].light[3].effect << 1 | (state.layer[0].light[3].loop ? 1 : 0);
|
|
963
|
+
data[4] |= state.layer[1].light[0].effect << 5 | (state.layer[1].light[0].loop ? 1 : 0) << 4;
|
|
964
|
+
data[4] |= state.layer[1].light[1].effect << 1 | (state.layer[1].light[1].loop ? 1 : 0);
|
|
965
|
+
data[5] |= state.layer[1].light[2].effect << 5 | (state.layer[1].light[2].loop ? 1 : 0) << 4;
|
|
966
|
+
data[5] |= state.layer[1].light[3].effect << 1 | (state.layer[1].light[3].loop ? 1 : 0);
|
|
967
|
+
data[6] |= state.layer[2].light[0].effect << 5 | (state.layer[2].light[0].loop ? 1 : 0) << 4;
|
|
968
|
+
data[6] |= state.layer[2].light[1].effect << 1 | (state.layer[2].light[1].loop ? 1 : 0);
|
|
969
|
+
data[7] |= state.layer[2].light[2].effect << 5 | (state.layer[2].light[2].loop ? 1 : 0) << 4;
|
|
970
|
+
data[7] |= state.layer[2].light[3].effect << 1 | (state.layer[2].light[3].loop ? 1 : 0);
|
|
971
|
+
data[8] |= state.layer[3].light[0].effect << 5 | (state.layer[3].light[0].loop ? 1 : 0) << 4;
|
|
972
|
+
data[8] |= state.layer[3].light[1].effect << 1 | (state.layer[3].light[1].loop ? 1 : 0);
|
|
973
|
+
data[9] |= state.layer[3].light[2].effect << 5 | (state.layer[3].light[2].loop ? 1 : 0) << 4;
|
|
974
|
+
data[9] |= state.layer[3].light[3].effect << 1 | (state.layer[3].light[3].loop ? 1 : 0);
|
|
975
|
+
data[10] |= state.layer[4].light[0].effect << 5 | (state.layer[4].light[0].loop ? 1 : 0) << 4;
|
|
976
|
+
data[10] |= state.layer[4].light[1].effect << 1 | (state.layer[4].light[1].loop ? 1 : 0);
|
|
977
|
+
data[11] |= state.layer[4].light[2].effect << 5 | (state.layer[4].light[2].loop ? 1 : 0) << 4;
|
|
978
|
+
data[11] |= state.layer[4].light[3].effect << 1 | (state.layer[4].light[3].loop ? 1 : 0);
|
|
979
|
+
data[12] |= state.layer[5].light[0].effect << 5 | (state.layer[5].light[0].loop ? 1 : 0) << 4;
|
|
980
|
+
data[12] |= state.layer[5].light[1].effect << 1 | (state.layer[5].light[1].loop ? 1 : 0);
|
|
981
|
+
data[13] |= state.layer[5].light[2].effect << 5 | (state.layer[5].light[2].loop ? 1 : 0) << 4;
|
|
982
|
+
data[13] |= state.layer[5].light[3].effect << 1 | (state.layer[5].light[3].loop ? 1 : 0);
|
|
983
|
+
data[14] = state.audio.sample | (state.audio.loop ? 1 : 0) << 7;
|
|
984
|
+
data[15] = state.beam.count >> 8;
|
|
985
|
+
data[16] = state.beam.count & 255;
|
|
986
|
+
data[17] = state.audio.volume << 4 | (state.beam.fault ? 1 : 0) | (state.drum[0].reverse ? 1 : 0) << 1 | (state.drum[1].reverse ? 1 : 0) << 2 | (state.drum[2].reverse ? 1 : 0) << 3;
|
|
987
|
+
data[18] = state.led_sequence;
|
|
988
|
+
return true;
|
|
989
|
+
}
|
|
990
|
+
function isCalibrated(state) {
|
|
991
|
+
return state.drum.every((drum) => drum.calibrated);
|
|
992
|
+
}
|
|
1010
993
|
|
|
1011
994
|
// src/udtHelpers.ts
|
|
1012
995
|
init_udtConstants();
|
|
@@ -1135,17 +1118,33 @@ var DOMOutput = class {
|
|
|
1135
1118
|
this.maxLines = maxLines;
|
|
1136
1119
|
}
|
|
1137
1120
|
write(level, message, timestamp) {
|
|
1138
|
-
if (!this.container)
|
|
1139
|
-
return;
|
|
1121
|
+
if (!this.container) return;
|
|
1140
1122
|
this.allEntries.push({ level, message, timestamp });
|
|
1123
|
+
let removedEntries = false;
|
|
1141
1124
|
while (this.allEntries.length > this.maxLines) {
|
|
1142
1125
|
this.allEntries.shift();
|
|
1126
|
+
removedEntries = true;
|
|
1127
|
+
}
|
|
1128
|
+
if (removedEntries) {
|
|
1129
|
+
this.refreshDisplay();
|
|
1130
|
+
return;
|
|
1131
|
+
}
|
|
1132
|
+
const enabledLevels = this.getEnabledLevelsFromCheckboxes();
|
|
1133
|
+
if (enabledLevels.has(level)) {
|
|
1134
|
+
const textFilter = this.getTextFilter();
|
|
1135
|
+
if (!textFilter || message.toLowerCase().includes(textFilter.toLowerCase())) {
|
|
1136
|
+
const timeStr = timestamp.toLocaleTimeString();
|
|
1137
|
+
const logLine = document.createElement("div");
|
|
1138
|
+
logLine.className = `log-line log-${level}`;
|
|
1139
|
+
logLine.textContent = `[${timeStr}] ${message}`;
|
|
1140
|
+
this.container.appendChild(logLine);
|
|
1141
|
+
this.container.scrollTop = this.container.scrollHeight;
|
|
1142
|
+
this.updateBufferSizeDisplay();
|
|
1143
|
+
}
|
|
1143
1144
|
}
|
|
1144
|
-
this.refreshDisplay();
|
|
1145
1145
|
}
|
|
1146
1146
|
refreshDisplay() {
|
|
1147
|
-
if (!this.container)
|
|
1148
|
-
return;
|
|
1147
|
+
if (!this.container) return;
|
|
1149
1148
|
this.container.innerHTML = "";
|
|
1150
1149
|
const enabledLevels = this.getEnabledLevelsFromCheckboxes();
|
|
1151
1150
|
const textFilter = this.getTextFilter();
|
|
@@ -1242,6 +1241,9 @@ var Logger = class _Logger {
|
|
|
1242
1241
|
addOutput(output) {
|
|
1243
1242
|
this.outputs.push(output);
|
|
1244
1243
|
}
|
|
1244
|
+
clearOutputs() {
|
|
1245
|
+
this.outputs = [];
|
|
1246
|
+
}
|
|
1245
1247
|
setMinLevel(level) {
|
|
1246
1248
|
this.enabledLevels = /* @__PURE__ */ new Set([level]);
|
|
1247
1249
|
}
|
|
@@ -1258,12 +1260,9 @@ var Logger = class _Logger {
|
|
|
1258
1260
|
return Array.from(this.enabledLevels);
|
|
1259
1261
|
}
|
|
1260
1262
|
shouldLog(level) {
|
|
1261
|
-
if (this.enabledLevels.has("all"))
|
|
1262
|
-
|
|
1263
|
-
if (level
|
|
1264
|
-
return true;
|
|
1265
|
-
if (this.enabledLevels.has(level))
|
|
1266
|
-
return true;
|
|
1263
|
+
if (this.enabledLevels.has("all")) return true;
|
|
1264
|
+
if (level === "all") return true;
|
|
1265
|
+
if (this.enabledLevels.has(level)) return true;
|
|
1267
1266
|
if (this.enabledLevels.size === 1) {
|
|
1268
1267
|
const singleLevel = Array.from(this.enabledLevels)[0];
|
|
1269
1268
|
if (singleLevel !== "all") {
|
|
@@ -1276,8 +1275,7 @@ var Logger = class _Logger {
|
|
|
1276
1275
|
return false;
|
|
1277
1276
|
}
|
|
1278
1277
|
log(level, message, context) {
|
|
1279
|
-
if (!this.shouldLog(level))
|
|
1280
|
-
return;
|
|
1278
|
+
if (!this.shouldLog(level)) return;
|
|
1281
1279
|
const contextPrefix = context ? `${context} ` : "";
|
|
1282
1280
|
const finalMessage = `${contextPrefix}${message}`;
|
|
1283
1281
|
const timestamp = /* @__PURE__ */ new Date();
|
|
@@ -1412,7 +1410,7 @@ var TowerResponseProcessor = class {
|
|
|
1412
1410
|
const cmdKey = cmdKeys.find((key) => TOWER_MESSAGES[key].value === cmdValue);
|
|
1413
1411
|
if (!cmdKey) {
|
|
1414
1412
|
logger.warn(`Unknown command received from tower: ${cmdValue} (0x${cmdValue.toString(16)})`, "TowerResponseProcessor");
|
|
1415
|
-
return { cmdKey: void 0, command: { name: "Unknown Command", value: cmdValue } };
|
|
1413
|
+
return { cmdKey: void 0, command: { name: "Unknown Command", value: cmdValue, critical: false } };
|
|
1416
1414
|
}
|
|
1417
1415
|
const command = TOWER_MESSAGES[cmdKey];
|
|
1418
1416
|
return { cmdKey, command };
|
|
@@ -1455,12 +1453,11 @@ var TowerResponseProcessor = class {
|
|
|
1455
1453
|
* @returns {boolean} Whether this response should be logged
|
|
1456
1454
|
*/
|
|
1457
1455
|
shouldLogResponse(cmdKey, logConfig) {
|
|
1458
|
-
const logAll = logConfig["LOG_ALL"];
|
|
1459
|
-
let canLogThisResponse = logConfig[cmdKey] || logAll;
|
|
1460
1456
|
if (!cmdKey) {
|
|
1461
|
-
|
|
1457
|
+
return true;
|
|
1462
1458
|
}
|
|
1463
|
-
|
|
1459
|
+
const logAll = logConfig["LOG_ALL"];
|
|
1460
|
+
return logConfig[cmdKey] || logAll;
|
|
1464
1461
|
}
|
|
1465
1462
|
/**
|
|
1466
1463
|
* Checks if a command is a battery response type.
|
|
@@ -1480,9 +1477,6 @@ var TowerResponseProcessor = class {
|
|
|
1480
1477
|
}
|
|
1481
1478
|
};
|
|
1482
1479
|
|
|
1483
|
-
// src/udtBleConnection.ts
|
|
1484
|
-
init_udtTowerState();
|
|
1485
|
-
|
|
1486
1480
|
// src/udtBluetoothAdapterFactory.ts
|
|
1487
1481
|
var BluetoothPlatform = /* @__PURE__ */ ((BluetoothPlatform3) => {
|
|
1488
1482
|
BluetoothPlatform3["WEB"] = "web";
|
|
@@ -1558,11 +1552,11 @@ var UdtBleConnection = class {
|
|
|
1558
1552
|
// When true, verifies connection before triggering disconnection on heartbeat timeout
|
|
1559
1553
|
// Tower state
|
|
1560
1554
|
this.towerSkullDropCount = -1;
|
|
1561
|
-
this.
|
|
1555
|
+
this.lastBatteryLog = 0;
|
|
1562
1556
|
this.lastBatteryPercentage = "";
|
|
1563
|
-
this.
|
|
1564
|
-
this.
|
|
1565
|
-
this.
|
|
1557
|
+
this.batteryLogFrequency = 15 * 1e3;
|
|
1558
|
+
this.batteryLogOnChangeOnly = false;
|
|
1559
|
+
this.batteryLogEnabled = true;
|
|
1566
1560
|
// Device information
|
|
1567
1561
|
this.deviceInformation = {};
|
|
1568
1562
|
// Logging configuration
|
|
@@ -1641,7 +1635,7 @@ var UdtBleConnection = class {
|
|
|
1641
1635
|
this.lastSuccessfulCommand = Date.now();
|
|
1642
1636
|
const { cmdKey } = this.responseProcessor.getTowerCommand(receivedData[0]);
|
|
1643
1637
|
const isBattery = this.responseProcessor.isBatteryResponse(cmdKey);
|
|
1644
|
-
const shouldLogCommand = this.logTowerResponses && this.responseProcessor.shouldLogResponse(cmdKey, this.logTowerResponseConfig) &&
|
|
1638
|
+
const shouldLogCommand = this.logTowerResponses && this.responseProcessor.shouldLogResponse(cmdKey, this.logTowerResponseConfig) && !isBattery;
|
|
1645
1639
|
if (shouldLogCommand) {
|
|
1646
1640
|
this.logger.info(`${cmdKey}`, "[UDT][BLE][RCVD]");
|
|
1647
1641
|
}
|
|
@@ -1656,14 +1650,14 @@ var UdtBleConnection = class {
|
|
|
1656
1650
|
const millivolts = getMilliVoltsFromTowerResponse(receivedData);
|
|
1657
1651
|
const batteryPercentage = milliVoltsToPercentage(millivolts);
|
|
1658
1652
|
const didBatteryLevelChange = this.lastBatteryPercentage !== "" && this.lastBatteryPercentage !== batteryPercentage;
|
|
1659
|
-
const
|
|
1660
|
-
const
|
|
1661
|
-
if (
|
|
1653
|
+
const batteryLogFrequencyPassed = Date.now() - this.lastBatteryLog >= this.batteryLogFrequency;
|
|
1654
|
+
const shouldLog = this.batteryLogEnabled && (this.batteryLogOnChangeOnly ? didBatteryLevelChange || this.lastBatteryPercentage === "" : batteryLogFrequencyPassed);
|
|
1655
|
+
if (shouldLog) {
|
|
1662
1656
|
this.logger.info(`${this.responseProcessor.commandToString(receivedData).join(" ")}`, "[UDT][BLE]");
|
|
1663
|
-
this.
|
|
1657
|
+
this.lastBatteryLog = Date.now();
|
|
1664
1658
|
this.lastBatteryPercentage = batteryPercentage;
|
|
1665
|
-
this.callbacks.onBatteryLevelNotify(millivolts);
|
|
1666
1659
|
}
|
|
1660
|
+
this.callbacks.onBatteryLevelNotify(millivolts);
|
|
1667
1661
|
} else {
|
|
1668
1662
|
if (this.callbacks.onTowerResponse) {
|
|
1669
1663
|
this.callbacks.onTowerResponse(receivedData);
|
|
@@ -1835,13 +1829,12 @@ var UdtBleConnection = class {
|
|
|
1835
1829
|
this.logger.info(`Device ${key}: ${value}`, "[UDT][BLE]");
|
|
1836
1830
|
}
|
|
1837
1831
|
}
|
|
1838
|
-
} catch
|
|
1832
|
+
} catch {
|
|
1839
1833
|
this.logger.debug("Device Information Service not available", "[UDT][BLE]");
|
|
1840
1834
|
}
|
|
1841
1835
|
}
|
|
1842
1836
|
async cleanup() {
|
|
1843
|
-
if (this.isDisposed)
|
|
1844
|
-
return;
|
|
1837
|
+
if (this.isDisposed) return;
|
|
1845
1838
|
this.isDisposed = true;
|
|
1846
1839
|
this.logger.info("Cleaning up UdtBleConnection instance", "[UDT][BLE]");
|
|
1847
1840
|
this.stopConnectionMonitoring();
|
|
@@ -1854,7 +1847,6 @@ var UdtBleConnection = class {
|
|
|
1854
1847
|
|
|
1855
1848
|
// src/udtCommandFactory.ts
|
|
1856
1849
|
init_udtConstants();
|
|
1857
|
-
init_udtTowerState();
|
|
1858
1850
|
var UdtCommandFactory = class {
|
|
1859
1851
|
/**
|
|
1860
1852
|
* Creates a rotation command packet for positioning tower drums.
|
|
@@ -1876,8 +1868,7 @@ var UdtCommandFactory = class {
|
|
|
1876
1868
|
*/
|
|
1877
1869
|
createSoundCommand(soundIndex) {
|
|
1878
1870
|
const soundCommand = new Uint8Array(TOWER_COMMAND_PACKET_SIZE);
|
|
1879
|
-
|
|
1880
|
-
soundCommand[AUDIO_COMMAND_POS] = sound;
|
|
1871
|
+
soundCommand[AUDIO_COMMAND_POS] = soundIndex & 255;
|
|
1881
1872
|
return soundCommand;
|
|
1882
1873
|
}
|
|
1883
1874
|
/**
|
|
@@ -1897,7 +1888,7 @@ var UdtCommandFactory = class {
|
|
|
1897
1888
|
* @returns 20-byte command packet (command type + 19-byte state data)
|
|
1898
1889
|
*/
|
|
1899
1890
|
createStatefulCommand(currentState, modifications) {
|
|
1900
|
-
const newState = currentState ?
|
|
1891
|
+
const newState = currentState ? this.deepCopyTowerState(currentState) : this.createEmptyTowerState();
|
|
1901
1892
|
if (modifications.drum) {
|
|
1902
1893
|
modifications.drum.forEach((drum, index) => {
|
|
1903
1894
|
if (drum && newState.drum[index]) {
|
|
@@ -1939,17 +1930,10 @@ var UdtCommandFactory = class {
|
|
|
1939
1930
|
* @returns 20-byte command packet
|
|
1940
1931
|
*/
|
|
1941
1932
|
createStatefulLEDCommand(currentState, layerIndex, lightIndex, effect, loop = false) {
|
|
1942
|
-
const
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
}
|
|
1946
|
-
if (!modifications.layer[layerIndex]) {
|
|
1947
|
-
modifications.layer[layerIndex] = { light: [] };
|
|
1948
|
-
}
|
|
1949
|
-
if (!modifications.layer[layerIndex].light) {
|
|
1950
|
-
modifications.layer[layerIndex].light = [];
|
|
1951
|
-
}
|
|
1952
|
-
modifications.layer[layerIndex].light[lightIndex] = { effect, loop };
|
|
1933
|
+
const layer = [];
|
|
1934
|
+
layer[layerIndex] = { light: [] };
|
|
1935
|
+
layer[layerIndex].light[lightIndex] = { effect, loop };
|
|
1936
|
+
const modifications = { layer };
|
|
1953
1937
|
modifications.audio = { sample: 0, loop: false, volume: 0 };
|
|
1954
1938
|
return this.createStatefulCommand(currentState, modifications);
|
|
1955
1939
|
}
|
|
@@ -2043,17 +2027,15 @@ var UdtCommandFactory = class {
|
|
|
2043
2027
|
* @returns 20-byte command packet
|
|
2044
2028
|
*/
|
|
2045
2029
|
createStatefulDrumCommand(currentState, drumIndex, position, playSound = false) {
|
|
2046
|
-
const
|
|
2047
|
-
|
|
2048
|
-
modifications.drum = [];
|
|
2049
|
-
}
|
|
2050
|
-
modifications.drum[drumIndex] = {
|
|
2030
|
+
const drum = [];
|
|
2031
|
+
drum[drumIndex] = {
|
|
2051
2032
|
jammed: false,
|
|
2052
2033
|
calibrated: true,
|
|
2053
2034
|
position,
|
|
2054
2035
|
playSound,
|
|
2055
2036
|
reverse: false
|
|
2056
2037
|
};
|
|
2038
|
+
const modifications = { drum };
|
|
2057
2039
|
modifications.audio = { sample: 0, loop: false, volume: 0 };
|
|
2058
2040
|
return this.createStatefulCommand(currentState, modifications);
|
|
2059
2041
|
}
|
|
@@ -2097,6 +2079,22 @@ var UdtCommandFactory = class {
|
|
|
2097
2079
|
led_sequence: 0
|
|
2098
2080
|
};
|
|
2099
2081
|
}
|
|
2082
|
+
/**
|
|
2083
|
+
* Creates a deep copy of a TowerState to avoid mutating the original.
|
|
2084
|
+
* @param state - The tower state to copy
|
|
2085
|
+
* @returns A new TowerState with all nested objects copied
|
|
2086
|
+
*/
|
|
2087
|
+
deepCopyTowerState(state) {
|
|
2088
|
+
return {
|
|
2089
|
+
drum: state.drum.map((d) => ({ ...d })),
|
|
2090
|
+
layer: state.layer.map((l) => ({
|
|
2091
|
+
light: l.light.map((lt) => ({ ...lt }))
|
|
2092
|
+
})),
|
|
2093
|
+
audio: { ...state.audio },
|
|
2094
|
+
beam: { ...state.beam },
|
|
2095
|
+
led_sequence: state.led_sequence
|
|
2096
|
+
};
|
|
2097
|
+
}
|
|
2100
2098
|
//#endregion
|
|
2101
2099
|
};
|
|
2102
2100
|
|
|
@@ -2180,9 +2178,10 @@ var CommandQueue = class {
|
|
|
2180
2178
|
if (this.currentCommand) {
|
|
2181
2179
|
const { description, id } = this.currentCommand;
|
|
2182
2180
|
this.logger.warn(`Command timeout after ${this.timeoutMs}ms: ${description || id}`, "[UDT]");
|
|
2183
|
-
this.currentCommand.
|
|
2181
|
+
const reject = this.currentCommand.reject;
|
|
2184
2182
|
this.currentCommand = null;
|
|
2185
2183
|
this.isProcessing = false;
|
|
2184
|
+
reject(new Error(`Command timeout after ${this.timeoutMs}ms: ${description || id}`));
|
|
2186
2185
|
this.processNext();
|
|
2187
2186
|
}
|
|
2188
2187
|
}
|
|
@@ -2264,7 +2263,7 @@ var UdtTowerCommands = class {
|
|
|
2264
2263
|
this.deps.bleConnection.lastSuccessfulCommand = Date.now();
|
|
2265
2264
|
} catch (error) {
|
|
2266
2265
|
this.deps.logger.error(`command send error: ${error}`, "[UDT][CMD]");
|
|
2267
|
-
const errorMsg = error?.message ??
|
|
2266
|
+
const errorMsg = error?.message ?? String(error);
|
|
2268
2267
|
const wasCancelled = errorMsg.includes("User cancelled");
|
|
2269
2268
|
const maxRetriesReached = this.deps.retrySendCommandCount.value >= this.deps.retrySendCommandMax;
|
|
2270
2269
|
const isDisconnected = errorMsg.includes("Cannot read properties of null") || errorMsg.includes("GATT Server is disconnected") || errorMsg.includes("Device is not connected") || errorMsg.includes("BluetoothConnectionError") || !this.deps.bleConnection.isConnected;
|
|
@@ -2276,9 +2275,9 @@ var UdtTowerCommands = class {
|
|
|
2276
2275
|
if (!maxRetriesReached && this.deps.bleConnection.isConnected && !wasCancelled) {
|
|
2277
2276
|
this.deps.logger.info(`retrying tower command attempt ${this.deps.retrySendCommandCount.value + 1}`, "[UDT][CMD]");
|
|
2278
2277
|
this.deps.retrySendCommandCount.value++;
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2278
|
+
const delay = 250 * this.deps.retrySendCommandCount.value;
|
|
2279
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
2280
|
+
return await this.sendTowerCommandDirect(command);
|
|
2282
2281
|
} else {
|
|
2283
2282
|
this.deps.retrySendCommandCount.value = 0;
|
|
2284
2283
|
}
|
|
@@ -2326,9 +2325,13 @@ var UdtTowerCommands = class {
|
|
|
2326
2325
|
this.deps.logDetail && this.deps.logger.debug(`Light Parameter ${JSON.stringify(lights)}`, "[UDT][CMD]");
|
|
2327
2326
|
this.deps.logger.info("Sending light commands", "[UDT][CMD]");
|
|
2328
2327
|
const layerCommands = this.mapLightsToLayerCommands(lights);
|
|
2329
|
-
|
|
2330
|
-
|
|
2328
|
+
const currentState = this.deps.getCurrentTowerState();
|
|
2329
|
+
for (const { layerIndex, lightIndex, effect, loop } of layerCommands) {
|
|
2330
|
+
currentState.layer[layerIndex].light[lightIndex] = { effect, loop };
|
|
2331
2331
|
}
|
|
2332
|
+
const command = this.deps.commandFactory.createStatefulCommand(currentState, {});
|
|
2333
|
+
this.deps.setTowerState(currentState, "lights");
|
|
2334
|
+
await this.sendTowerCommand(command, "lights");
|
|
2332
2335
|
}
|
|
2333
2336
|
/**
|
|
2334
2337
|
* Maps the Lights object to layer/light index commands for setLEDStateful.
|
|
@@ -2342,7 +2345,7 @@ var UdtTowerCommands = class {
|
|
|
2342
2345
|
const layerIndex = this.getTowerLayerForLevel(doorwayLight.level);
|
|
2343
2346
|
const lightIndex = this.getLightIndexForSide(doorwayLight.position);
|
|
2344
2347
|
const effect = LIGHT_EFFECTS[doorwayLight.style] || LIGHT_EFFECTS.off;
|
|
2345
|
-
commands.push({ layerIndex, lightIndex, effect, loop:
|
|
2348
|
+
commands.push({ layerIndex, lightIndex, effect, loop: effect !== LIGHT_EFFECTS.off });
|
|
2346
2349
|
}
|
|
2347
2350
|
}
|
|
2348
2351
|
if (lights.ledge) {
|
|
@@ -2350,7 +2353,7 @@ var UdtTowerCommands = class {
|
|
|
2350
2353
|
const layerIndex = TOWER_LAYERS.LEDGE;
|
|
2351
2354
|
const lightIndex = this.getLedgeLightIndexForSide(ledgeLight.position);
|
|
2352
2355
|
const effect = LIGHT_EFFECTS[ledgeLight.style] || LIGHT_EFFECTS.off;
|
|
2353
|
-
commands.push({ layerIndex, lightIndex, effect, loop:
|
|
2356
|
+
commands.push({ layerIndex, lightIndex, effect, loop: effect !== LIGHT_EFFECTS.off });
|
|
2354
2357
|
}
|
|
2355
2358
|
}
|
|
2356
2359
|
if (lights.base) {
|
|
@@ -2358,7 +2361,7 @@ var UdtTowerCommands = class {
|
|
|
2358
2361
|
const layerIndex = baseLight.position.level === "top" || baseLight.position.level === "b" ? TOWER_LAYERS.BASE2 : TOWER_LAYERS.BASE1;
|
|
2359
2362
|
const lightIndex = this.getBaseLightIndexForSide(baseLight.position.side);
|
|
2360
2363
|
const effect = LIGHT_EFFECTS[baseLight.style] || LIGHT_EFFECTS.off;
|
|
2361
|
-
commands.push({ layerIndex, lightIndex, effect, loop:
|
|
2364
|
+
commands.push({ layerIndex, lightIndex, effect, loop: effect !== LIGHT_EFFECTS.off });
|
|
2362
2365
|
}
|
|
2363
2366
|
}
|
|
2364
2367
|
return commands;
|
|
@@ -2564,8 +2567,7 @@ var UdtTowerCommands = class {
|
|
|
2564
2567
|
};
|
|
2565
2568
|
const command = this.deps.commandFactory.createStatefulCommand(currentState, modifications);
|
|
2566
2569
|
await this.sendTowerCommand(command, "resetTowerSkullCount");
|
|
2567
|
-
const updatedState = { ...currentState };
|
|
2568
|
-
updatedState.beam.count = 0;
|
|
2570
|
+
const updatedState = { ...currentState, beam: { ...currentState.beam, count: 0 } };
|
|
2569
2571
|
this.deps.setTowerState(updatedState, "resetTowerSkullCount");
|
|
2570
2572
|
}
|
|
2571
2573
|
/**
|
|
@@ -2836,10 +2838,15 @@ var UltimateDarkTower = class {
|
|
|
2836
2838
|
this.onCalibrationComplete = () => {
|
|
2837
2839
|
};
|
|
2838
2840
|
this.onSkullDrop = (towerSkullCount) => {
|
|
2841
|
+
void towerSkullCount;
|
|
2839
2842
|
};
|
|
2840
2843
|
this.onBatteryLevelNotify = (millivolts) => {
|
|
2844
|
+
void millivolts;
|
|
2841
2845
|
};
|
|
2842
2846
|
this.onTowerStateUpdate = (newState, oldState, source) => {
|
|
2847
|
+
void newState;
|
|
2848
|
+
void oldState;
|
|
2849
|
+
void source;
|
|
2843
2850
|
};
|
|
2844
2851
|
// utility
|
|
2845
2852
|
this._logDetail = false;
|
|
@@ -2870,6 +2877,12 @@ var UltimateDarkTower = class {
|
|
|
2870
2877
|
this.commandFactory = new UdtCommandFactory();
|
|
2871
2878
|
const commandDependencies = this.createCommandDependencies();
|
|
2872
2879
|
this.towerCommands = new UdtTowerCommands(commandDependencies);
|
|
2880
|
+
if (config?.brokenSeals) {
|
|
2881
|
+
for (const seal of config.brokenSeals) {
|
|
2882
|
+
const sealKey = `${seal.level}-${seal.side}`;
|
|
2883
|
+
this.brokenSeals.add(sealKey);
|
|
2884
|
+
}
|
|
2885
|
+
}
|
|
2873
2886
|
}
|
|
2874
2887
|
/**
|
|
2875
2888
|
* Set up the tower response callback after all components are initialized
|
|
@@ -2984,23 +2997,23 @@ var UltimateDarkTower = class {
|
|
|
2984
2997
|
return this.previousBatteryPercentage;
|
|
2985
2998
|
}
|
|
2986
2999
|
// Getter/setter methods for connection configuration
|
|
2987
|
-
get
|
|
2988
|
-
return this.bleConnection.
|
|
3000
|
+
get batteryLogFrequency() {
|
|
3001
|
+
return this.bleConnection.batteryLogFrequency;
|
|
2989
3002
|
}
|
|
2990
|
-
set
|
|
2991
|
-
this.bleConnection.
|
|
3003
|
+
set batteryLogFrequency(value) {
|
|
3004
|
+
this.bleConnection.batteryLogFrequency = value;
|
|
2992
3005
|
}
|
|
2993
|
-
get
|
|
2994
|
-
return this.bleConnection.
|
|
3006
|
+
get batteryLogOnChangeOnly() {
|
|
3007
|
+
return this.bleConnection.batteryLogOnChangeOnly;
|
|
2995
3008
|
}
|
|
2996
|
-
set
|
|
2997
|
-
this.bleConnection.
|
|
3009
|
+
set batteryLogOnChangeOnly(value) {
|
|
3010
|
+
this.bleConnection.batteryLogOnChangeOnly = value;
|
|
2998
3011
|
}
|
|
2999
|
-
get
|
|
3000
|
-
return this.bleConnection.
|
|
3012
|
+
get batteryLogEnabled() {
|
|
3013
|
+
return this.bleConnection.batteryLogEnabled;
|
|
3001
3014
|
}
|
|
3002
|
-
set
|
|
3003
|
-
this.bleConnection.
|
|
3015
|
+
set batteryLogEnabled(value) {
|
|
3016
|
+
this.bleConnection.batteryLogEnabled = value;
|
|
3004
3017
|
}
|
|
3005
3018
|
get logTowerResponses() {
|
|
3006
3019
|
return this.bleConnection.logTowerResponses;
|
|
@@ -3184,11 +3197,10 @@ var UltimateDarkTower = class {
|
|
|
3184
3197
|
* @returns Promise that resolves when the command is sent
|
|
3185
3198
|
*/
|
|
3186
3199
|
async sendTowerState(towerState) {
|
|
3187
|
-
const { rtdt_pack_state: rtdt_pack_state2 } = await Promise.resolve().then(() => (init_udtTowerState(), udtTowerState_exports));
|
|
3188
3200
|
const stateToSend = { ...towerState };
|
|
3189
3201
|
stateToSend.audio = { sample: 0, loop: false, volume: 0 };
|
|
3190
3202
|
const stateData = new Uint8Array(TOWER_STATE_DATA_SIZE);
|
|
3191
|
-
const success =
|
|
3203
|
+
const success = rtdt_pack_state(stateData, TOWER_STATE_DATA_SIZE, stateToSend);
|
|
3192
3204
|
if (!success) {
|
|
3193
3205
|
throw new Error("Failed to pack tower state data");
|
|
3194
3206
|
}
|
|
@@ -3216,11 +3228,9 @@ var UltimateDarkTower = class {
|
|
|
3216
3228
|
* @param stateData - The 19-byte state data from tower response
|
|
3217
3229
|
*/
|
|
3218
3230
|
updateTowerStateFromResponse(stateData) {
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
this.setTowerState(newState, "tower response");
|
|
3223
|
-
});
|
|
3231
|
+
const newState = rtdt_unpack_state(stateData);
|
|
3232
|
+
newState.audio = { sample: 0, loop: false, volume: this.currentTowerState.audio.volume };
|
|
3233
|
+
this.setTowerState(newState, "tower response");
|
|
3224
3234
|
}
|
|
3225
3235
|
//#endregion
|
|
3226
3236
|
/**
|
|
@@ -3380,6 +3390,25 @@ var UltimateDarkTower = class {
|
|
|
3380
3390
|
return { level, side };
|
|
3381
3391
|
});
|
|
3382
3392
|
}
|
|
3393
|
+
/**
|
|
3394
|
+
* Marks a seal as broken in software tracking without sending any commands to the tower.
|
|
3395
|
+
* Use this to restore game state (e.g., resuming a game where seals were already broken).
|
|
3396
|
+
* Unlike breakSeal(), this does NOT trigger sound or light effects on the tower.
|
|
3397
|
+
* @param seal - Seal identifier to mark as broken
|
|
3398
|
+
*/
|
|
3399
|
+
markSealBroken(seal) {
|
|
3400
|
+
const sealKey = `${seal.level}-${seal.side}`;
|
|
3401
|
+
this.brokenSeals.add(sealKey);
|
|
3402
|
+
}
|
|
3403
|
+
/**
|
|
3404
|
+
* Marks a seal as unbroken in software tracking without sending any commands to the tower.
|
|
3405
|
+
* Use this to undo a seal break or restore individual seals for game state management.
|
|
3406
|
+
* @param seal - Seal identifier to mark as unbroken
|
|
3407
|
+
*/
|
|
3408
|
+
markSealRestored(seal) {
|
|
3409
|
+
const sealKey = `${seal.level}-${seal.side}`;
|
|
3410
|
+
this.brokenSeals.delete(sealKey);
|
|
3411
|
+
}
|
|
3383
3412
|
/**
|
|
3384
3413
|
* Resets the broken seals tracking (clears all broken seals).
|
|
3385
3414
|
*/
|
|
@@ -3429,7 +3458,7 @@ var UltimateDarkTower = class {
|
|
|
3429
3458
|
* @param {LogOutput[]} outputs - Array of log outputs to use (e.g., ConsoleOutput, DOMOutput)
|
|
3430
3459
|
*/
|
|
3431
3460
|
setLoggerOutputs(outputs) {
|
|
3432
|
-
this.logger.
|
|
3461
|
+
this.logger.clearOutputs();
|
|
3433
3462
|
outputs.forEach((output) => this.logger.addOutput(output));
|
|
3434
3463
|
}
|
|
3435
3464
|
/**
|
|
@@ -3527,8 +3556,7 @@ var UltimateDarkTower_default = UltimateDarkTower;
|
|
|
3527
3556
|
// src/index.ts
|
|
3528
3557
|
init_udtConstants();
|
|
3529
3558
|
init_udtBluetoothAdapter();
|
|
3530
|
-
|
|
3531
|
-
var src_default = UltimateDarkTower_default;
|
|
3559
|
+
var index_default = UltimateDarkTower_default;
|
|
3532
3560
|
export {
|
|
3533
3561
|
AUDIO_COMMAND_POS,
|
|
3534
3562
|
BATTERY_STATUS_FREQUENCY,
|
|
@@ -3589,7 +3617,7 @@ export {
|
|
|
3589
3617
|
VOLUME_DESCRIPTIONS,
|
|
3590
3618
|
VOLUME_ICONS,
|
|
3591
3619
|
createDefaultTowerState,
|
|
3592
|
-
|
|
3620
|
+
index_default as default,
|
|
3593
3621
|
drumPositionCmds,
|
|
3594
3622
|
isCalibrated,
|
|
3595
3623
|
logger,
|