Tuesday, September 10, 2013

Kindle digital photo frame part 5: testing and finalizing

The scripting and programming is mostly complete. Time to test the Kindle. For the purpose of testing, I set the Kindle to change screensavers every 5 minutes instead of every 3 hours. It works flawlessly for hours at a time, then fails. It always fails in the same way: displaying no picture in screensaver mode. Even manually pressing the button power twice does not solve it. Perhaps the Blanket program crashed or something, I don't know, but it fixes itself after a restart.

After hours of debugging I still cannot figure out what the problem is. Decided to call it quits, but added a recovery option should that happen. I installed KUAL and kterm, so that after a reboot I can manually run my screensaver changing script again.

Finally, I decided to consolidate both the script to change screensavers and that to download images. Here's the final masterpiece:

I've reset the screensavers to change every 3 hours instead of 5 minutes. It'll still be a few days before I present this to my girlfriend, a final few days to test and make sure it works perfect!

Kindle digital photo frame part 4: downloading pictures from the net + more screensaver problems

Even more problems came to bite me. I had intended to use wget with some options like -r to easily download all the images that I have listed on the front page of my CakePHP backend. However, Kindle's busybox wget is quite primitive; it does not have so many options, and I am forced to perform grep, awk and a lot more scripting to download the pictures that I uploaded. Here's the code:

In addition, Kindle renames screensavers after restart. All the photos inside the screensavers folder will be renamed to bg_xsmall_ssXX.png. That implies that a maximum of 100 photos are allowed. In addition, if the order of the photos is to be randomized via creating a file called "random", all the photos' filenames will be randomized again upon bootup, meaning I won't be able to tell if /var/local/blanket/screensaver/last_ss points to a photo or downloaded image.

In view of these, I decided to rotate the photos myself by placing one 1 photo inside the screensavers directory: bg_small_ss00.png, and replace that file everytime I change my screensaver. As usual, Busybox is so limited in functionality that I have to go through massive scripting just to choose a random photo or determine a random number. This is my updated screensaver-changing script:

Monday, September 9, 2013

MK 809 III Android mini PC

The MK 809 looks like an oversized thumb drive that plugs into a HDMI port, but it is a full fledged android pc. I was quite excited when I saw it on sale on Qoo10; I've been wanting a powerful arm computer to test BOINC on, and the MK 809 III has 4 cores, fits into my palm and uses a phone charger. Sweet!

I'm more bitter about the price though. The Qoo10 seller was selling at S$96 including shipping fees. That's out of my budget. Decided to source upstream, and found it alibaba.com, selling for US$45 a piece. However, there is a minimum order of 10. Thus finally, I went to it's sister site, aliexpress, and found one selling at US$57. Perfect!

I wonder if an Android OS can be used for programming?

Would update when the item arrives.

Final Fantasy Fables: Chocobo's Dungeon

Just cleared the 100 levels dungeon in Chopin's dungeon for the Wii. I killed the boss at level 71, and was level 8 dragoon wearing a genji's  talon+79 and king's saddle+57 when I did it. All I did was spam Holy Lance and Gungnir, drink ethers like crazy, and ate just one Phoenix down when near death.

Phew, that was fast!

Sunday, September 8, 2013

Kindle digital photo frame part 3: Changing screensavers every 3 hours

Getting the Kindle to change its screensaver is as simple as running /usr/bin/powerd_test -p twice. The script to do so:

I wanted the screensaver to be changed every 3 hours, excluding nighttime. It's a matter of appending to /etc/crontab/root:

Then I ran into a pesky problem. The screensaver changer works if I ran it manually. It doesn't work via the cron job. Or rather, I discovered that the Kindle goes to sleep after 1 minute in screensaver mode.

After fiddling with /usr/bin/powerd_test -s for quite some time I discovered the following. The Kindle has 4 power levels: Active, Screen Saver, Ready to suspend, and sleep. Active stays on for 10 minutes, Screen Saver stays on for 1 minute, and Ready to suspend stays on for 5 seconds. This is my log:

I can wake up my Kindle via the command "lipc-set-prop com.lab126.powerd wakeUp 1" provided it is in one of those 3 states. To try and suspend my Kindle in the "ScreenSaver" or "Ready to suspend" state for as long as possible, I investigated the seemingly useless property, deferSuspend, from com.lab126.powerd. When you run it, it gives the error:

com.lab126.powerd failed to set value for property deferSuspend (0x8 lipcErrNoSuchProperty)

I discovered that the property can only be set DURING THE READY TO SUSPEND STATE. That means after 11 minutes of leaving the Kindle alone I have a 5 second window to change the time left in "Ready to Suspend" state. See my logs:

My screensaver changing script ended up as:

Digital photo frame: Kindle Touch vs Kindle Keyboard

In the midst of hacking my newly acquired Kindle keyboard I got myself another Kindle: this time a Kindle Touch 3G. I intended to use one as the photo frame and another as my ebook reader.

Now, which to use for my digital photo frame?

The Touch, being slimmer without a keyboard, would be easier to conceal within a frame. Not to mention that my Keyboard came with a leather case and I like it a lot. The Touch seems like a natural choice.

Until I got down to hacking it. After the usual jailbreaking and stuff, I found out that the Touch only supports PNG. This, while my Kindle keyboard can support jpg, gif and images of all shapes and sizes. Ended up using the Kindle Touch anyway.

Kindle digital photo frame part 2

Now that I can SSH into the Kindle I need to figure out the functions that I need. I want the Kindle to cycle through me and my gf's photos every 3 hours. Apart from that, I want to be able to upload photos of cute cats or love messages onto the internet, and those will show up, ONLY ONCE, on the Kindle.

For cycling photos, I need to:
  1. Wake up the Kindle from sleeping
  2. Put it to sleep again.

(1) is easy to find. The command, lipc-set-prop com.lab126.powerd wakeUp 1, will wake up the Kindle. (http://www.mobileread.com/. forums/archive/index.php/t-160328.html) Fortunately, cron works even when the Kindle is sleeping, so cycling photos is definitely possible.

(2) took me a while to find. The command is, /usr/bin/powerd_test -p . (http://www.mobileread.com/forums/showthread.php?t=220810) It works for waking up the Kindle as well, so now I can simply cycle my photos by running this command twice!

For displaying my uploaded pictures, I need to:
  1. Setup a server backend for uploading images
  2. Periodically downloading them into the Kindle
  3. Display the images occasionally, deleting them after they've been displayed.

For (1), I can simply use OpenShift and CakePHP to setup a backend for uploading and storing images. I've familiarized myself with that setup thanks to a previous competition, so no worries here.

(2), I can simply write a script for downloading the images from my backend and add it to crontab. I can even turn on wireless using cron, no issues here.

(3), I had no idea to detect which image is being displayed on screen. Thankfully, I found this page https://github.com/yifanlu/OpenBlanket/blob/master/screensaver.c, line 363 of the code shows that the last screensaver displayed is stored at "/var/local/blanket/screensaver/last_ss". I can use this while waking up the Kindle, to delete the images shown before.

Stay tuned to the next part!

Kindle digital photo frame part 1

Weeks ago I found out that my girlfriend would look at our pictures to relax herself when she is bored/stressed. I had the idea of putting a digital photo frame at her desk at work, that would cycle through our photos on a regular basis. She would be so delighted.

So I went to search for some digital photo frames on Qoo10.sg. Lots of choices, but there's a major problem. They're all using LED/LCD screens. This means: either they have an annoyingly short battery life (this item - 4 to 5 hours only?! Seriously?) or AC adaptor cables. I want a frame that is portable, not entangled by wires, and have a battery life counted in weeks, not hours.

So, the Kindle suits my purposes well. It does not consume power when displaying pictures, only when changing them. Suppose I change the images only once per hour... how much power can I save? The Kindle will last weeks!

I was lucky enough to find a seller on Hardwarezone selling his old Kindle keyboard WiFi at $70. He posted his offer just 3 hours before I saw it. And, coincidentally, he was visiting my office on the next day. I don't even need to arrange a pickup point! ^^

The next part: hacking the kindle. I followed a series of guides:

  1. http://anoved.net/2012/02/custom-kindle-screensaver-images-with-kite/ to enable custom screensavers.
  2. http://speely.wordpress.com/tag/3-4/ to enable ssh, and used this to figure out the root password
More to come!

Kindle lipc property list

=~=~=~=~=~=~=~=~=~=~=~= PuTTY log 2013.08.30 15:54:14 =~=~=~=~=~=~=~=~=~=~=~=
login as: root


Welcome to Kindle!

root@192.168.43.115's password: 
#################################################
#  N O T I C E  *  N O T I C E  *  N O T I C E  # 
#################################################
Rootfs is mounted read-only. Invoke mntroot rw to
switch back to a writable rootfs.
#################################################
[root@kindle root]# k   lipc-probe -a -v
com.lab126.pmond
 r  Str summary [name[pid] - state - mem_limit - mem_curr
----------------------------------------
tmd[13086] - started - 9000 - 2728
mcsd[13088] - started - 5000 - 1180
syslog[964] - started - 5000 - 808
netwatchd[0] - stopped - 5000 - 0
phd[13090] - started - 5000 - 2800
cvm[14228] - started - 103424 - 68272
wifid[13272] - started - 5000 - 3468
browserd[14055] - started - 90000 - 8408
webreader[14013] - started - 80000 - 15668
audioserver[15975] - started - 50000 - 4144
ttsd[13790] - started - 150000 - 6388
powerd[13143] - started - 5000 - 1456
volumd[13095] - started - 5000 - 1348
wand[0] - stopped - 5000 - 0
cmd[13267] - started - 5000 - 1516
]
 w Str start
 w Str restart
 w Str stop
 rw Str logMask [0xffff0000]
 w Str kill
 w Str heartbeat_start
 w Str mem_limit
 rw Str logLevel [Current log level=info
(Possible levels: all, perf, debug[9-0], info, warn, error, crit, none)]
 w Str heartbeat_stop
com.lab126.audio
 rw  Str URI []
 w Str PlayerStop
 rw Int Control [0]
 rw Int GstrLatency [10000]
 r Int ManagerInitialize [1]
 rw Str logLevel [Current log level=none
(Possible levels: all, perf, debug[9-0], info, warn, error, crit, none)]
 rw Int CmdIVolume [14]
 r Int CmdISpeakerMax [15]
 w Str SendEvent
 w Int ThreadUp
 rw Str logMask [0x00000000]
 w Str PlayerDataReady
 w Str PlayerRelease
 r Int ManagerCleanup [1]
 w Str PlayerResume
WARNING: Failed to get value of Seek <0x213>
 rw Int Seek
 w Str PlayerCreate
 w Str PlayerPrefetch
 r Int CmdINSinks [2]
 rw Int Chapter [0]
WARNING: Failed to get value of ManagerSuspend <0xf>
 r Int ManagerSuspend
 w Str PlayerLoop
 w Str PlayerSeek
 w Str PlayerPause
 r Int CmdICurrentMax [15]
 w Str PlayerSuspend
 w Int ResetVolume
 rw Int GstrBufferTime [200000]
 w Str PlayerStart
 r Int ManagerShutdown [-4]
 w Int Kill
 rw Int Volume [70]
 r Int ManagerResume [1]
com.lab126.ttsd
 rw  Has enqueueSnippet [*NOT SHOWN*]
 w Int unpause2
 w Int cancelSnippetPlayback
 rw Has playSnippetNow [*NOT SHOWN*]
 w Int pause2
com.lab126.tts
 rw  Str TtsSVoice [Tom]
 w Int CtrlBookmark
 rw Has playFile [*NOT SHOWN*]
 rw Int TextToProcess [10]
 w Int stop
 rw Str logMask [0xffff0000]
 w Int pause
 rw Str logLevel [Current log level=info
(Possible levels: all, perf, debug[9-0], info, warn, error, crit, none)]
 w Int unpause
 rw Str TtsSModel [full_155mrf22]
 rw Int TtsISpeed [100]
com.lab126.powerd
 w  Int addSuspendLevels
 r Str status [Powerd state: Active
Remaining time in this state: 308.400766
defer_suspend:0
suspend_grace:0
prevent_screen_saver:0
drive_mode:off
Battery Level: 97%
Last batt event at: 97%
Charging: No
batt_full=1
Battery logging: On
]
 w Int wakeUp
 rw Int preventScreenSaver [0]
 rw Str logMask [0xffff0000]
 w Int suspendGrace
 w Int deferSuspend
 rw Str logLevel [Current log level=info
(Possible levels: all, perf, debug[9-0], info, warn, error, crit, none)]
 w Int touchScreenSaverTimeout
 r Str state [active]
 w Int abortSuspend
 r Int isCharging [0]
 r Int battLevel [97]
 w Int rtcWakeup
com.lab126.system
 w  Str date
 r Str version [System Software Version: 040-S4_luigi-172597 Sat Sep 1 14:29:41 PDT 2012]
 r Str boardid []
 r Str waveformversion [V220_C024_60_WJ7501_D (M24, S/N 1301, 85Hz)]
 r Str usid [B008A0A004357F9E]
 r Str orientation []
 w Str sendEvent
com.lab126.wifid
 rw  Has createProfile [*NOT SHOWN*]
 r Str signalStrength [5/5
]
 rw Has cmNWProperties [*NOT SHOWN*]
 rw Has netConfig [*NOT SHOWN*]
 r Str manufacturerCode [53GRADB9SMRC2WEX5DF4]
 rw Has profileData [*NOT SHOWN*]
 r Str feelingLuckyProfile [CBTL]
 w Str cmDisconnect
 rw Has currentEssid [*NOT SHOWN*]
 r Str 711 [********* 1- Connection *********
1.1 MAC: 28:EF:01:A8:69:3B
1.2 Wireless: On(1)
1.3 AP: A (02:08:22:d2:18:87)
1.3.1   Signal strength: 5/5
1.3.2   Captive: no
1.3.3   Security: WPA2-PSK
1.3.4   Channel: 1
1.6 Country: CN

********* 2- Wireless Configuration *********
2.1   A 0 [WPA2-PSK][CCMP] (6) 

********* 3- Interface Configuration *********
3.1 IP Address: 192.168.43.115
3.2 Netmask   : 255.255.255.0
3.3 Broadcast : 192.168.43.255
3.4 Gateway   : 192.168.43.1
3.5 Config    : DHCP
3.6 DNS       : 192.168.43.1, 
3.7 Sponsored    : no

********* 4- Last DHCP Session *********
Sending discover...
Offer from server xxx.xxx.43.1 received
Sending select for xxx.xxx.43.115...
Lease of xxx.xxx.43.115 obtained, lease time 43200

5 Device Time: Fri Aug 30 07:54:38 2013

]
 r Int profileCount [2]
 w Str cmConnMode
 r Str cmState [CONNECTED]
 w Str scan
 rw Str logMask [0xffff0000]
 rw Has createNetConfig [*NOT SHOWN*]
 w Str cmCheckConnection
 r Str cmProfile [A]
 r Int cmIntfInUse [1]
 rw Int enable [1]
 r Str macAddress [28:EF:01:A8:69:3B]
 rw Str logLevel [Current log level=info
(Possible levels: all, perf, debug[9-0], info, warn, error, crit, none)]
 w Str deleteProfile
 r Str scanState [idle]
 w Str cmConnect
 rw Has scanList [*NOT SHOWN*]
 rw Has cmIntfInfo [*NOT SHOWN*]
 r Str macSecret [53GRADB9SMRC2WEX5DF4]
com.lab126.framework
 rw  Has transfer_status [*NOT SHOWN*]
 w Int insertKeystroke
 r Str xfsn [ELVvgP9mY0kDCu9gkeNQNYZqmnIHyNbJ9uP9xltY1/eJ3IvONcTj3bGDy7UE1w4Wb2yV3F0K9J4IFWBv9D8tGJXYHZgXqF5gXJG8eYsgooKWWH5iaa3vADv04BEdO29ecIIPVfUVejk=]
 rw Str logMask [crit | error | warn | info | event | perf | test | journal | debug0 | debug1 | debug2 | debug3 | debug4 | debug5 | debug6 | debug7 | debug8 | debug9 (0xffffff0)]
 w Int logContent
 rw Str logLevel [debug9]
 r Int wirelessSwitch [1]
 w Int read
 r Int isRegistered [0]
 r Int wanSwitch [1]
 w Int dismissDialog
com.lab126.transfer
 rw  Has dump_queues [*NOT SHOWN*]
 rw Has modify [*NOT SHOWN*]
 rw Has get_info [*NOT SHOWN*]
 rw Has request_upload [*NOT SHOWN*]
 rw Has dequeue [*NOT SHOWN*]
 rw Str logMask [0xffff0000]
 rw Str logLevel [Current log level=info
(Possible levels: all, perf, debug[9-0], info, warn, error, crit, none)]
 rw Has send_status [*NOT SHOWN*]
 rw Has request_download [*NOT SHOWN*]
 rw Has obliterate [*NOT SHOWN*]
com.lab126.phd
 w  Str newSPHSchedule
 rw Str logMask [0xffff0000]
 rw Str logLevel [Current log level=info
(Possible levels: all, perf, debug[9-0], info, warn, error, crit, none)]
com.lab126.volumd
 r  Int mmcIsAvailable [0]
 r Int userstoreFreeSpace [3127952]
 r Int driveModeState [0]
 r Int mmcFreeSpace [-1]
 rw Int useUsbForSerial [0]
 w Int userstoreReadyToUnMount
 rw Str logMask [0xffff0000]
 r Int mmcTotalSpace [-1]
 rw Int useUsbForNetwork [0]
 r Int userstoreTotalSpace [3201936]
 rw Str logLevel [Current log level=info
(Possible levels: all, perf, debug[9-0], info, warn, error, crit, none)]
 r Int userstoreIsAvailable [1]
com.lab126.webreaderListener
com.lab126.cmd
 r  Str activeInterface [wifi]
 w Str ensureConnection
 rw Str logMask [0xffff0000]
 rw Str logLevel [Current log level=info
(Possible levels: all, perf, debug[9-0], info, warn, error, crit, none)]
 rw Has availableInterfaces [*NOT SHOWN*]
 rw Has interfaceProperties [*NOT SHOWN*]
com.lab126.cvm
 rw  Str logMask [0xffff0000]
 rw Str logLevel [Current log level=info
(Possible levels: all, perf, debug[9-0], info, warn, error, crit, none)]
com.lab126.mcsd
 w  Int performScan
 w Int selectAutomaticMode
 r Int getManagementState [0]
 w Int enableManagementState
 w Int requestCurrentState
 w Int abortScan
 w Str selectNetwork
[root@kindle root]# exit

Monday, July 15, 2013

Codechef July 2013 Prob: the ultimate troll question

First, I had no idea how to solve this at all. There is no way to brute force it for such extremely large numbers.

Then, I saw this comment:
I was trolled by this question in two phases : First after solving for two hours I was like "oh man, awesome question. So one part of the question remains" then after 5 hours of PnC and probability, when I saw it I was like "mother of all trolls" serious mindfuck question.
I knew there had to be a shortcut somewhere. Hence, I worked out the first sample test case for t4=1. Yielded the result of 0.5. Could it be that the output is the same regardless of how many tickets Chef discards?

Investigating further, I made a program that calculates the probability of every single combination, a.k.a brute forcing the solution. Code here. Of course, I would only load the program with small inputs. The result:

Input:


Output:


I found the shortcut! Indeed, the probability is the same regardless of how many tickets Chef discarded. Happily discarded T4 from my program, submitted it, only to get a runtime error. Turns out my stack has run out of space due to too many recursive calls from T3. Hmm, I thought, I could make the calculation non-recursive, but it is still up to 1000000000 calculations for a single test. Another shortcut must exist!

Went back to the question to look for more patterns. Discovered than 0.5 = 2/(2+2) for first sample test case, and 0.4 = 2/(2+3) for second test case. T3 is also not needed!

Submitted a program consisting of just these few lines:



ANDDDDDDDDDDDDDDDDD


Ultimate troll question.



Codechef July 2013 Galactik

First, to find out where to build the bridges, I had to find out what islands/isolated pockets of planets are there. This can be done by a connected components algorithm, simple enough.

Next step, to choose which islands to build the teleporters on....I had no idea. Dug through the comments on the question page for hints. I found this big one:
Can GFA create more than one teleport on a planet?
Please specify if GFA can construct more than one teleport ending on a planet.
@zwolf10003 ,@qwaker00: yes.

Hence, I could just build one end of all teleporters on the same planet. And of course, that planet would offer the cheapest rate in the galaxy for building one!

The other end would go to each individual island/component. And for each island, the best place to end the teleporter would be the cheapest planet in the island.

With the solution planned out I proceeded to code it out in Python. Code here. Worked perfectly, but when submitted:


Sigh.

Time for port over to C++ again. But before that, I made a search for the fastest I/O operation I can achieve on C++. I landed upon this blog post. Tried the last method, but found that Windows does not have getchar_unlocked(). Replaced it with getchar() instead.

The result:


It's accepted!


Tuesday, July 2, 2013

Codechef Jun 2013 Collect

Coded first in Python, time limit exceeded.

Then ported over to C++, time limited exceeded again.

Reviewed the editorial, added segment trees to facilitate range querying, but still exceeded time limit!

=_=U

Thursday, June 27, 2013

Win32 no more flicker

Thanks to this blog, solved that flicker problem by:

  1. Painting to a back buffer instead of directly to screen
  2. Overriding WM_ERASEBKGND with "return true" so that it doesn't erase the background every second/every time the screen is invalidated.

Code

Next, to get rid of the black background.

Wednesday, June 26, 2013

Codechef Jun 2013 Elephants (C++)

This code is simply a direct port from Python to C++. My Python submission gave a "time limit exceeded" error, while my C++ submission is perfectly accepted. Is Python really that slow?

Tuesday, June 25, 2013

More Win32 fun

Managed to set a timer to update the text on the screen every second, however, the window does not wipe itself clean after every update.

Code

After much research, came upon this solution: http://msdn.microsoft.com/en-us/library/ms632599(VS.85).aspx#layered

Instead of I used That solved it. Code

Codechef June 2013 Elephants

Wednesday, June 19, 2013

Win32 programming: random messages on the screen

I've always wondered how typical keygen programs, when run, doesn't create a window on screen. Or rather, technically, it's still a window, but there are no title bars, no _ □ X buttons, no borders, and even the background is transparent. Well, after viewing some basic Win32 tutorials and meddling with windows style I managed to satisfy my curiosity:
Next step, to make it drag-able!

Tuesday, June 18, 2013

Codechef May 2013 WitMath

I thought that by referencing the editorial and following faithfully I could have the solution out in minutes. Turned out to be hours..totally forgot how to do repeated squaring. Good revision, this was.

Monday, June 17, 2013

Codechef June 2013 Delish

I worked for hours on this one, just for my solution to be rejected. =( But the hard work paid off, my solution came very close to the one in the editorial =) This one didn't get accepted: Did my correction and got it accepted:

Codechef June 2013 Wstring

Seen the editorial, the algorithm described is exactly the same as what I did..but my solution is not accepted. I don't know why ='(

Codechef June 2013 Predictopus

Was wondering for a while if the each test case is accumulative from the previous...turned out it was not. Accepted!

Codechef June 2013 Lapindromes

Accepted!

Friday, June 14, 2013

Google Code Jam 2009, Round 1C, Problem A: All Your Base

Here is a nice summary of the approach to this problem.
The above problem statement, requires the output to be the minimum possible number. The first step is to understand that the number would be smaller if you take the smallest possible 'Base System' for the number. To find the base system that you want, you would have to find the number of unique symbols in the input string. If there are 2 'Unique' symbols in the string, take it as 'Base 2' system. If there are 10 unique symbols, take it as 'Base 10 (Decimal)' system.....and so on. Since the 'Unary System' is not used, ignore that. 
After that, we need to find how we can make the sum, as minimal as possible. Since we don't know which digit stands for what, we have to make a decision for each symbol, so as to make the number, as small as possible. Since the left most digit carries more weight, this digit should be multiplied by the smallest digit. But since the left-most digit can't be zero (0), make it '1'. Use the Zero (0) for the second left-most digit (if there is 2nd digit in the number). Then use '2' for the third left most digit (if it is unique), '3' for the 4th left most digit (if it is unique)..and so on, unitl the end of the string with symbols. 
^^

Thursday, June 13, 2013

ACM 103 Stacking Boxes

Greedy problem. For each box, sort each dimension from biggest to smallest. Then, sort all boxes from smallest to biggest. Apply some dynamic programming and viola!