From 2659b824ede7718df24564f6dd0c74004c4a97b6 Mon Sep 17 00:00:00 2001
From: MultiMote <contact@mmote.ru>
Date: Wed, 8 Jan 2025 11:56:25 +0300
Subject: [PATCH] Move raw packet processing to the base class

---
 src/client/abstract_client.ts    | 38 +++++++++++++++++++++++++++++
 src/client/bluetooth_impl.ts     | 18 +++-----------
 src/client/capacitor_ble_impl.ts | 42 +++-----------------------------
 src/client/serial_impl.ts        | 26 ++------------------
 4 files changed, 47 insertions(+), 77 deletions(-)

diff --git a/src/client/abstract_client.ts b/src/client/abstract_client.ts
index efa748f..5bb8b9e 100644
--- a/src/client/abstract_client.ts
+++ b/src/client/abstract_client.ts
@@ -19,6 +19,7 @@ import {
   HeartbeatEvent,
   HeartbeatFailedEvent,
   PacketReceivedEvent,
+  RawPacketReceivedEvent,
 } from "../events";
 import { findPrintTask, PrintTaskName } from "../print_tasks";
 import { Utils, Validators } from "../utils";
@@ -65,6 +66,7 @@ export abstract class NiimbotAbstractClient extends EventEmitter<ClientEventMap>
   private heartbeatIntervalMs: number = 2_000;
   protected mutex: Mutex = new Mutex();
   protected debug: boolean = false;
+  private packetBuf = new Uint8Array();
 
   /** @see https://github.com/MultiMote/niimblue/issues/5 */
   protected packetIntervalMs: number = 10;
@@ -145,6 +147,42 @@ export abstract class NiimbotAbstractClient extends EventEmitter<ClientEventMap>
     });
   }
 
+  /**
+   * Convert raw bytes to packet objects and fire events. Defragmentation included.
+   * @param data Bytes to process.
+   */
+  protected processRawPacket(data: DataView | Uint8Array) {
+    if (data.byteLength === 0) {
+      return;
+    }
+
+    console.log("processRawPacket")
+
+    if (data instanceof DataView) {
+      data = new Uint8Array(data.buffer);
+    }
+
+    this.packetBuf = Utils.u8ArrayAppend(this.packetBuf, data);
+
+    try {
+      const packets: NiimbotPacket[] = NiimbotPacket.fromBytesMultiPacket(this.packetBuf);
+
+      if (packets.length > 0) {
+        this.emit("rawpacketreceived", new RawPacketReceivedEvent(this.packetBuf));
+
+        packets.forEach((p) => {
+          this.emit("packetreceived", new PacketReceivedEvent(p));
+        });
+
+        this.packetBuf = new Uint8Array();
+      }
+    } catch (_e) {
+      if (this.debug) {
+        console.info(`Incomplete packet, ignoring:${Utils.bufToHex(this.packetBuf)}`);
+      }
+    }
+  }
+
   /**
    * Send raw bytes to the printer port.
    *
diff --git a/src/client/bluetooth_impl.ts b/src/client/bluetooth_impl.ts
index a32f37f..cbd3151 100644
--- a/src/client/bluetooth_impl.ts
+++ b/src/client/bluetooth_impl.ts
@@ -1,7 +1,6 @@
-import { ConnectEvent, DisconnectEvent, PacketReceivedEvent, RawPacketReceivedEvent, RawPacketSentEvent } from "../events";
+import { ConnectEvent, DisconnectEvent, RawPacketSentEvent } from "../events";
 import { ConnectionInfo, NiimbotAbstractClient } from ".";
-import { NiimbotPacket } from "../packets/packet";
-import { ConnectResult, ResponseCommandId } from "../packets";
+import { ConnectResult } from "../packets";
 import { Utils } from "../utils";
 
 class BleConfiguration {
@@ -65,18 +64,7 @@ export class NiimbotBluetoothClient extends NiimbotAbstractClient {
 
     channel.addEventListener("characteristicvaluechanged", (event: Event) => {
       const target = event.target as BluetoothRemoteGATTCharacteristic;
-
-      const data = new Uint8Array(target.value!.buffer);
-
-      this.emit("rawpacketreceived", new RawPacketReceivedEvent(data));
-
-      const packet = NiimbotPacket.fromBytes(data);
-
-      this.emit("packetreceived", new PacketReceivedEvent(packet));
-
-      if (!(packet.command in ResponseCommandId)) {
-        console.warn(`Unknown response command: 0x${Utils.numberToHex(packet.command)}`);
-      }
+      this.processRawPacket(target.value!);
     });
 
     await channel.startNotifications();
diff --git a/src/client/capacitor_ble_impl.ts b/src/client/capacitor_ble_impl.ts
index cad8077..ffa25c4 100644
--- a/src/client/capacitor_ble_impl.ts
+++ b/src/client/capacitor_ble_impl.ts
@@ -1,19 +1,12 @@
-import {
-  ConnectEvent,
-  DisconnectEvent,
-  PacketReceivedEvent,
-  RawPacketReceivedEvent,
-  RawPacketSentEvent,
-} from "../events";
+import { ConnectEvent, DisconnectEvent, RawPacketSentEvent } from "../events";
 import { ConnectionInfo, NiimbotAbstractClient } from ".";
-import { NiimbotPacket } from "../packets/packet";
 import { ConnectResult } from "../packets";
 import { Utils } from "../utils";
 import { BleCharacteristic, BleClient, BleDevice, BleService } from "@capacitor-community/bluetooth-le";
 
 /**
-  * @category Client
-  */
+ * @category Client
+ */
 export interface NiimbotCapacitorBleClientConnectOptions {
   /**
    * Skip device picker dialog and connect to given device ID.
@@ -34,7 +27,6 @@ export class NiimbotCapacitorBleClient extends NiimbotAbstractClient {
   private deviceId?: string;
   private serviceUUID?: string;
   private characteristicUUID?: string;
-  private packetBuf = new Uint8Array();
 
   public async connect(options?: NiimbotCapacitorBleClientConnectOptions): Promise<ConnectionInfo> {
     await this.disconnect();
@@ -73,7 +65,7 @@ export class NiimbotCapacitorBleClient extends NiimbotAbstractClient {
     }
 
     await BleClient.startNotifications(this.deviceId, this.serviceUUID, this.characteristicUUID, (value: DataView) => {
-      this.onBlePacketReceived(value);
+      this.processRawPacket(value);
     });
 
     try {
@@ -116,32 +108,6 @@ export class NiimbotCapacitorBleClient extends NiimbotAbstractClient {
     throw new Error("Unable to find suitable channel characteristic");
   }
 
-  private onBlePacketReceived(dv: DataView) {
-    if (dv.byteLength === 0) {
-      return;
-    }
-
-    this.packetBuf = Utils.u8ArrayAppend(this.packetBuf, new Uint8Array(dv.buffer));
-
-    try {
-      const packets: NiimbotPacket[] = NiimbotPacket.fromBytesMultiPacket(this.packetBuf);
-
-      if (packets.length > 0) {
-        this.emit("rawpacketreceived", new RawPacketReceivedEvent(this.packetBuf));
-
-        packets.forEach((p) => {
-          this.emit("packetreceived", new PacketReceivedEvent(p));
-        });
-
-        this.packetBuf = new Uint8Array();
-      }
-    } catch (_e) {
-      if (this.debug) {
-        console.info(`Incomplete packet, ignoring:${Utils.bufToHex(this.packetBuf)}`);
-      }
-    }
-  }
-
   private onBleDisconnect() {
     this.deviceId = undefined;
     this.serviceUUID = undefined;
diff --git a/src/client/serial_impl.ts b/src/client/serial_impl.ts
index 812e042..63bf7d7 100644
--- a/src/client/serial_impl.ts
+++ b/src/client/serial_impl.ts
@@ -1,6 +1,5 @@
-import { ConnectEvent, DisconnectEvent, PacketReceivedEvent, RawPacketReceivedEvent, RawPacketSentEvent } from "../events";
+import { ConnectEvent, DisconnectEvent, RawPacketSentEvent } from "../events";
 import { ConnectionInfo, NiimbotAbstractClient } from ".";
-import { NiimbotPacket } from "../packets/packet";
 import { ConnectResult } from "../packets";
 import { Utils } from "../utils";
 
@@ -63,8 +62,6 @@ export class NiimbotSerialClient extends NiimbotAbstractClient {
   }
 
   private async waitSerialData() {
-    let buf = new Uint8Array();
-
     while (true) {
       try {
         const result = await this.reader!.read();
@@ -72,8 +69,7 @@ export class NiimbotSerialClient extends NiimbotAbstractClient {
           if (this.debug) {
             console.info(`<< serial chunk ${Utils.bufToHex(result.value)}`);
           }
-
-          buf = Utils.u8ArrayAppend(buf, result.value);
+          this.processRawPacket(result.value);
         }
 
         if (result.done) {
@@ -83,24 +79,6 @@ export class NiimbotSerialClient extends NiimbotAbstractClient {
       } catch (_e) {
         break;
       }
-
-      try {
-        const packets: NiimbotPacket[] = NiimbotPacket.fromBytesMultiPacket(buf);
-
-        if (packets.length > 0) {
-          this.emit("rawpacketreceived", new RawPacketReceivedEvent(buf));
-
-          packets.forEach((p) => {
-            this.emit("packetreceived", new PacketReceivedEvent(p));
-          });
-
-          buf = new Uint8Array();
-        }
-      } catch (_e) {
-        if (this.debug) {
-          console.info(`Incomplete packet, ignoring:${Utils.bufToHex(buf)}`);
-        }
-      }
     }
   }