Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

B21 Support? #4

Open
rickyelopez opened this issue May 14, 2023 · 30 comments
Open

B21 Support? #4

rickyelopez opened this issue May 14, 2023 · 30 comments

Comments

@rickyelopez
Copy link

Hi there, really cool that you managed to figure all this out.

I'm trying this on a B21, and when I try to print an image with a width of 96px, it comes out in the center of the label, rotated the wrong way, and tiny. Any idea why that might be happening?

I've read through all the code and I'm not understanding a few things:

  1. Why 96px? Surely this can print more pixels?
  2. Why rotate the image if the width/height ratio is > 1?
  3. Any chance you can document the expected packet structure for sending the image to the printer? seems like each line in the image is broken up into an array of 8 12bit sections (which adds up to 96, is this what drives the 96px?) and then prepended with some kind of parity header? Can this be extended to print something with more than 96px?

It is printing something, so it seems like the general structure is the same across this printer and whichever one you were testing this with. Happy to help get this working on the B21, but as it stands I'm missing some context on what to try.

Appreciate any help, thanks!

@kjy00302
Copy link
Owner

Currently, some parts (e.g. image size) of niimprint is hard-coded to D11-like printers.
D11 prints image vertically, so it automatically rotates landscape image.

I need to fix this (and do documentation!) someday, but I'm busy for personal things.

@rickyelopez
Copy link
Author

rickyelopez commented Jul 17, 2023

Totally understand! I've made a lot more progress and I'm able to get it to print larger sizes now, but I'm struggling to get it to print in landscape.

Do you have any data you could share about how the header in the image packets is calculated? I'm trying to scale it up to work with a full width image (400px wide for this printer, as far as I can tell), but I'm having trouble calculating the header in a way that works.

Far as I can tell so far, the header is 6 bytes where the first two bytes is the line number, the next three bytes are the counts of how many bits are set in that line (where each byte represents the number of bits set for the length of the line divided by 3) and the last byte is always 0x01.

This works fine when I use lines of width 30 (where each of the three bytes represents 10 bytes each), but it doesn't work when I try to scale it up to lines of width 48 (where each byte would represent 16 bytes). Any suggestions?

edit: OK so I actually got the above working, and it's printing nicely! That being said, I don't know how to handle calculating the checksum for a line length that doesn't divide nicely by 3. Any idea how I could do it for, for example, a line length of 50 (400px)?

@CTroncoso11
Copy link

Totally understand! I've made a lot more progress and I'm able to get it to print larger sizes now, but I'm struggling to get it to print in landscape.

Do you have any data you could share about how the header in the image packets is calculated? I'm trying to scale it up to work with a full width image (400px wide for this printer, as far as I can tell), but I'm having trouble calculating the header in a way that works.

Far as I can tell so far, the header is 6 bytes where the first two bytes is the line number, the next three bytes are the counts of how many bits are set in that line (where each byte represents the number of bits set for the length of the line divided by 3) and the last byte is always 0x01.

This works fine when I use lines of width 30 (where each of the three bytes represents 10 bytes each), but it doesn't work when I try to scale it up to lines of width 48 (where each byte would represent 16 bytes). Any suggestions?

edit: OK so I actually got the above working, and it's printing nicely! That being said, I don't know how to handle calculating the checksum for a line length that doesn't divide nicely by 3. Any idea how I could do it for, for example, a line length of 50 (400px)?

I'm working on a React Native implementation based on this repo, can you give an example of your code? I'm going through a similar problem when "transforming" a canvas.

@kjy00302
Copy link
Owner

Could you perform Bluetooth packet capture between B21 and official app? I'd like to analyze, but I don't have any devices other than D11.

@rickyelopez
Copy link
Author

I'm working on a React Native implementation based on this repo, can you give an example of your code? I'm going through a similar problem when "transforming" a canvas.

Sure, what do you want to see?

@rickyelopez
Copy link
Author

Could you perform Bluetooth packet capture between B21 and official app? I'd like to analyze, but I don't have any devices other than D11.

Sure, but I don't know how to do this. Any articles you can point me to?

Anyway, I think I mostly got this figured out. Looks like even the official app can only print as large as 384mm wide, so looks like I'm already at the max.

@kjy00302
Copy link
Owner

Sure, but I don't know how to do this. Any articles you can point me to?

For Android, refer Gadgetbridge's document about BT snoop. Not sure about capturing on IOS

@kjy00302
Copy link
Owner

I bought B21 myself for analyze, and it uses same packet type as D11. Different thing is, D11's pixel count encodes 32 pixels per byte (96 / 3 = 32), but B21 encodes 128 pixels per byte (384 / 3 = 128).

@alexzirnea
Copy link

alexzirnea commented Aug 12, 2023

@kjy00302 What's your experience with aftermarket rolls of paper on B1/B21?
I did a simple experiment with mine. When I bought the printer, I also added a roll of labels in the cart. When I print with the original roll(which has the NFC tag) everything works as expected.
However, when I print with only a piece from the same roll containing a few labels, I had the surprise that the heating intensity drops down to about 50% and it also introduces some artifacts. Just so you buy their label rolls..
I just so hope that this mess is actually caused by their app and not the actual firmware.
Will try your code in the following days and see what's the outcome
LE: Tried the code, it appears that the actual "broken printing" is done in the firmware. It does the same thing with the scripts in this repo (albeit the image is flipped because of how the D1 prints).

@rickyelopez
Copy link
Author

Sure, but I don't know how to do this. Any articles you can point me to?

For Android, refer Gadgetbridge's document about BT snoop. Not sure about capturing on IOS

unfortunately I don't have a rooted phone, and for whatever reason the non-root methods don't work for me. Either way, I see you bought one to see for yourself

I bought B21 myself for analyze, and it uses same packet type as D11. Different thing is, D11's pixel count encodes 32 pixels per byte (96 / 3 = 32), but B21 encodes 128 pixels per byte (384 / 3 = 128).

yeah I ended up figuring this out, was able to get it to print fine using 128 pixels/byte

@alexzirnea I scanned the NFC tag in one of the official rolls with my Flipper Zero and have been emulating it when powering up so that I can use rolls of receipt paper (super cheap) for testing. This has been working great, looks like the B21 only tries to read the NFC tag when powering up or after opening/closing the lid.

@alexzirnea
Copy link

@rickyelopez I wouldn't have worried about the possibility of spoofing the NFC tag. The issue is that some sizes are tied to a specific serial number contained within the NFC tag itself
Last time I scanned the roll with my phone it looked MAC-like.
So there may be two possibilities:

  1. The MCU has some way of decoding the roll (i.e. the first byte is the roll type) and also it stores some unique serial number of the roll internally to decrement some counter and stop you from printing when out of labels.
  2. It is plain dumb and it only looks after specific data to identify the label.

I guess you can inject a "known" roll data and print with it forever and also have custom size labels?
IIRC, I could change the size of the label even though the printer identified it correctly.

@rickyelopez
Copy link
Author

Yeah that's exactly why I did it.

  1. I didn't want it to decrement the counter you mentioned (if it's stored in the tag)
  2. I figured I could buy a couple of different roles and see what changes so that I can write my own tags if I want with specific sizes/types

@alexzirnea
Copy link

I think it is very unlikely that the printer will ever write to the tag itself.
I assume that the tag serial number acts more like a key(I also did a check whether the printer changes it after a print, btw).
What can potentially happen is that the printer stores in some kind of NVM(nothing external of the main MCU, as I disassembled it already :) ) the last let's say 20 inserted rolls and it decrements an internal counter associated to that slot.
The roll I bought is 40x30mm with key 1D:3E:DC:0C:93:00:00. If anyone else has a similar roll, we can confirm/bust whether these have unique IDs.
You can read the roll facing the tag to the back of the phone. I'm using NFC Tools on Android to do that.

@AndBondStyle
Copy link

AndBondStyle commented Aug 16, 2023

I have some wireshark captures of USB communication (basically serial data) with B21. Anyone needs that?
P.S. I'm only starting to look into all of this, so a quick question: does bluetooth use the same commands as the serial (usb)?

@kjy00302
Copy link
Owner

I have some wireshark captures of USB communication (basically serial data) with B21. Anyone needs that? P.S. I'm only starting to look into all of this, so a quick question: does bluetooth use the same commands as the serial (usb)?

I think USB serial uses same protocol as Bluetooth serial. (also refer #8)

@AndBondStyle
Copy link

@kjy00302 cool :)
If you need any help, I'm willing to contribute

@tanenyi
Copy link

tanenyi commented Aug 18, 2023

I think it is very unlikely that the printer will ever write to the tag itself.
I assume that the tag serial number acts more like a key(I also did a check whether the printer changes it after a print, btw).
What can potentially happen is that the printer stores in some kind of NVM(nothing external of the main MCU, as I disassembled it already :) ) the last let's say 20 inserted rolls and it decrements an internal counter associated to that slot.
The roll I bought is 40x30mm with key 1D:3E:DC:0C:93:00:00. If anyone else has a similar roll, we can confirm/bust whether these have unique IDs.
You can read the roll facing the tag to the back of the phone. I'm using NFC Tools on Android to do that.

NFC ID

seems all the IDs have the format 1D:xx:yy:ll:hh:00:00. I assume:

Key Value
xx UUID
yy UUID
ll length (could also include variation metadata)
hh height
ID Length Height Variation
1D:87:8E:47:86:00:00 22mm 14mm Standard
1D:FE:AB:47:86:00:00 22mm 14mm Standard
1D:EF:A2:47:86:00:00 22mm 14mm Standard
1D:95:AB:40:86:00:00 40mm 14mm Sakura
1D:94:A4:40:86:00:00 40mm 14mm Ocean
1D:FC:EA:4C:86:00:00 40mm 14mm Transparent
1D:8C:AF:C8:90:00:00 40mm 30mm Standard
1D:E6:0A:61:82:00:00 40mm 60mm Standard
1D:13:83:61:82:00:00 40mm 60mm Standard
1D:02:AB:61:82:00:00 40mm 60mm Standard

Genuine Check Mechanism

I put 10 new rolls then back to the old roll but it is still faint.

previously when calling the technical hotline, they said they were able to see the number of prints on a roll based on the serial number of my roll. I might take that with a pinch of salt because the number of prints (300 claimed) was way more than the number of labels I had in the roll (240).

either the NVM storage is like you mentioned, 20 rolls or more (definitely above 10), or they are using some other smarts that might involve online DB. that being said, I can't even print a test page clearly even when the device is not connected to the app

@alexzirnea
Copy link

I think it is very unlikely that the printer will ever write to the tag itself.
I assume that the tag serial number acts more like a key(I also did a check whether the printer changes it after a print, btw).
What can potentially happen is that the printer stores in some kind of NVM(nothing external of the main MCU, as I disassembled it already :) ) the last let's say 20 inserted rolls and it decrements an internal counter associated to that slot.
The roll I bought is 40x30mm with key 1D:3E:DC:0C:93:00:00. If anyone else has a similar roll, we can confirm/bust whether these have unique IDs.
You can read the roll facing the tag to the back of the phone. I'm using NFC Tools on Android to do that.

NFC ID

seems all the IDs have the format 1D:xx:yy:ll:hh:00:00. I assume:

Key Value
xx UUID
yy UUID
ll length (could also include variation metadata)
hh height
ID Length Height Variation
1D:87:8E:47:86:00:00 22mm 14mm Standard
1D:FE:AB:47:86:00:00 22mm 14mm Standard
1D:EF:A2:47:86:00:00 22mm 14mm Standard
1D:95:AB:40:86:00:00 40mm 14mm Sakura
1D:94:A4:40:86:00:00 40mm 14mm Ocean
1D:FC:EA:4C:86:00:00 40mm 14mm Transparent
1D:8C:AF:C8:90:00:00 40mm 30mm Standard
1D:E6:0A:61:82:00:00 40mm 60mm Standard
1D:13:83:61:82:00:00 40mm 60mm Standard
1D:02:AB:61:82:00:00 40mm 60mm Standard

Genuine Check Mechanism

I put 10 new rolls then back to the old roll but it is still faint.

previously when calling the technical hotline, they said they were able to see the number of prints on a roll based on the serial number of my roll. I might take that with a pinch of salt because the number of prints (300 claimed) was way more than the number of labels I had in the roll (240).

either the NVM storage is like you mentioned, 20 rolls or more (definitely above 10), or they are using some other smarts that might involve online DB. that being said, I can't even print a test page clearly even when the device is not connected to the app

That is really good info!
A packet dump could very easily spot whether a roll key is uploaded to their cloud when adding a new roll.
(Which I'm almost certainly sure it does, at least for tracking purposes).
Hmm, so you're saying that even with the official roll, you aren't able to print clearly with the scripts in this repo?
I mean, mine worked, but I can't recall if it was connected to the app beforehand.
One thing to try(but this includes disassembling the printer) is to cut off the power. I didn't really properly analyze the circuit whether the MCU has the power completely cut off, but assuming it is a soft power button, some parts of the MCU(including SRAM) might be still getting power. Sort of deep sleep.

@pgodwin
Copy link

pgodwin commented Sep 29, 2023

edit: OK so I actually got the above working, and it's printing nicely! That being said, I don't know how to handle calculating the checksum for a line length that doesn't divide nicely by 3. Any idea how I could do it for, for example, a line length of 50 (400px)?

@rickyelopez Are you able to share your code? The code works with the D110, but I have 15x30mm labels, 120x240 bitmap - but the top is continously cropped off. I suspect its the bit counts but unsure how to approach it.

@rickyelopez
Copy link
Author

edit: OK so I actually got the above working, and it's printing nicely! That being said, I don't know how to handle calculating the checksum for a line length that doesn't divide nicely by 3. Any idea how I could do it for, for example, a line length of 50 (400px)?

@rickyelopez Are you able to share your code? The code works with the D110, but I have 15x30mm labels, 120x240 bitmap - but the top is continously cropped off. I suspect its the bit counts but unsure how to approach it.

Sure, I can push my code to a fork tonight. I didn't clean it up but it should work.

@pgodwin
Copy link

pgodwin commented Oct 2, 2023

Sure, I can push my code to a fork tonight. I didn't clean it up but it should work.

That'd be great. Thank you!

@rickyelopez
Copy link
Author

Sure, I can push my code to a fork tonight. I didn't clean it up but it should work.

That'd be great. Thank you!

https://github.com/kjy00302/niimprint/compare/main...rickyelopez:niimprint:b21?expand=1

Sorry for the mess. I think I had started to try to clean up some of the code but then I got busy with other projects. Anyway, what you're looking for should be in there.

@pgodwin
Copy link

pgodwin commented Oct 9, 2023

Thanks Ricky - much appreciated.

@vasilisvg
Copy link

I tried using the Niimbot B21 with a raspberry pi yesterday. I managed to connect to via bluetooth, but not via USB. But then when I ran the scripts (several forks of them, also the one by @rickyelopez) I get timeouts or host is down messages So I have several questions (-:

  • Did anyone manage to print with it using a Raspberry Pi?
  • If so, did you manage to connect to it via USB?
  • And finally, how do I print with it?

Here are two of the error messages:

pi@pi-imprint:~/niimprint $ python3 niimprint/ -a C2:F6:10:03:06:82 ~/-60-93-98-194-66-56-854-418-11.png
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "/home/pi/niimprint/niimprint/__main__.py", line 47, in <module>
    printer = printerclient.PrinterClient(args.address)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/pi/niimprint/niimprint/printerclient.py", line 36, in __init__
    self._sock.connect((address, 1))
OSError: [Errno 112] Host is down
pi@pi-imprint:~/niimprint $ python3 niimprint/ -a C2:F6:10:03:06:82 ~/-60-93-98-194-66-56-854-418-11.png
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "/home/pi/niimprint/niimprint/__main__.py", line 47, in <module>
    printer = printerclient.PrinterClient(args.address)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/pi/niimprint/niimprint/printerclient.py", line 36, in __init__
    self._sock.connect((address, 1))
TimeoutError: [Errno 110] Connection timed out

The first one is shown when the Pi is connected to the printer via bluetooth, the second one when it isn’t.

And then I have a final question: did anyone manage to turn off the sound? It’s horrible!

@AndBondStyle
Copy link

AndBondStyle commented Oct 29, 2023

@vasilisvg check out my fork. B21 works fine both via bluetooth and usb. I also got "connection timed out" error, I think that's because B21 has two bluetooth addresses and you connected to the wrong one (see notes here).
https://github.com/AndBondStyle/niimprint

P.S. I don't beleive there's a way to disable sound in software. The only way is to take it apart and desolder the beeper.

@rickyelopez
Copy link
Author

@vasilisvg check out my fork. B21 works fine both via bluetooth and usb. I also got "connection timed out" error, I think that's because B21 has two bluetooth addresses and you connected to the wrong one (see notes here). https://github.com/AndBondStyle/niimprint

that's an awesome cleanup, thanks!

@vasilisvg
Copy link

@AndBondStyle That looks fantastic! I’ll probably have some time to play with it later this week. Can’t wait!

@vasilisvg
Copy link

@AndBondStyle I managed to get it to work! Thank you so much!

@deamwork
Copy link

deamwork commented Nov 6, 2023

I think it is very unlikely that the printer will ever write to the tag itself.
I assume that the tag serial number acts more like a key(I also did a check whether the printer changes it after a print, btw).
What can potentially happen is that the printer stores in some kind of NVM(nothing external of the main MCU, as I disassembled it already :) ) the last let's say 20 inserted rolls and it decrements an internal counter associated to that slot.
The roll I bought is 40x30mm with key 1D:3E:DC:0C:93:00:00. If anyone else has a similar roll, we can confirm/bust whether these have unique IDs.
You can read the roll facing the tag to the back of the phone. I'm using NFC Tools on Android to do that.

NFC ID

seems all the IDs have the format 1D:xx:yy:ll:hh:00:00. I assume:
Key Value
xx UUID
yy UUID
ll length (could also include variation metadata)
hh height
ID Length Height Variation
1D:87:8E:47:86:00:00 22mm 14mm Standard
1D:FE:AB:47:86:00:00 22mm 14mm Standard
1D:EF:A2:47:86:00:00 22mm 14mm Standard
1D:95:AB:40:86:00:00 40mm 14mm Sakura
1D:94:A4:40:86:00:00 40mm 14mm Ocean
1D:FC:EA:4C:86:00:00 40mm 14mm Transparent
1D:8C:AF:C8:90:00:00 40mm 30mm Standard
1D:E6:0A:61:82:00:00 40mm 60mm Standard
1D:13:83:61:82:00:00 40mm 60mm Standard
1D:02:AB:61:82:00:00 40mm 60mm Standard

Genuine Check Mechanism

I put 10 new rolls then back to the old roll but it is still faint.
previously when calling the technical hotline, they said they were able to see the number of prints on a roll based on the serial number of my roll. I might take that with a pinch of salt because the number of prints (300 claimed) was way more than the number of labels I had in the roll (240).
either the NVM storage is like you mentioned, 20 rolls or more (definitely above 10), or they are using some other smarts that might involve online DB. that being said, I can't even print a test page clearly even when the device is not connected to the app

That is really good info! A packet dump could very easily spot whether a roll key is uploaded to their cloud when adding a new roll. (Which I'm almost certainly sure it does, at least for tracking purposes). Hmm, so you're saying that even with the official roll, you aren't able to print clearly with the scripts in this repo? I mean, mine worked, but I can't recall if it was connected to the app beforehand. One thing to try(but this includes disassembling the printer) is to cut off the power. I didn't really properly analyze the circuit whether the MCU has the power completely cut off, but assuming it is a soft power button, some parts of the MCU(including SRAM) might be still getting power. Sort of deep sleep.

More genuine label rolls in my hand:

ID Length Height Variation Count App connected?
1D:91:E1:93:92:00:00 25 38 White cable label 200 pcs N
1D:98:36:9A:92:00:00 50 20 Standard 320 pcs N
1D:A9:C6:FD:90:00:00 25 38 Yellow cable label 100 pcs Y

Maybe these will help somehow?

@enzosimon1987
Copy link

1D:A0:70:AC:8E:00:00 50*30 label

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants