diff --git a/src/packets/abstraction.ts b/src/packets/abstraction.ts
index 12b1c84..9800517 100644
--- a/src/packets/abstraction.ts
+++ b/src/packets/abstraction.ts
@@ -351,7 +351,7 @@ export class Abstraction {
     await this.send(PacketGenerator.printerReset());
   }
 
-  public async waitUntilPrintFinishedV1(pagesToPrint: number, timeoutMs: number = 5_000): Promise<void> {
+  public async waitUntilPrintFinishedByPageIndex(pagesToPrint: number, timeoutMs: number = 5_000): Promise<void> {
     return new Promise<void>((resolve, reject) => {
       const listener = (evt: PacketReceivedEvent) => {
         if (evt.packet.command === ResponseCommandId.In_PrinterPageIndex) {
@@ -393,7 +393,7 @@ export class Abstraction {
    * @param pagesToPrint Total pages to print.
    * @param pollIntervalMs Poll interval in milliseconds.
    */
-  public async waitUntilPrintFinishedV2(pagesToPrint: number, pollIntervalMs: number = 300): Promise<void> {
+  public async waitUntilPrintFinishedByStatusPoll(pagesToPrint: number, pollIntervalMs: number = 300): Promise<void> {
     return new Promise<void>((resolve, reject) => {
       this.client.dispatchTypedEvent("printprogress", new PrintProgressEvent(1, pagesToPrint, 0, 0));
 
@@ -418,8 +418,44 @@ export class Abstraction {
     });
   }
 
-  public async printEnd(): Promise<void> {
-    await this.send(PacketGenerator.printEnd());
+  /**
+   * Poll printer every {@link pollIntervalMs} and resolve when printer pages equals {@link pagesToPrint}.
+   *
+   * printprogress event is firing during this process.
+   *
+   * PrintEnd call is not needed after this functions is done running.
+   *
+   * @param pagesToPrint Total pages to print.
+   * @param pollIntervalMs Poll interval in milliseconds.
+   */
+  public async waitUntilPrintFinishedByPrintEndPoll(pagesToPrint: number, pollIntervalMs: number = 500): Promise<void> {
+    return new Promise<void>((resolve, reject) => {
+      this.client.dispatchTypedEvent("printprogress", new PrintProgressEvent(1, pagesToPrint, 0, 0));
+
+      this.statusPollTimer = setInterval(() => {
+        this.printEnd()
+          .then((printEndDone: boolean) => {
+            if(!printEndDone) {
+              this.client.dispatchTypedEvent("printprogress", new PrintProgressEvent(1, pagesToPrint, 0, 0));
+            } else {
+              this.client.dispatchTypedEvent("printprogress", new PrintProgressEvent(pagesToPrint, pagesToPrint, 100, 100));
+              clearInterval(this.statusPollTimer);
+              resolve();
+            }
+          })
+          .catch((e: unknown) => {
+            clearInterval(this.statusPollTimer);
+            reject(e as Error);
+          });
+      }, pollIntervalMs ?? 500);
+    });
+  }
+
+  /** False returned when printEnd refused */
+  public async printEnd(): Promise<boolean> {
+    const response = await this.send(PacketGenerator.printEnd());
+    Validators.u8ArrayLengthEquals(response.data, 1);
+    return response.data[0] === 1;
   }
 
   public newPrintTask(name: PrintTaskName, options?: PrintOptions): AbstractPrintTask {
diff --git a/src/print_tasks/B1PrintTask.ts b/src/print_tasks/B1PrintTask.ts
index b95e148..9c2b1e3 100644
--- a/src/print_tasks/B1PrintTask.ts
+++ b/src/print_tasks/B1PrintTask.ts
@@ -23,7 +23,7 @@ export class B1PrintTask extends AbstractPrintTask {
   }
 
   override waitForFinished(): Promise<void> {
-    return this.abstraction.waitUntilPrintFinishedV2(
+    return this.abstraction.waitUntilPrintFinishedByStatusPoll(
       this.printOptions.totalPages ?? 1,
       this.printOptions.statusPollIntervalMs
     );
diff --git a/src/print_tasks/B21V1PrintTask.ts b/src/print_tasks/B21V1PrintTask.ts
new file mode 100644
index 0000000..2332591
--- /dev/null
+++ b/src/print_tasks/B21V1PrintTask.ts
@@ -0,0 +1,33 @@
+import { EncodedImage } from "../image_encoder";
+import { LabelType, PacketGenerator } from "../packets";
+import { AbstractPrintTask } from "./AbstractPrintTask";
+
+export class B21V1PrintTask extends AbstractPrintTask {
+  override printInit(): Promise<void> {
+    return this.abstraction.sendAll([
+      PacketGenerator.setDensity(this.printOptions.density ?? 2),
+      PacketGenerator.setLabelType(this.printOptions.labelType ?? LabelType.WithGaps),
+      PacketGenerator.printStart(),
+    ]);
+  }
+
+  override async printPage(image: EncodedImage, quantity?: number): Promise<void> {
+    this.checkAddPage(quantity ?? 1);
+
+    for (let i = 0; i < (quantity ?? 1); i++) {
+      await this.abstraction.sendAll([
+        PacketGenerator.pageStart(),
+        PacketGenerator.setPageSizeV2(image.rows, image.cols),
+        ...PacketGenerator.writeImageData(image, this.printheadPixels()),
+        PacketGenerator.pageEnd(),
+      ], this.printOptions.pageTimeoutMs);
+    }
+  }
+
+  override waitForFinished(): Promise<void> {
+    return this.abstraction.waitUntilPrintFinishedByPrintEndPoll(
+      this.printOptions.totalPages ?? 1,
+      this.printOptions.statusPollIntervalMs
+    );
+  }
+}
diff --git a/src/print_tasks/D110PrintTask.ts b/src/print_tasks/D110PrintTask.ts
index df52787..a1dc865 100644
--- a/src/print_tasks/D110PrintTask.ts
+++ b/src/print_tasks/D110PrintTask.ts
@@ -24,7 +24,7 @@ export class D110PrintTask extends AbstractPrintTask {
   }
 
   override waitForFinished(): Promise<void> {
-    return this.abstraction.waitUntilPrintFinishedV2(
+    return this.abstraction.waitUntilPrintFinishedByStatusPoll(
       this.printOptions.totalPages ?? 1,
       this.printOptions.statusPollIntervalMs
     );
diff --git a/src/print_tasks/OldD11PrintTask.ts b/src/print_tasks/OldD11PrintTask.ts
index 69fb661..58048f0 100644
--- a/src/print_tasks/OldD11PrintTask.ts
+++ b/src/print_tasks/OldD11PrintTask.ts
@@ -25,7 +25,7 @@ export class OldD11PrintTask extends AbstractPrintTask {
   }
 
   override waitForFinished(): Promise<void> {
-    return this.abstraction.waitUntilPrintFinishedV1(
+    return this.abstraction.waitUntilPrintFinishedByPageIndex(
       this.printOptions.totalPages ?? 1,
       this.printOptions.statusTimeoutMs
     );
diff --git a/src/print_tasks/V5PrintTask.ts b/src/print_tasks/V5PrintTask.ts
index 614f91e..5b91d4f 100644
--- a/src/print_tasks/V5PrintTask.ts
+++ b/src/print_tasks/V5PrintTask.ts
@@ -23,7 +23,7 @@ export class V5PrintTask extends AbstractPrintTask {
   }
 
   override waitForFinished(): Promise<void> {
-    return this.abstraction.waitUntilPrintFinishedV2(
+    return this.abstraction.waitUntilPrintFinishedByStatusPoll(
       this.printOptions.totalPages ?? 1,
       this.printOptions.statusPollIntervalMs
     );
diff --git a/src/print_tasks/index.ts b/src/print_tasks/index.ts
index 8dcb860..805d0a4 100644
--- a/src/print_tasks/index.ts
+++ b/src/print_tasks/index.ts
@@ -1,5 +1,6 @@
 import { PrinterModel as M } from "../printer_models";
 import { B1PrintTask } from "./B1PrintTask";
+import { B21V1PrintTask } from "./B21V1PrintTask";
 import { D110PrintTask } from "./D110PrintTask";
 import { OldD11PrintTask } from "./OldD11PrintTask";
 import { V5PrintTask } from "./V5PrintTask";
@@ -8,6 +9,7 @@ export const printTasks = {
   D11_OLD: OldD11PrintTask,
   D110: D110PrintTask,
   B1: B1PrintTask,
+  B21_V1: B21V1PrintTask,
   V5: V5PrintTask,
 };
 
@@ -16,7 +18,8 @@ export type PrintTaskName = keyof typeof printTasks;
 export const printTaskNames = Object.keys(printTasks) as PrintTaskName[];
 
 export const modelPrintTasks: Partial<Record<PrintTaskName, M[]>> = {
-  D11_OLD: [M.D11, M.D11S, M.B21_L2B, M.B21, M.B21_PRO, M.B21_C2B],
+  D11_OLD: [M.D11, M.D11S],
+  B21_V1: [M.B21, M.B21_L2B, M.B21_C2B],
   D110: [M.B21S, M.B21S_C2B, M.D110],
   B1: [M.D11_H, M.D110_M, M.B1],
 };