instax_api
instax_api copied to clipboard
Instax Mini Link support placeholder
Launched last month, the Instax Mini Link: https://instax.com/mini_link/en/
Same mini film at 800x600 resolution as the SP-2, but prints over Bluetooth instead of wifi, and uses a different Instax Mini Link app.
Oooh, this is basically what I wished the instax was when it first launched! I've not got any reason to buy one for myself sadly, but happy to help support someone else adding it to this library.
At a guess, I would imagine that Fujifilm will have likely used the same communications protocol under the covers, but have switched from WiFi to bluetooth. If this is the case, then it should make it pretty easy to adapt this library to work with it.
Does instax mini link use the same communications protocol as sp-2? If the answer is true, I gonna buy a mini link instead of sp-2.
dmesg:
[27085.469143] usb 3-2.1: USB disconnect, device number 8
[28991.907737] usb 3-2.1: new full-speed USB device number 9 using xhci_hcd
[28992.044195] usb 3-2.1: New USB device found, idVendor=04cb, idProduct=5019, bcdDevice= 2.00
[28992.044200] usb 3-2.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[28992.044202] usb 3-2.1: Product: instax mini Link1
[28992.044205] usb 3-2.1: Manufacturer: FUJIFILM
[28992.044207] usb 3-2.1: SerialNumber: 00000000001A
[28992.100359] cdc_acm 3-2.1:1.0: ttyACM0: USB ACM device`
ok -> CDC ACM (serial port over USB)
Bluetooth find 2 devices:
INSTAX-10669469(ANDROID) typ printer but can not connect
INSTAX-10669469(IOS) typ unkown it is possible to connect
[INSTAX-10669469(IOS)]# info
Device FA:AB:BC:4D:1A:FA (random)
Name: INSTAX-10669469(IOS)
Alias: INSTAX-10669469(IOS)
Paired: yes
Trusted: yes
Blocked: no
Connected: yes
LegacyPairing: no
UUID: Generic Access Profile (00001800-0000-1000-8000-00805f9b34fb)
UUID: Generic Attribute Profile (00001801-0000-1000-8000-00805f9b34fb)
UUID: Device Information (0000180a-0000-1000-8000-00805f9b34fb)
UUID: Vendor specific (0000e0ff-3c17-d293-8e48-14fe2e4da212)
UUID: Vendor specific (70954782-2d83-473d-9e5f-81e1d02d5273)
Modalias: bluetooth:v005Dp0000d0100
ManufacturerData Key: 0x04d8
ManufacturerData Value:
01 00 ..
RSSI: -46
TxPower: 0
Last year, I successfully translate this project to iOS project with swift language. So I purchased a mini link to test. There are three characteristics can read or write 0xFFE1 (Write Notify) 0xFFE9 (Write) 0xFFEA (Notify)
When I tried to sendPrePrintCommand with cmdNumber from 1 to 8, it gets no response at all. So I think they have changed communications protocol.
I suspect that you're right @caichunjian520, the jump to bluetooth would have probably have instigated more changes deeper down the stack too. However, this actually should be pretty easy to reverse engineer compared to the original instax devices. If anyone has an instax mini and an android device, they can enable the Bluetooth HCI snoop log, which I have a feeling will let you log all of your bluetooth traffic and then analyse it in WireShark on your computer (https://support.honeywellaidc.com/s/article/How-to-capture-Bluetooth-traffic-from-and-to-an-Android-Device)
If we could get a complete set of interactions between the android app and the mini this way, we should be able to figure out what's going on.
I'm unlikely to buy another instax printer, but if we can get the wireshark logs uploaded, I'd be happy to go through and see if I can match them to this API.
Hi will try it with my Moto G5 with LineageOS.I find the developer options. Now i have to find the log.
Am Montag, den 28.12.2020, 01:39 -0800 schrieb James Sutton:
I suspect that you're right @caichunjian520, the jump to bluetooth would have probably have instigated more changes deeper down the stack too. However, this actually should be pretty easy to reverse engineer compared to the original instax devices.
If anyone has an instax mini and an android device, they can enable the Bluetooth HCI snoop log, which I have a feeling will let you log all of your bluetooth traffic and then analyse it in WireShark on your computer ( https://support.honeywellaidc.com/s/article/How-to-capture-Bluetooth-traffic-from-and-to-an-Android-Device ) If we could get a complete set of interactions between the android app and the mini this way, we should be able to figure out what's going on. I'm unlikely to buy another instax printer, but if we can get the wireshark logs uploaded, I'd be happy to go through and see if I can match them to this API.
— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.
I just try to get the BLE HCI log file. There are two files when printing a photo with mini link printer. One file with extension .log, another with extension .last
In order to get the smallest data file. I just switch on the HCI log option, select image, and print, then switch off the log option. So it would be quicker to analyse.
I print two photos, each has 2 files. So there are total 4 files to analyse.
Image a https://www.dropbox.com/s/z282i2fbl9ldo7p/btsnoop_hci_image_a.log?dl=0 https://www.dropbox.com/s/22uen29t8s0fhv4/btsnoop_hci.log_image_a.last?dl=0
Image b https://www.dropbox.com/s/2h05637o8nhnime/btsnoop_hci_image_b.log?dl=0 https://www.dropbox.com/s/13qwm7lz2rq85f5/btsnoop_hci.log_image_b.last?dl=0
So, it was not so easy for me. I found it on my G5 with LineageOS here ./data/misc/bluetooth/logs/btsnoop_hci.log I printed one file. + 2. file :-) https://www.dropbox.com/sh/dwe22pvy0gs4zy0/AAD536KOrH6jkHpJj78yMxw3a?dl=0
Please contact me via my email. netzwanze(at)gmx.net
Ok, These logs look perfect!
For reference, I'm viewing them in wireshark with the btspp
filter on as these look like the actual commands / responses between the device and the phone.
![Screenshot 2020-12-31 at 11 22 29](https://user-images.githubusercontent.com/1068763/103408469-824a9d80-4b5a-11eb-854f-a5dd83d8abd1.png)
Some first observations:
- Command Packets start with
0x41 0x62
and Response packets start with0x61 0x42
- The next two bytes appear to be the total length of the packet.
- The final byte is a two's complement checksum - 1 for some reason
I'm starting to write some parsing code for the log files you've provided me with, will update here as I find more 👍🏻
Ok getting a bit further now, here are what I think some of the commands / responses are: (I'm stripping the headers out for the payloads to make things tidier below.
Command Payload | Response Payload | Notes |
---|---|---|
0007 0000 |
0010 0000 0001 0000 0000 0000 00 |
|
0008 0001 00 |
0012 0001 0000 0846 554a 4946 494c 4d |
ASCII for FUJIFILM , byte 6 is string length, 8 |
0008 0001 01 |
000e 0001 0001 0453 502d 34 |
ASCII for SP-4 , byte 6 is length, 8 |
0008 0001 02 |
0012 0001 0002 0831 3034 3538 3634 37 |
ASCII for 10458647 (Serial Number) byte 6 is length, 8 |
0008 0001 03 |
000e 0001 0003 0430 3030 30 |
ASCII for 0000 byte 6 length, 4 |
0008 0001 04 |
000e 0001 0004 0430 3130 32 |
ASCII for 0102 byte 6 length, 4 |
0008 0001 05 |
000e 0001 0005 0431 2e30 30 |
ASCII for 1.00 |
0008 0002 00 |
0013 0002 0000 0258 0320 0200 0002 5800 |
|
0007 2010 |
000a 2010 0000 00 |
|
0009 3002 0203 |
0009 3002 0003 |
|
0137...... |
0008 3001 00 |
This is a big command, not big enough for image data thought |
0008 0002 02 |
0011 0002 0002 2600 000d 0000 0000 |
|
0008 0002 03 |
0011 0002 0003 0000 0004 0000 0001 |
|
0008 0002 01 |
000d 0002 0001 0232 0010 |
|
0007 3000 |
000f 3000 0000 10ff f0fb f000 |
|
038f...... |
000c 1001 0000 0000 02 |
Lots of these, and huge, definitely the image being sent. |
There are a few more, but I'll pause there for now..
This Protocol, definitely seems to be a step-change from the previous one used on the SP-1,2 and 3. Not surprising given the new form factor and communication method (Bluetooth rather than WiFi). From what I've seen already, it would appear that they've had some time to reflect and improve on the old one (always a good thing, but just means a bit more work for us!)
The Plan!
[ ] Create a new mini-link branch [ ] Build out a packet library for the mini link / sp-4 [ ] Build out the test harness and appropriate bluetooth serial code [ ] Test with App & test harness [ ] Flesh out Packet Library [ ] Test with real device [ ] Merge mini-link branch back to master
I can probably get away with doing most of the steps above, and am more than happy to. But will definitely need some help in testing with the real device eventually!
Great. I will test with my mini link.
I have a question. I worked on several BLE projects on iOS as well as Android. All of them need to set notify for listening data change from peripheral device. Or send byte array to characteristic to send data.
Based on the log file. I can't figure out which characteristic I should write data. does it work with RFCOMM protocol?
ASCII for 10458647 (SN? or version?) byte 6 is length, 8
10458647 is my instax mini link serial number string. I think every device is different.
@caichunjian520 Thanks, I've updated the table to confirm that it's the SN In regards to the BLE, I've never worked with it before so I wouldn't know where to start. Once we've got some very basic commands implemented in the packet library we can start trying to work out how to initiate and manage the BLE connection. I believe it is using RFCOMM though as that's what wireshark is telling me...
I have a question. I worked on several BLE projects on iOS as well as Android. All of them need to set notify for listening data change from peripheral device. Or send byte array to characteristic to send data.
Based on the log file. I can't figure out which characteristic I should write data. does it work with RFCOMM protocol?
It's a pretty basic protocol and basically just implements a UART using GATT. The printer advertises a the UART "service" ( "70954782-2d83-473d-9e5f-81e1d02d5273"), which contains a characteristic where the client registers notifications ( "70954784-2d83-473d-9e5f-81e1d02d5273") and another which the client writes to ("70954783-2d83-473d-9e5f-81e1d02d5273"). There are some MTU limitations in BLE, so it seems like there are cases where an entire request/response frame won't always fit in a single GATT write or notification. It seems like the printer and the official client just performs multiple writes/notifications in that case.
I believe Android uses the exact same protocol over RFCOMM instead of BLE. There might be some subtle differences to "reserve" the connection in the BLE case (there is a command that only seems to be used over BLE), but I don't think that is important.
I have played around with one of these printers and made the following observations:
- Requests start with a 2 byte opcode followed by request-specific data.
- Responses start with a 2 byte opcode, a 1 byte result code, followed by response-specific data.
- The first byte in the opcode is a seems to be a command group.
- The image is always(?) transfered as a JPEG.
- Integers are always big endian.
Interesting opcode:
- 0x0001: Query device information such as model number (returns ASCII). Most of this information is available using standard GATT characteristics. The first byte selects the value to query.
- 0x0002: Query device capabilities and state (print resolution, prints left, battery, etc.). The first byte determines which function to query.
- 0x1000: Begin image
- 0x1001: Image data block (32-bit block index followed by data)
- 0x1002: End of image
- 0x1080: Print uploaded image
- 0x3000: Query accelerometer
- 0x3001: Set LED state (it's possible to specify a short animation)
Images are broken into blocks of data and the last block is padded to be the length of a full block. The start command contains the size of the image and the response contains the requested block size.
Just a heads up that Fujifilm has a new partnership with Nintendo and a new app that supports printing Nintendo Switch screenshots, a new colorway of the Mini Link printer (white/red/blue), a Pikachu silicon case, might ultimately drive some additional traffic to this repo: https://instax.com/instaxyourhero/en/
I have this Mini Link because of the new app lol but not the Nintendo version, but maybe reversing the app might show additional information about how it connects and the like.
I will have a look at this later either this week or the next. As I have multiple things on the planning today etc.
recent update to their mini-link app completely destroyed print quality when image resizing is required. I have images to show for comparison, it's absurd. The nintendo app also prints to the mini link and did not get the update.
however, even before the update, the downsizing led to weird but consistent artifacts between prints. I even bought a second printer to verify, and used the mini link app across different versions on different phones to determine the cause.
I'd love to use this repo to print to my mini-link. not very familiar with the hardware side, but can contribute to resizing / compression if using this doesn't already fix the problem of artifacting I am noticing. Please let me know how I might be able to help (happy to do so, especially on the testing side).
did we ever get to the point of actually printing ? I have a bunch of those around :D and would love to thinker (there's also the wide printer which I believe is the same protocol)
Anyone had luck with this?
For some reason I wasn't able to find this repo before. Great to see other users wanting to liberate the Link Mini from its app!
Edit: after reading this thread more thoroughly I see my info was a bit redundant, but I'll leave it up anyway ;)
Below is a small dump of my attempts at reverse engineering this device. I'll be sure to further check everything that has been said in this thread. I wasn't able to get the BLE snoop logs to work on my Pixel 3a, so thanks for your upload @netzwanze! And for the note on USB. Turns out I was using one of those cursed microusb-with-just-power-no-data cables..
My experience with BLE devices is very limited but I've been able to figure out you can indeed register for notifications with 70954784-2d83-473d-9e5f-81e1d02d5273 like @andysan said. After registering I get the following response: b'\x02\t\xf7\x00\x11\x01\x00\x80\x84\x1e\x00'. Not been able to decode this yet (but also didn't really try).
But checking the bt_stack logs on my Android device also seem to suggest it uses rfcomm?
# bt_stack: [INFO:port_api.cc(234)] RFCOMM_CreateConnection: bd_addr=88:b4:36:xx:xx:xx, scn=6, is_server=0, mtu=990, uuid=0x1101, dlci=12, signal_state=0x0b, p_port=0x72a45da9c8
I've been able to open a connection using rfcomm on the commandline, but I don't know how to send my bytearray that way.
I've been going trough the Android code, and from what I can see in the code, at least some of the packets you send to the device are ordered like this:
'Ab' // two bytes, some header
packetsize // two bytes, default is 7
event ID // byte, integer
eventValue // byte, integer
checksum // byte
The checksum is calculated by summing all items and generating a value from 0 to 255 which gets added to the packet as the last byte: return (255 - (sum(bytearray) & 255)) & 255;
Those event ID and value seem to match the ones in this list, but I'm not completely sure if these are things you can send to the device, or types of info you can get back from the device (there are a total of 64 of these):
SUPPORT_FUNCTION_AND_VERSION_INFO(0, 0),
DEVICE_INFO_SERVICE(0, 1),
SUPPORT_FUNCTION_INFO(0, 2),
IDENTIFY_INFORMATION(0, 16),
SHUT_DOWN(1, 0),
RESET(1, 1),
AUTO_SLEEP_SETTINGS(1, 2),
BLE_CONNECT(1, 3),
PRINT_IMAGE_DOWNLOAD_START(16, 0),
Fun fact: running logcat on the Nintendo version of the app (# adb logcat "InstaxApplication:D *:S") returns the x, y and z value of the accelerometer on std.out. Kind of a weird thing for the devs to leave in there.
This is a small bare-bones script that allows you to talk to the printer. It connects to the first Instax-... (IOS)
device it sees, registers to the notify endpoint and sends a packet to the write endpoint. It prints out any response and checks if it contains a valid checksum.
So next step: figure out what to send exactly ;)
import asyncio
from bleak import BleakScanner, BleakClient
from bleak.backends.characteristic import BleakGATTCharacteristic
from struct import pack, unpack_from
writeUUID = '70954783-2d83-473d-9e5f-81e1d02d5273'
notifyUUID = '70954784-2d83-473d-9e5f-81e1d02d5273'
def prettify_bytearray(value):
return ' '.join([f'{x:02x}' for x in value])
def createChecksum(bytearray):
return (255 - (sum(bytearray) & 255)) & 255;
def createPacket(payload):
start = b'\x41\x62' # Ab from client, server responds with Ba
packetSize = pack('>H', 5 + len(payload))
packet = start + packetSize + payload
packet += pack('B', createChecksum(packet))
print(f"Sending packet: {packet}, (length: {len(packet)})")
print(f" {prettify_bytearray(packet)} (length: {len(packet)}")
return packet
def validate_checksum(data):
return (sum(data) & 255) == 255
def notification_handler(characteristic: BleakGATTCharacteristic, packet: bytearray):
if len(packet) < 8:
print(f"Error: response packet size should be >= 8 (was {len(packet)})")
raise
elif not validate_checksum(packet):
print("Checksum validation failed")
raise
data = packet[4:-1] # the packet without header and checksum
print(f'Response data: {data} (length: {len(data)}, checksum OK)')
print(f' {prettify_bytearray(data)}')
async def main():
dev = None
devices = await BleakScanner.discover()
for d in devices:
if d.name.startswith('INSTAX-') and d.name.endswith('(IOS)'):
dev = d
break
if not dev:
print("No printer found")
exit()
print(f'Found instax printer {dev.name} at {dev.address}')
async with BleakClient(dev.address) as client:
print('connected')
await client.start_notify(notifyUUID, notification_handler)
packet = createPacket(b'\x00\x01\x02') # Request serial number
await client.write_gatt_char(writeUUID, packet)
await asyncio.sleep(5.0)
asyncio.run(main())
Hi Javl! Glad to read that you got a connection. It would be a burner to get an image printed over bluetooth at the mini link directly from an own app. Please keep on going!!
Sorry for my poor English and lack of knowledge on bluetooth data.
I just print a photo and get the log
The image data split into 69 blocks, 900 bytes image data each block
41 62 / 03 8F / 10 01 / 00 00 00 n / image block bytes / checksum
0x41, 0x62 header
0x03, 0x8F length
0x10, 0x01 upload image
0x00, 0x00, 0x00, n upload block index, ~the last n range: 0x00 - 0x44~
image block bytes 900 bytes
But there are two questions I don't understand:
- I tried to print two different images, but the first image sent with 69 blocks and the second with 60 blocks.
- If I use 69 blocks, 900 bytes * 69 = 62100 bytes, and 3 bytes per pixel for a color image, so there is only 20700 pixels? But the image should be 600 * 800 * 3 = 1440000 pixels.
- At the final image block (index 0x44), most of the image data is 0x00, which is totally different from previous block.
I'm keeping track of my attempts over at my InstaxBLE repo. It might be nice to integrate it with instax_api at some point but for now I like to be able to store it somewhere.
As a demo the script currently gets the device's serialnumber, and then prints out the accelerometer info, 2 times per second. Events are defined as EventType.<eventname>
for easy access. For example, requesting the serialnumber can be done using:
packet = createPacket(EventType.DEVICE_INFO_SERVICE, b'\x02') # \x02 means serialnumber
await client.write_gatt_char(writeUUID, packet)
Events are listed over here with parsers for each type here. Not the most optimized code, but it's progress ;)
I think I've got it; I wrote a working parser for the logs provided by @netzwanze and @caichunjian520! (the blue blobs are for privacy)
I've also been able to send commands to control the LEDs, so in theory I should be able to combine the two and make an actual print! I hope to be able to check this tonight.
For the LED control the packet turns out to use the following:
- the number of frames in your animation
- the frame duration (higher is a slower animation)
- a RGB color per frame
- when to run (immediately, on print, on print complete or 'pattern switch', not sure what that is)
- how many times to repeat the animation (0 plays once, 1 plays two times (repeats once), etc.. up to 255 which makes it repeat forever.
This is awesome folks! Sorry I've not been more involved, work has been mad and I still don't have a bluetooth version of the printer so can't do much myself at the moment. I need to do some general improvements to the existing library though, so will have a think about how the bluetooth components could be merged in.
I was able to print one of the above photos from my Python code! I didn't manage to print my own image yet; there are still some values I'm not sure about which I need to calculate per image. But very close!