Thursday, July 18, 2013

txtr Beagle - Part two - software

Bluetooth


Thanks to Moritz I was able to connect to txtr via the Bluetooth SPP profile. To do this you need to disable the txtr app that is installed on your phone and install any app that does Bluetooth serial debugging. I used "Bluetooth SPP", available freely on the Play Store.

UPDATE: Andreas Schier has written an open-source java toolchain for Beagle: https://github.com/schierla/jbeagle


UPDATE: Florian Echtler has built two Python scripts, one emulating the server and another one for the client. The server allows you to send images to your reader: http://floe.butterbrot.org/matrix/hacking/txtr/

Turn on Bluetooth on the phone and Beagle, start the app and choose "Real-time mode". Inside the prompt you should type "HELP" (all caps) followed by the enter key (not "Done") so a newline is inserted after the command. You should see a listing of available commands.
Here's the [obscured] output from my device:

Connecting…
Bluetooth connect OK.

Bluetooth Protocol v8

Accepted commands:

(GET)PARTNER, GETBOOKS, (DELETE)BOOK, QUIT, MEMORY, INFO, HELP, etc.

 Issuing the INFO command:
PROTOCOL VERSION=8
FIRMWARE ID=Beagle-F-U BUILDDATE=18.April.2013 GIT=cxxxxxx IAP=0 BLUETOOTH=u.3

DEVICE SERIAL=8888888 BDADDR=00:xx:xx:xx:xx:xx DISPLAY=V110

# bookselect button activated

VCOM VALUE=1910

SDCONTENT REVISION=2

OPTION LOWFLASH=0 FFTBT=1
INFOOK

 Issuing GETBOOKS:
BOOK ID=1111111111111111 FIRSTPAGE=1 LASTPAGE=19 CURRENTPAGE=19 AUTHOR=sgsdfgsdfgdgsd TITLE=sdfgsdfgsdfgsdfg
BOOK ID=888888888888888 FIRSTPAGE=1 LASTPAGE=183 CURRENTPAGE=5 AUTHOR=adfrgsdfgsdfgsdfgsdfgsdfg TITLE=sdfgsdfgsdfgsdfgsdfg

BOOK ID=888888888888 FIRSTPAGE=1 LASTPAGE=423 CURRENTPAGE=1 AUTHOR=TG9uZG9uLCBKYWNr TITLE=V2hpdGUgRmFuZw

BOOK ID=888888888888888 FIRSTPAGE=1 LASTPAGE=447 CURRENTPAGE=321 AUTHOR=sdfgsdfgsdfgsdfg TITLE=sdfgsdfgsdfgsdfg

GETBOOKSOK


 Issuing MEMORY:
BOOKS USE=4 MAXIMUM=15
CLUSTERS USE=21 MAXIMUM=255 SIZE=59

MEM TOTAL=8192 FREE=2168

MEMORYOK

 QUIT:
QUITOK
Partner:
PARTNER ID=B234E345D123



Not much to see here but I assume the BOOK command signals the device that an upload is about to start. I was initially considering the fact that a different Bluetooth channel (binary) was used for the transfer but giving how much time it takes to actually transfer a book they might actually be using the same (Serial) channel.



Android


The apk and application storage were retrieved from the device using TitaniumBackup.

Storage


The storage archive contains the following data:
- fonts
- hyphenation dictionaries (de, en, es, fr, it, pt)
- some web tracking databases (cache and cookies), Google analytics client id
- Adobe Digital Edition - activation xml; I assume this is some fingerprint used to register the pdf parser with Adobe (http://adeactivate.adobe.com/adept)
- fingerprint id - either for the phone or the Beagle, not sure
- adobe DRM registration id - xml
- authenti[fi]cation xml containing user and token, in my case Facebook
- billing info xml
- preferences xml - for the app

App


The apk was unpacked and the .dex file was passed to the dex2jar utility. Jd-gui was used to browse and dump the decompiled source code. I will not post any code dump since it's probably illegal.


However, it's probably no problem to post the package structure and figure out what might be happening.

There's the Google analytics package there but I've seen that in almost every Android app.

Facebook is there for login.

http://actionbarsherlock.com/

GMS is play services SDK.

The sonyericsson package implements a humanized version of touch zooming, I haven't studied that yet.

https://github.com/akquinet/androlog
https://github.com/akquinet/roboject

And a bunch of other stuff, but it's interesting to note the renderer service has only two renderers: EPUB and PDF.

































Jumping over some details, it seems that the books are rendered on the Android device inside a Bitmap object http://developer.android.com/reference/android/graphics/Bitmap.html
The settings flag is Bitmap.Config.ARGB_8888, which means each pixel is stored on 4 bytes.
For grayscale conversion a new bitmap is created and receives a color matrix filter with saturation set to zero. For raw retrieval, the getPixels () method is called with the parameters (int[480000], 0, 600, 0, 0, 600, 800).
public void getPixels (int[] pixels, int offset, int stride, int x, int y, int width, int height)
Added in API level 1
Returns in pixels[] a copy of the data in the bitmap. Each value is a packed int representing a Color. The stride parameter allows the caller to allow for gaps in the returned pixels array between rows. For normal packed results, just pass width for the stride value. The returned colors are non-premultiplied ARGB values.
Parameters







pixels The array to receive the bitmap's colors
offset The first index to write into pixels[]
stride The number of entries in pixels[] to skip between rows (must be >= bitmap's width). Can be negative.
x The x coordinate of the first pixel to read from the bitmap
y The y coordinate of the first pixel to read from the bitmap
width The number of pixels to read from each row
height The number of rows to read
Throws


IllegalArgumentException if x, y, width, height exceed the bounds of the bitmap, or if abs(stride) < width.
ArrayIndexOutOfBoundsException if the pixels array is too small to receive the specified number of pixels.
There are a few native methods stored in librenderer.so (5 MBytes!) most notably getCurrentScreenBuffer() which does not return anything.

Transferring

The main actions are stored in BeagleDevice.class, showing some more commands than what HELP listed:
  •  DELETEBOOK ID=[id]
  •  VIRGIN
  •  ENDBOOK
  •  PAGE [pagenum] - also passes a byte[] array, used for uploading
  •  UTILITYPAGE [pagenum] - with byte[] parameter
  •  OPTION LOWFLASH=[num]
  •  VCOM [num]
  •  BOOK ID=[num]
  •  TITLE [string]
  •  AUTHOR [string]
I'll go over some details in a next post, for now what's interesting is the transfer payload type. It's a compressed byte[] array retrieved by calling convertToZipped4bpp(int[], 600, 800, 16, false) native method.
The 4-bit format is called 3BIT+DITHER.


3 comments:

  1. This comment has been removed by a blog administrator.

    ReplyDelete
  2. It's hard to come by experienced people on txtr Beagle. Thank you for sharing Liguis.
    Check this out too:
    Medical Records Software

    ReplyDelete
  3. I simply want to tell you that I am new to weblog and definitely liked this blog site. Very likely I’m going to bookmark your blog . You absolutely have wonderful stories. Cheers for sharing with us your blog.
    VLC Media Player

    ReplyDelete