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

My own version: https://github.com/ligius-/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.


21 comments:

  1. Hey Ligius,

    thanks for the teardown. Got myself a Beagle today and am very curious, if there's a way to pass the complicated process to get an ebook file on the device (upload to txtr.com, download on phone, upload to device). My knowledge of this hacking stuff tends to zero but I admire guys like you who try their best to free devices like the Beagle.

    I am looking forward to your next posts regarding this device. Thanks for the effort

    Cheers
    czery

    ReplyDelete
  2. Hi Czery,
    That's my final goal, but until then I'm documenting every step. So the answer is: no, currently not possible.

    ReplyDelete
  3. Hey Czery, Ligius,
    a friend of mine has reverse-engineered the book transfer last weekend.
    He wanted to clean up the code (Python) a little bit before putting it on GitHub over the next days:
    https://github.com/floe

    ReplyDelete
  4. It would be great to know if we could use the Transfer like Serial Console because if it would be true we could build up own Android APP ;)

    ReplyDelete
  5. Yes, transfer works via BT Serial Port Profile using the BOOK, PAGE, ... commands.
    However, images are PGM files with a special zlib compression, so you have to convert them first.
    The code is still very rough, but I guess Florian will put it online soon.
    If you are impatient (or curious): write a small script that poses as a Beagle and let the Android txtr app connect to it - that's (partially) how Florian reverse-engineered the exact protocol.

    ReplyDelete
  6. I'm not getting it completely but http://rpm.txtr.com/ looks like some code for the beagle "txtr a" ?
    Also, why do you have a limit of 15 books? I only have five :-(

    ReplyDelete
  7. Thanks for the comments, I added a final(?) chapter describing how to protocol works.
    Anyone can develop an Android or even Python app to talk to the device and upload the books, but I haven't actually provided any code. It should be a 2 hour job.

    ReplyDelete
  8. I didn't really clean anything up, but here's my code on github: https://github.com/floe/opentxtr

    I've also written a short blog post about it: http://floe.butterbrot.org/matrix/hacking/txtr/

    Thanks for sharing!

    ReplyDelete
  9. I've written a Java application that allows to manage ebooks on the beagle (list and delete books, upload PDFs as new books).

    The code is available on github:
    https://github.com/schierla/jbeagle

    ReplyDelete
    Replies
    1. Your piece of software seems absolutely fantastic. Call me stupid, but I couldn't for the life of me, figure out how to pair the beagle with a pc. I never got past, the "please return to the txtr beagle app to finish pairing" screen. Do you have any tips on that. With that of course Jbeagle just says "searching for begale" (This is on windows by the way).

      Delete
    2. Windows 8.1 or 10? Click start, type 'add device', select 'add or remove devices', select the Bluetooth section. Now keep pressed on the power button of the Beagle until it starts flashing blue, it should be in pairing mode. It should afterwards appear in the Windows dialog.
      For more control over PDF rendering check out my fork of the project https://github.com/ligius-/jbeagle

      Delete
    3. Thanks for replying.

      Problem is, that when I put my beagle into pairing mode, when connected to a PC it will just say, "Pairing successful, please return to the txtr app". If I launch JBeagle in this state, it will just say "searching for beagle", and than the beagle will give a timeout message after a while, but JBeagle fail to find it. I can connect the beagle to and android device through to -soon to be shut down but still operating- official app, and then it will say "Waiting for books", when in bluetooth mode, and like that I can even transfer a book. I have Win10 on my main pc, but if needed I have a Pc in the house With Win8.1 (On that it does the same thing BTW), and WinXP if that helps. Also in bluetooth settings its says that if for example the beagle is on COM port N than the "beagle spp dev" is on COM N-1. (I don't know if that is supposed to be like that or not). So if you have any idea what I am doing wrong, please hit me with t :D

      Delete
    4. This comment has been removed by the author.

      Delete
    5. Here's what I did, step by step, Win10:

      - start the beagle (pwr btn), keep pressed pwr to get into the pairing mode (blue led flashing)

      - keep pressed left and right arrows to reset the device (this will remove all books and settings!)

      - disabled and re-enabled the bluetooth adapter in device manager as it was acting up on my pc

      - started beagle, put it into pairing mode

      - started the pc discovery (add bluetooth device), found the beagle, got a confirmation code, accepted that

      - started the jBeagle application, the top status bar should display 'Searching for beagle...' and then shortly 'retrieving books' and then 'done'.

      - press browse to select a file (from my app, link above, go to releases)

      - press upload

      Delete
    6. Well I did just that, 3 times, just to make sure, I also removed th batteries in the beagle and restarted, the computer just to make absolutely sure, But I am stuck at the "Searching for beagle screen" . Tried it with the win8 pc --->same. Also I got the compiled java package to rule out the problem with eclipse, but no change. By the way my beagle is a Hungarian language model... Does that make a difference? Also, is there a way for me to tell, where the process gets stuck? Also as I stated before the begale gets stuck on screen that says "Bluetooth pairing successful. Please return to the txt app to continue pairing... So at the moment I am completely stumped...

      Delete
    7. I have the German model, though it should not be any difference. As soon as the device is paired in Windows the Bluecove library should take care of connecting to it.
      If you have some knowledge of Java, start the app in Debug mode, set a breakpoint in BeagleUtil.java:53 and try to step over the code. See if it throws any exceptions there. I'll be happy to assist.

      Delete
    8. Sadly I know nothing about java, but I have seen other programming languages (c# and visual basic), so at least I have a basic idea :D. Very nice from the original programmer to comment to every subroutine what it does. So I found the bit where it searches for the beagle


      beagle = BeagleUtil.searchForBeagle();

      This is the line it gets stuck on. It does not even exit with an exeption, it just stays there. I guess BeagleUtil.searchForBeagle(); is a subroutine defined somewhere else. How can I find where that is?

      Delete
    9. Press F3 to go to that function. Press F5 to step into it. Press F6 to step over functions. Select a text and press Ctrl+Shift+i to see an evaluation of that expression. F8 to resume running. By stepping over stuff you are able to see if something throws an exception (jumps to the catch block) and see what the exception is. I would have modified the code to show the exceptions in the console, but have not bothered to do that.

      Delete
    10. This comment has been removed by the author.

      Delete
    11. Just enter this chat room: http://www.chatzy.com/55869808451853 and we can work from there, it's getting too detailed to have a meaningful conversation here.

      Delete
    12. I've made a new release a few days ago on my Github project that addresses that issue - the Hungarian version of Beagle is shown as 'txtr beagle' instead of 'Beagle'. A nicer way to do that would be to have a list of BT devices from which to choose. Next release maybe... Also included are some small features and fixes (reconnection, keep-alive ping)

      Delete