@opendisplay/opendisplay 1.0.1 → 1.1.1
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/README.md +4 -18
- package/dist/index.cjs +50 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.js +50 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -651,7 +651,10 @@ declare class OpenDisplayDevice {
|
|
|
651
651
|
* await device.uploadImage(imageData, {
|
|
652
652
|
* refreshMode: RefreshMode.FULL,
|
|
653
653
|
* ditherMode: DitherMode.BURKES,
|
|
654
|
-
* compress: true
|
|
654
|
+
* compress: true,
|
|
655
|
+
* onProgress: (current, total, stage) => {
|
|
656
|
+
* console.log(`${stage}: ${current}/${total} (${Math.floor(current/total*100)}%)`);
|
|
657
|
+
* }
|
|
655
658
|
* });
|
|
656
659
|
* ```
|
|
657
660
|
*/
|
|
@@ -659,6 +662,8 @@ declare class OpenDisplayDevice {
|
|
|
659
662
|
refreshMode?: RefreshMode;
|
|
660
663
|
ditherMode?: DitherMode;
|
|
661
664
|
compress?: boolean;
|
|
665
|
+
onProgress?: (current: number, total: number, stage: string) => void;
|
|
666
|
+
onStatusChange?: (message: string) => void;
|
|
662
667
|
}): Promise<void>;
|
|
663
668
|
/**
|
|
664
669
|
* Execute image upload using compressed or uncompressed protocol.
|
|
@@ -673,6 +678,8 @@ declare class OpenDisplayDevice {
|
|
|
673
678
|
* - Progress logging
|
|
674
679
|
*
|
|
675
680
|
* @param imageData - Data to send in chunks
|
|
681
|
+
* @param onProgress - Optional progress callback (current bytes, total bytes, stage)
|
|
682
|
+
* @param onStatusChange - Optional status message callback
|
|
676
683
|
* @returns True if device auto-completed (sent 0x0072 END early), false if all chunks sent normally
|
|
677
684
|
* @throws {ProtocolError} If unexpected response received
|
|
678
685
|
* @throws {BLETimeoutError} If no response within timeout
|
package/dist/index.d.ts
CHANGED
|
@@ -651,7 +651,10 @@ declare class OpenDisplayDevice {
|
|
|
651
651
|
* await device.uploadImage(imageData, {
|
|
652
652
|
* refreshMode: RefreshMode.FULL,
|
|
653
653
|
* ditherMode: DitherMode.BURKES,
|
|
654
|
-
* compress: true
|
|
654
|
+
* compress: true,
|
|
655
|
+
* onProgress: (current, total, stage) => {
|
|
656
|
+
* console.log(`${stage}: ${current}/${total} (${Math.floor(current/total*100)}%)`);
|
|
657
|
+
* }
|
|
655
658
|
* });
|
|
656
659
|
* ```
|
|
657
660
|
*/
|
|
@@ -659,6 +662,8 @@ declare class OpenDisplayDevice {
|
|
|
659
662
|
refreshMode?: RefreshMode;
|
|
660
663
|
ditherMode?: DitherMode;
|
|
661
664
|
compress?: boolean;
|
|
665
|
+
onProgress?: (current: number, total: number, stage: string) => void;
|
|
666
|
+
onStatusChange?: (message: string) => void;
|
|
662
667
|
}): Promise<void>;
|
|
663
668
|
/**
|
|
664
669
|
* Execute image upload using compressed or uncompressed protocol.
|
|
@@ -673,6 +678,8 @@ declare class OpenDisplayDevice {
|
|
|
673
678
|
* - Progress logging
|
|
674
679
|
*
|
|
675
680
|
* @param imageData - Data to send in chunks
|
|
681
|
+
* @param onProgress - Optional progress callback (current bytes, total bytes, stage)
|
|
682
|
+
* @param onStatusChange - Optional status message callback
|
|
676
683
|
* @returns True if device auto-completed (sent 0x0072 END early), false if all chunks sent normally
|
|
677
684
|
* @throws {ProtocolError} If unexpected response received
|
|
678
685
|
* @throws {BLETimeoutError} If no response within timeout
|
package/dist/index.js
CHANGED
|
@@ -1340,6 +1340,16 @@ var BLEConnection = class {
|
|
|
1340
1340
|
}
|
|
1341
1341
|
return this.notificationQueue.dequeue(timeoutMs);
|
|
1342
1342
|
}
|
|
1343
|
+
/**
|
|
1344
|
+
* Clear the notification queue.
|
|
1345
|
+
*
|
|
1346
|
+
* Useful for clearing any stale responses before starting a new operation.
|
|
1347
|
+
* This drains any buffered notifications and cancels pending read requests.
|
|
1348
|
+
*/
|
|
1349
|
+
clearQueue() {
|
|
1350
|
+
console.debug(`Clearing notification queue (${this.notificationQueue.size} buffered)`);
|
|
1351
|
+
this.notificationQueue.clear("Queue cleared by request");
|
|
1352
|
+
}
|
|
1343
1353
|
/**
|
|
1344
1354
|
* Handle incoming BLE notifications.
|
|
1345
1355
|
*
|
|
@@ -1660,7 +1670,10 @@ var OpenDisplayDevice = class _OpenDisplayDevice {
|
|
|
1660
1670
|
* await device.uploadImage(imageData, {
|
|
1661
1671
|
* refreshMode: RefreshMode.FULL,
|
|
1662
1672
|
* ditherMode: DitherMode.BURKES,
|
|
1663
|
-
* compress: true
|
|
1673
|
+
* compress: true,
|
|
1674
|
+
* onProgress: (current, total, stage) => {
|
|
1675
|
+
* console.log(`${stage}: ${current}/${total} (${Math.floor(current/total*100)}%)`);
|
|
1676
|
+
* }
|
|
1664
1677
|
* });
|
|
1665
1678
|
* ```
|
|
1666
1679
|
*/
|
|
@@ -1670,9 +1683,12 @@ var OpenDisplayDevice = class _OpenDisplayDevice {
|
|
|
1670
1683
|
const refreshMode = options.refreshMode ?? 0 /* FULL */;
|
|
1671
1684
|
const ditherMode = options.ditherMode ?? DitherMode2.BURKES;
|
|
1672
1685
|
const compress = options.compress ?? true;
|
|
1686
|
+
const onProgress = options.onProgress;
|
|
1687
|
+
const onStatusChange = options.onStatusChange;
|
|
1673
1688
|
console.log(
|
|
1674
1689
|
`Uploading image (${this.width}x${this.height}, ${ColorScheme4[this.colorScheme]})`
|
|
1675
1690
|
);
|
|
1691
|
+
onStatusChange?.("Preparing image...");
|
|
1676
1692
|
const encodedData = prepareImageForUpload(
|
|
1677
1693
|
imageData,
|
|
1678
1694
|
this.width,
|
|
@@ -1682,27 +1698,44 @@ var OpenDisplayDevice = class _OpenDisplayDevice {
|
|
|
1682
1698
|
);
|
|
1683
1699
|
let compressedData = null;
|
|
1684
1700
|
if (compress) {
|
|
1701
|
+
onStatusChange?.("Compressing...");
|
|
1685
1702
|
compressedData = compressImageData(encodedData, 6);
|
|
1686
1703
|
if (compressedData.length < MAX_COMPRESSED_SIZE) {
|
|
1687
1704
|
console.log(`Using compressed upload protocol (size: ${compressedData.length} bytes)`);
|
|
1705
|
+
onStatusChange?.("Uploading...");
|
|
1688
1706
|
await this.executeUpload({
|
|
1689
1707
|
imageData: encodedData,
|
|
1690
1708
|
refreshMode,
|
|
1691
1709
|
useCompression: true,
|
|
1692
1710
|
compressedData,
|
|
1693
|
-
uncompressedSize: encodedData.length
|
|
1711
|
+
uncompressedSize: encodedData.length,
|
|
1712
|
+
onProgress,
|
|
1713
|
+
onStatusChange
|
|
1694
1714
|
});
|
|
1695
1715
|
} else {
|
|
1696
1716
|
console.log(
|
|
1697
1717
|
`Compressed size exceeds ${MAX_COMPRESSED_SIZE} bytes, using uncompressed protocol`
|
|
1698
1718
|
);
|
|
1699
|
-
|
|
1719
|
+
onStatusChange?.("Uploading...");
|
|
1720
|
+
await this.executeUpload({
|
|
1721
|
+
imageData: encodedData,
|
|
1722
|
+
refreshMode,
|
|
1723
|
+
onProgress,
|
|
1724
|
+
onStatusChange
|
|
1725
|
+
});
|
|
1700
1726
|
}
|
|
1701
1727
|
} else {
|
|
1702
1728
|
console.log("Compression disabled, using uncompressed protocol");
|
|
1703
|
-
|
|
1729
|
+
onStatusChange?.("Uploading...");
|
|
1730
|
+
await this.executeUpload({
|
|
1731
|
+
imageData: encodedData,
|
|
1732
|
+
refreshMode,
|
|
1733
|
+
onProgress,
|
|
1734
|
+
onStatusChange
|
|
1735
|
+
});
|
|
1704
1736
|
}
|
|
1705
1737
|
console.log("Image upload complete");
|
|
1738
|
+
onStatusChange?.("Upload complete!");
|
|
1706
1739
|
}
|
|
1707
1740
|
/**
|
|
1708
1741
|
* Execute image upload using compressed or uncompressed protocol.
|
|
@@ -1713,8 +1746,11 @@ var OpenDisplayDevice = class _OpenDisplayDevice {
|
|
|
1713
1746
|
refreshMode,
|
|
1714
1747
|
useCompression = false,
|
|
1715
1748
|
compressedData,
|
|
1716
|
-
uncompressedSize
|
|
1749
|
+
uncompressedSize,
|
|
1750
|
+
onProgress,
|
|
1751
|
+
onStatusChange
|
|
1717
1752
|
} = params;
|
|
1753
|
+
this.connection.clearQueue();
|
|
1718
1754
|
let startCmd;
|
|
1719
1755
|
let remainingCompressed = null;
|
|
1720
1756
|
if (useCompression && compressedData && uncompressedSize) {
|
|
@@ -1732,11 +1768,12 @@ var OpenDisplayDevice = class _OpenDisplayDevice {
|
|
|
1732
1768
|
validateAckResponse(response, 112 /* DIRECT_WRITE_START */);
|
|
1733
1769
|
let autoCompleted = false;
|
|
1734
1770
|
if (useCompression && remainingCompressed && remainingCompressed.length > 0) {
|
|
1735
|
-
autoCompleted = await this.sendDataChunks(remainingCompressed);
|
|
1771
|
+
autoCompleted = await this.sendDataChunks(remainingCompressed, onProgress, onStatusChange);
|
|
1736
1772
|
} else if (!useCompression) {
|
|
1737
|
-
autoCompleted = await this.sendDataChunks(imageData);
|
|
1773
|
+
autoCompleted = await this.sendDataChunks(imageData, onProgress, onStatusChange);
|
|
1738
1774
|
}
|
|
1739
1775
|
if (!autoCompleted) {
|
|
1776
|
+
onStatusChange?.("Refreshing display...");
|
|
1740
1777
|
const endCmd = buildDirectWriteEndCommand(refreshMode);
|
|
1741
1778
|
await this.connection.writeCommand(endCmd);
|
|
1742
1779
|
response = await this.connection.readResponse(
|
|
@@ -1754,11 +1791,13 @@ var OpenDisplayDevice = class _OpenDisplayDevice {
|
|
|
1754
1791
|
* - Progress logging
|
|
1755
1792
|
*
|
|
1756
1793
|
* @param imageData - Data to send in chunks
|
|
1794
|
+
* @param onProgress - Optional progress callback (current bytes, total bytes, stage)
|
|
1795
|
+
* @param onStatusChange - Optional status message callback
|
|
1757
1796
|
* @returns True if device auto-completed (sent 0x0072 END early), false if all chunks sent normally
|
|
1758
1797
|
* @throws {ProtocolError} If unexpected response received
|
|
1759
1798
|
* @throws {BLETimeoutError} If no response within timeout
|
|
1760
1799
|
*/
|
|
1761
|
-
async sendDataChunks(imageData) {
|
|
1800
|
+
async sendDataChunks(imageData, onProgress, onStatusChange) {
|
|
1762
1801
|
let bytesSent = 0;
|
|
1763
1802
|
let chunksSent = 0;
|
|
1764
1803
|
while (bytesSent < imageData.length) {
|
|
@@ -1779,6 +1818,7 @@ var OpenDisplayDevice = class _OpenDisplayDevice {
|
|
|
1779
1818
|
console.log(
|
|
1780
1819
|
`No response after chunk ${chunksSent} (${(bytesSent / imageData.length * 100).toFixed(1)}%), waiting for device refresh...`
|
|
1781
1820
|
);
|
|
1821
|
+
onStatusChange?.("Refreshing display...");
|
|
1782
1822
|
response = await this.connection.readResponse(
|
|
1783
1823
|
_OpenDisplayDevice.TIMEOUT_REFRESH
|
|
1784
1824
|
);
|
|
@@ -1788,10 +1828,12 @@ var OpenDisplayDevice = class _OpenDisplayDevice {
|
|
|
1788
1828
|
}
|
|
1789
1829
|
const [command, isAck] = checkResponseType(response);
|
|
1790
1830
|
if (command === 113 /* DIRECT_WRITE_DATA */) {
|
|
1831
|
+
onProgress?.(bytesSent, imageData.length, "upload");
|
|
1791
1832
|
} else if (command === 114 /* DIRECT_WRITE_END */) {
|
|
1792
1833
|
console.log(
|
|
1793
1834
|
`Received END response after chunk ${chunksSent} - device auto-completed`
|
|
1794
1835
|
);
|
|
1836
|
+
onProgress?.(imageData.length, imageData.length, "upload");
|
|
1795
1837
|
return true;
|
|
1796
1838
|
} else {
|
|
1797
1839
|
throw new ProtocolError(
|