Sunday, December 12, 2010

A stripped-down Rockbox build for the Archos V2 Recorder

The Archos V2 Recorder has only two megabytes of RAM. This RAM is used for the software running on the device, and whatever RAM remains may be used as a buffer to store MP3 data. It's a very small amount of RAM and even at 128 kbps, most songs cannot fit. Because of this, the hard drive has to spin up frequently to read additional data.

In 2007 I noticed how newer versions of Rockbox left less free buffer space and I decided to make my own build with more free space. The first step was a RomBox build. This helped a lot, but I wasn't satisfied. I saved more RAM by disabling various features which I didn't need: code page loading, language loading and the voice interface. With this build, I have 1.774 MB of buffer space.

I also fixed a few bugs, either by backporting fixes from later versions or by fixing the bug myself. Most notably, I fixed the charging screen issues.

Here are some files associated with this custom build:
This is all based on Rockbox from November 2007. I've used this build for years on my V2 Recorder without running into any significant problems. I view it as a finished product, because I see no need to update the V2 Recorder to newer versions of Rockbox, and my attempts to minimize memory usage encountered diminishing returns.

I did not make any builds for other old Archos devices because I don't have access to those devices for testing. It should not be hard to build for those. The only tricky part is what I did to the language system to save RAM.

Update 

This is based on Rockbox r15545. You can now download just the patch. Here's a list of the included fixes and changes:
  • FS#9638 - temp_cue is unused and wasting memory 
  • FS#7631 - Charging screen broken on V2 Recorder. Several fixes enable the charging screen, display of input current on the screen, and proper startup from the charging screen.
  • FS#9635 - Instant backlight turn-off on FM/V2 Recorder
  • FS#8163 - Rockbox (Sansa) hangs in settings menu. This fixes a crash caused by the scrolling title used for setting text horizontal scrolling speed. 
  • Removal of language changing, with English language strings used directly from ROM. (This requires manual intervention when building.)
  • Removal of voice functionality.
  • Removal of codepage changing
  • Removal of the database (this is part of the RomBox instructions).
  • Removal of low battery shutdown
  • Unused conditionals for removing bookmark functionality. This part is probably incomplete and bookmark functionality remains.
In general, the removals are kind of incomplete and messy. I removed the main memory using parts, but I didn't remove all traces of those features. For example, the settings for removed features still remain. I did not extensively test all possibilities, but I did not run into any problems whatsoever over years of use.

Saturday, December 11, 2010

drop.io is closing and my files were hosted there

In the past I chose to use drop.io for hosting files (other than photos) which are associated with this blog. I just learned that drop.io is closing and all files will be deleted on December 15th. I just found out about this as I went there to replace a file with a newer version. The drop.io blog post claims that notification e-mails will be sent, but I didn't receive any e-mail despite having an e-mail address associated with my account.

I'm now hosting my files via Dropbox. I think I updated all the links. If you find a broken link, leave a blog comment here or on that particular article.

Wednesday, December 08, 2010

Sometimes, a period doesn't match any character

Recently I found that in regular expressions in GNU sed, ‘.’ failed to match some characters. At first it was very surprising, but there's a simple explanation in the GNU sed manual:
s/.*// does not clear pattern space
This happens if your input stream includes invalid multibyte sequences. POSIX mandates that such sequences are not matched by ‘.’, so that ‘s/.*//’ will not clear pattern space as you would expect. In fact, there is no way to clear sed's buffers in the middle of the script in most multibyte locales (including UTF-8 locales). For this reason, GNU sed provides a `z' command (for `zap') as an extension.

To work around these problems, which may cause bugs in shell scripts, set the LC_COLLATE and LC_CTYPE environment variables to ‘C’.

The used the ISO-8859-1 character set while Cygwin by default uses UTF-8. The characters not being matched formed invalid sequences in UTF-8. Setting ‘LANG=C’ also fixes the problem.

Thursday, December 02, 2010

Hiding a window from the Taskbar using WS_EX_TOOLWINDOW

A window can be hidden from the Taskbar by adding the WS_EX_TOOLWINDOW extended style. As a side-effect, this changes the window frame, but that may not be a problem. When modifying an already existing window, that window needs to be hidden and then showed again for the modification to take effect.

One application can easily do this to a window of another application. For example, here is a bit of code for doing this to Windows Live Messenger:
HWND hw = FindWindow("MSBLWindowClass", NULL);
if (hw == NULL) {
printf("Window not found.\n");
return -1;
}
ShowWindow(hw, SW_HIDE);
SetWindowLongPtr(hw, GWL_EXSTYLE,
GetWindowLongPtr(hw, GWL_EXSTYLE)
| WS_EX_TOOLWINDOW);
ShowWindow(hw, SW_SHOW);

It works well, but the code has to be run every time the window is created. It's better to actually create the window with WS_EX_TOOLWINDOW, but that requires a bit more work. The simplest way is to intercept the function which the application uses to create windows. Detours provides an easy way to do this. For example, to hide the Windows Live Messenger window, intercept CreateWindowExW. The intercepting function just needs to do the following before calling the real function:
if ((((DWORD)lpClassName) & ~0xFFFF) != 0 &&
!wcscmp(L"MSBLWindowClass", lpClassName)) {
dwExStyle |= WS_EX_TOOLWINDOW;
}

I don't recommend patching of binaries. It's more difficult to understand program flow and devise a patch, and some applications would make it even more difficult via packing and anti-debugger techniques. Patching also needs to be re-done when the application is updated. In this case, it only makes sense as a reverse engineering training exercise. One hint: a Win32 API monitoring program such as WinAPIOverride32 can easily find the location of the call.

Getting elapsed time since last Windows wakeup via CallNtPowerInformation

Windows provides the last system wake time via CallNtPowerInformation. It returns the "interrupt-time count, in 100-nanosecond units". To obtain the time since last wake, this needs to be subtracted from another value, but the documentation doesn't explain what other value can be used. In Windows 7, GetTickCount and GetTickCount64 (which return time in milliseconds) work great. The combination even returns a good result after a bootup, when the system hasn't slept yet. Do not use QueryUnbiasedInterruptTime or QueryPerformanceCounter. The latter will be close enough at first, but every time the system sleeps and wakes, additional error will accumulate.