Thursday, April 30, 2015

After I upgraded to Ubuntu 15.04 Vivid Vervet, the Audacious plugin I used to control a display device I built had a problem. Functionality related to sleep and wake didn't work anymore. That's because UPower doesn't handle sleep and wake anymore. Notification events instead come from systemd-logind. In particular, it is the "PrepareForSleep" signal on the "org.freedesktop.login1.Manager" interface. When its argument is true, the system is preparing to go to sleep, and when it's false, the system is waking up. Here's the new code.

I still need to find a way to determine the last wake time. Formerly I was using the /var/log/pm-suspend.log modification time, but that is also now unavailable because systemd is handling it instead. If the plugin observes a wakeup, it gets the correct time from that, but when started it needs another method.

This illustrates a major difference between Windows and Linux. The Windows version of the plugin can still use the WM_POWERBROADCAST message, with parameters dating from Windows 2000. Linux is a moving target, and things will break unless you keep updating them. This probably also extends to Linux application APIs.

HWMonitor is a nice utility which shows temperature, voltage and other measurements. It supports the motherboard, hard drive, graphics card and UPS. However, I've seen blue screens after using it in the past, and this experience further confirms that HWMonitor causes blue screens.

I just upgraded to version 1.27. I hope that version will work better.

Edit: Nope, it's not fixed. I didn't trust version 1.27, so wanted to restart after using it. I got another memory corruption crash on shutdown.

I saw Cinnamon claiming that the UPS is empty (0%), which made me assume there was some bug in Linux. It even hibernated the PC even though AC power wasn't interrupted, which is definitely a bug. Then I double-checked via apcupsd in Linux, and then in Windows, with PowerChute Personal Edition 3.0.2 and CPUID HWMonitor 1.20.0. The UPS was definitely claiming it was empty. However, PowerChute said it was operating normally and charging.

HWMonitor provides the most interesting information. It constantly updates the battery voltage and levels, and keeps minimum and maximum values..The voltage was fluctuating from below 12 to above 13. That does not seem like proper charging. When I took the battery out, it was around 12.6. My first thought was that there was a bad capacitor causing excessive ripple and giving bad readings. This led me to open up the UPS:

I saw high ripple at the leftmost capacitor, near the red wiring fault light and the heat sinks. After replacing that 220µF 50V capacitor, ripple went down from 5V to 3V. I'm not sure that this helped though. When it started charging, HWMonitor reported voltage steadily rising toward 13.50V. It stayed stable for a while. Then it fluctuated going down to 11.54V even. Now, the voltage is stable again, around 13.26V, and percentage is rising.

The stability makes me think the fluctuations were the firmware interrupting charging and doing some discharge tests. Surely 11.54V is too low though. Maybe the battery is bad and the firmware isn't smart enough to report that. I saw it quickly go below 12V with a car headlight, so it probably is worn out.

Sunday, April 26, 2015

I switched to KDE when GNOME 3 was released. Over time, version 4 generally got better and less buggy. I was satisfied and even happy with it. Now Plasma 5 seems to have thrown away a lot of that progress. There are far more bugs and less features. It's not as bad as the GNOME 3 change, but Plasma 5 is bad enough that I don't want to use it.

It's tragic how these free software desktop environments get to be good and then revert to a state which should be called an alpha release. Of course GNOME 2 and KDE 4 had some limitations and disadvantages. A big bold change can help there, but I think the only way to truly improve is to slowly evolve into something better. Even Microsoft can't successfully make sudden big changes.

GNOME 3 has improved in the meantime. I still think the window switching, application launcher and top bar are inefficient and limiting, and it wastes screen space. So, I definitely won't be choosing GNOME 3. MATE reminded me that things have improved since GNOME 2, and I don't want that either.

Cinnamon seems good now. It seems to be a combination of the best of GNOME 2 and GNOME 3. Its web page may be unimpressive, but the software works well and has enough features. It seems significantly faster than KDE, and I'm forced to install a lot less stuff. Losing KDE 4 was annoying at first, but now it seems I'm switching to something even better.

Thursday, April 23, 2015

Synaesthesia is my favourite music visualization program. I created an updated Windows port and also ported it to Emscripten. The code is on GitHub. Here is a screen shot, but you have to see it in action to really appreciate it.

Click here to run the program. Then start visualization by dragging an audio file from a file browser window on your computer to the web page. No information is sent over the network. The file is played by the web browser and visualized by asm.js running in the browser.

If you find that Firefox can't play MP3 files in Linux, install gstreamer1.0-fluendo-mp3.

Emscripten's SDL tries to emulate desktop SDL. This involves some costly operations which many programs don't need. Performance can be improved by changing settings to prevent those operations.

Consider the multiple copies

The image exists in 3 places in the web page: program memory, canvas ImageData, and the canvas element. Normally, SDL_LockSurface() copies from the canvas, to ImageData and then to program memory, and SDL_UnlockSurface() copies from program memory to ImageData and to the canvas. Conversion may be needed between program memory and ImageData.

SDL.defaults.copyOnLock = false

SDL_LockSurface() will copy from canvas to ImageData but not from ImageData into program memory.

SDL.defaults.discardOnLock = true

SDL_LockSurface() will use createImageData() once to initially create ImageData, and never copy from the canvas. Copying from ImageData to program memory is prevented regardless of SDL.defaults.copyOnLock.

SDL.defaults.opaqueFrontBuffer = false

With normal SDL you can write only the RGB values and get opaque pixels of the requested colour. Canvas pixels also have an alpha value, which needs to be set to 255 to make pixels fully opaque.

Normally, both SDL_LockSurface() and SDL_UnlockSurface() set alpha values in ImageData to 255. This option prevents those operations. With it, the SDL_HWPALETTE 8 bpp mode works normally, your code that writes pixels into memory must set the alpha values. You can simply bitwise or pixels with Amask from the surface SDL_PixelFormat.

Use SDL_HWPALETTE flag for 8 bpp modes

It's possible to use 8 bpp without SDL_HWPALETTE. However, that uses less optimized code when converting to 32 bpp for the canvas, and doesn't work with SDL.defaults.opaqueFrontBuffer = false.

SDL_HWPALETTE requires that SDL_LockSurface() copying is disabled. 8 bpp modes without the flag don't have that requirement, but you'll end up with 32 bpp RGB values copied back, which you probably don't want.

Module.screenIsReadOnly = true

This prevents SDL_LockSurface() copying. You could use it instead of SDL.defaults.discardOnLock = true. The only difference is that ImageData is copied from the canvas the first time SDL_LockSurface() is called instead of being created via createImageData(). It's probably better to use the SDL.defaults options instead because they're better documented and better named.

Sample code

Here is a code fragment which sets uses the recommended optimization settings and enters 8 bpp mode in the recommended way. Some of this is redundant as noted above, but there's no harm in that.

Wednesday, April 22, 2015

Normally, iPodLinux uses a Linux 2.4 kernel. The SVN repository on SourceForge also has a 2.6 kernel. It's an abandoned work in progress which lacks some drivers and support for PP502x iPods. Nevertheless, it may be a good starting point.

The port is based on Linux 2.6.7 with linux-2.6.7-hsc0.patch.gz applied. (This is the MMU-less ARM patch. It was mainlined in later 2.6 kernels.) Then, the iPodLinux files need to be copied into that tree, overwriting some Linux files.

This runs into several problems. Building with the old GCC 2.95.3 toolchain fails because the assembler is too old. With arm-uclinux-elf-tools.tar.bz2, the assembler is fine, but old GCC options are used, which aren't accepted by GCC 3.4.3. There are also two other small errors, and one error preventing make menuconfig. I'm distributing a fixed version in the form of a bare Git repository. It successfully builds linux.bin, which I didn't try to run because I don't have an old PP5002 based iPod.

One build problem remains: make always rebuilds everything. I'm not sure what's going on. If I run make -n --trace after successfully building linux.bin, I see a lot of stuff being re-built due to FORCE, as if this is intentional.

Tuesday, April 21, 2015

I've been using Winamp for a long time. With a stripped-down configuration and the 2.x interface it is perfect. It supports a lot of formats, plugins and a playlist. With a nice skin it looks good, but takes up very little screen space and resources. I'm used to playing files from folders, and not using any sort of database.

Audacious seems to be the best replacement for Winamp in Linux these days. Its default interface is too big and plain, but it supports Winamp 2.x skins. It also uses plugins to implement various functionality and has an even better plugin API than Winamp.

There didn't seem to be any equivalent of the Winamp "Find File on Disk" plugin, so I created one. This gist contains the source code. To use it, right click on a file in the playlist, go into the "Services" sub-menu and select "Open File Location". You can also select multiple files in the playlist, and they will all be selected in the file manager.

Right now the plugin is written to use the KDE Dolphin file manager, which offers the nice --select flag. I'm not sure how to make this automatically work well with any file manager.

Hard drives found in iPods generally support SMART. It is useful for checking drive health and running tests. The flash-based diagnostic mode reports only a few of the attributes. Rockbox lacks support for USB mass storage features which would allow programs running on a computer to use iPod hard drive SMART functions. I believe the original firmware's disk mode and the emergency disk mode in flash also lack this support.

Wednesday, April 08, 2015

This is an old post that I didn't get around to completing, and kept as a draft. It talks about how I ported Rockbox to the RCA RC3000A digital boombox. Code is available on GitHub.

Summary

First I opened it up and noted the chips inside. Some already have Rockbox drivers. Then, I figured out how to use USB boot mode to run code using tcctool with slight modifications. I used code to dump the firmware, outputting data via a GPIO pin and reading it via the sound card. Then I did some reverse engineering, figured out various functionality, got a Rockbox bootloader running, got Rockbox running and finally made playback work.

The LCD

First, I wanted a better form of feedback than GPIO pin toggling, so I figured out the LCD. The LCD command and data writing routines can be reached by following subroutine calls from a function that displays strings on the LCD. Then, other functions can be identified which use these functions to do stuff with the LCD. The initialization sequence was interesting. Instead of writing register indexes and then writing data to those registers, some commands have a command number in the high bits and data in the lower bits. I identified the controller by searching through Rockbox LCD driver files for | (which is bitwise or in C). The lcd-archos-bitmap.c driver for the graphical LCD on old Archos devices seemed like a match, so the LCD controller is probably a SSD1815. However, the initialization routine uses different values because the LCD panel is different, and it's important to use those values.

The call to the LCD initialization routine was surrounded by other interesting and relevant code. Just before the initialization, a call to a long function set the TCC760 chip select register for access to the LCD. Instead of trying to understand the function, I simply executed it in ARMSim to get the value. There was also a nearby GPIO call which controls the backlight.

Now it was possible to execute some code and write to the LCD. I thought building even a Rockbox bootloader would be difficult, so I just used a modified lcd-archos-bitmap.c file. This worked, but there was nothing interesting to display. I also verified that the nearby GPIO controlled the backlight. This was tricky, because although the CPU and LCD can run from USB power only, the backlight requires external power.

Building a Rockbox bootloader

This success made me want to try running more of Rockbox. I first decided to build a bootloader, because it uses only selected components of Rockbox. The Rockbox Wiki provides some basic information about how to create a new target. I started off by copying files from the Sansa C100, which uses the related Telechips TCC770 CPU. There were plenty of things to edit and rename, but it was all fairly straightforward, and error messages can serve as a guide showing what needs to be done.

Uploading code to SDRAM

The resulting bootloader was too big for loading in TCC760 internal SRAM, so I needed to use DRAM. Unlike with later chips, USB boot mode doesn't provide a way to set the SDCFG register. So, I used a small bit of assembler code to set SDCFG and then jump back to 0 to restart USB boot mode and enable uploading of a longer program to SDRAM. It was easy to get the bootloader running, but timer interrupts took a bit more work. The TCC760 is similar to TCC770, but there are some key differences with some peripheral register bits.

Figuring out the buttons

The bootloader allowed viewing of GPIO and ADC values which helped me figure out the buttons and some other values. The power/play/pause button is connected to its own GPIO pin, but all the other buttons are connected to one pin, with each connecting it to ground via a different value resistor. This means the ADC must be used to read these buttons. I ended up finding the original firmware routine which reads buttons and using its thresholds between different buttons. I suppose that's better than using measured values, because the measured values are affected by resistor tolerances.

SD card access

The RC3000A has 512MB of internal NAND flash storage, and an SD card. I chose to first use the SD card, because that seems safer. When I viewed GPIO values, I found pins for SD card write protect and SD card detection. I used these to find the SD card code. ARM code typically loads a base address into a register and then accesses a memory mapped peripheral register using that register plus an offset encoded into an instruction. In this case, 0x80000000 is always loaded into the register, so the offsets are predictable and they can be used to search disassembled code for GPIO access with few false matches. There is one unfortunate complication though. All the code I've seen makes the GPIO port obvious, but some uses a value loaded from RAM to define the bit.

I assumed that the SD card uses bit banging because there is no SD controller and USB access to the card is ridiculously slow. I did find bit banging code, but actually the SD card is hooked up to GSIO0, and there is also code for that. I chose to initially use bit banging code, because it is simpler to be sure I'm doing it correctly. GSIO could have left me wondering if the problem was the way I'm using GSIO or the interface to the SD card.

SD card bit bang SPI interface code can be used to add SD cards to routers, and source is available there. However, I chose to start with code from within Rockbox, from the Archos Ondio MMC card driver. Its structure more closely matches my intended final structure, with GSIO and hopefully also DMA.

After learning about the SD card protocol and commands, I first worked on getting initialize_card() working. At first this seemed futile, but then I added the initial synchronizing code sending 0xFF bytes with chip select not asserted and it worked. Then I just had an endianness issue in card_extract_bits() and after that the function succeeded. Then it was simple to read a sector.

Building Rockbox, adding functionality, and getting sound

(Post was interrupted here and continued much later.)

Once SD card reading was available and mountable, it seemed like a good time to run a full build of Rockbox. Since this includes files and functionality not compiled into the bootloader, some work was needed to get it to compile. Then it was time to add more functionality.First I added I2C support, testing it using the E8564 RTC chip, which Rockbox already supports. The RC3000A uses purely software based bit-banging I2C, although the TCC760 chip does contain an I2C controller.

I wanted to first set up the CODEC for FM radio playback, which should be simpler than music playback. At first I thought I could use the CS42L55 code present in Rockbox, but the CS42L51 is significantly different, so I ended up creating a new driver using parts of the Linux driver. I got the radio working using the pre-existing TEA5767 driver. Only the headphone jack was usable, because the amplifier driving the speakers was off.

Then it was time to do various tweaks to CODEC and I2S configuration and make playback work. However, the result was interrupted playback, because the device was too slow. I enabled the CPU caches, and started using GSIO for SD card access, and sped up the SD clock. Finally, I got perfect playback of a FLAC file.

Cleanups, tweaks and optimizations

There was still a lot of optimizing to do. The fast internal RAM in the TCC760 could be used to speed up code. Thumb and INIT_ATTR could free up memory. The SD driver needed more work. DMA could be used for playback.

I spent a lot of time trying to get DMA to work with GSIO for SD card accesses, but it seemed impossible and eventually I gave up. I optimized things the best I could with 16 bit GSIO transfers.

Getting USB to work was interesting, because I had never worked with a USB device before.

There were a lot of features to support. Rockbox includes various LCD settings such as flip and inverse, and a way to display greyscale on an LCD which doesn't officially support it. I also enabled sound bass and treble setting via the codec and backlight PWM fading.

Flashing the bootloader

So far, Rockbox could only be loaded via USB boot. It time to flash a Rockbox bootloader with dual-boot support, allowing for choosing between original firmware and Rockbox. I was a bit anxious because this could brick the device, but there was no real danger because USB boot should allow recovery.

Initially, I was thinking I would create a flash plugin and use it to flash the bootloader. However, I ended up creating a firmware upgrade file and flashing it via the original firmware. My first attempt allowed access to original firmware, but failed to run Rockbox. After adding some short initialization code from the original firmware I could load Rockbox.

The end?

Once I had a working Rockbox port, I stopped working on this. The RCA RC3000A devices are probably quite rare, and I've never encountered anyone else interested in running Rockbox on one. It doesn't even seem like there's any interest in running Rockbox on TCC76X devices. Therefore, I don't think adding this port to Rockbox would benefit anyone.

One thing that still interests me is making use of the OHCI USB host controller on the device. The original firmware supports it but fails badly when accessing a large device because it tries to scan all the files and keep a list in memory. I wonder if there's a good free software embedded USB stack? The SeaBIOS code might be useful, but it is GPL 3 and Rockbox is GPL 2.

I've also thought about adding an ESP8266 module and creating a Rockbox plugin for playing Internet radio. Such a plugin could also be used with other targets with externally accessible serial ports, such as the iPods.

Sunday, April 05, 2015

iPodLinux is a Linux distribution for iPods based on PortalPlayer chips: the old hard disk based iPods up to the 5th generation, and the 1st generation Nano. It's actually a port of uClinux, because the processor lacks the memory management hardware needed for ordinary Linux. iPodLinux consists of a kernel port, the Podzilla application which provides an iPod-like interface, and various modules for Podzilla which are in effect small programs.

I have iPodLinux installed on my 5th generation iPod. It's interesting but not very useful for me. I normally run Rockbox, and I've only used iPodLinux for running Smartmontools smartctl to check hard disk health. Nevertheless, I'm interested in learning more about the Linux kernel, so I just spent some time tracking down the kernel source code.

Source locations

The old home page at www.ipodlinux.org has been down for a long time. Don't bother trying Archive.org, because the site wasn't archived due to its robots.txt.

There is an ipodlinux SourceForge project. Its files section contains patches and binaries. The latest 2.4.24-ipod2 version there is old and does not contain PP502x code needed for 5th generation iPods. If you want to use it, get linux-2.4.24, apply uClinux-2.4.24-uc0.diff and then apply the ipod2 patch. You can build with the arm-elf-tools-20030314.sh toolchain.

The same SourceForge project also has a SVN repository which has a later version. The kernel was initially at trunk/linux/ and then in r2251 "The Great Befuddlement" moved it to linux/2.4/. The repository only contains changed files, so you have to take an unmodified Linux directory, apply the uClinux patch, and then copy files from the repository into that tree. This kernel builds with arm-elf-tools-20030314.sh and works with my iPod. The repository seems abandoned, with the last commit in 2009. For convenience I'm providing a Git repository of just the kernel.

The SVN repository also has a 2.6 port at linux/2.6/ but it's at a very early stage. It might partially work with some older iPod, but it certainly won't have full functionality. I didn't even get it to compile successfully yet.

The uClinux-2.4.x patches starting with uClinux-2.4.24-uc1.diff.gz also contain iPodLinux code. It seems to be a stripped-down version of the ipod0 code, meaning it's very old. This complicates attempts to upgrade later iPodLinux to a later kernel version version, but it wasn't too hard to do with a git merge.

The latest version?

Finally I found ipodlinux on GitHub. The linux-2.4.32-ipod kernel seems to contain everything from the SourceForge SVN repository, but it switches over to uClinux 2.4.32 earlier, so it is not an exact copy. After that it contains some iPod specific patches, and then various Linux fixes.

The repository contains the entire kernel, so you can simply build from there. It is meant to be compiled with a later version of the toolchain. I used arm-uclinux-elf-tools.tar.bz2 with GCC 3.4.3. It compiles without problems and works on my 5th generation iPod.

Installing the kernel

You need to convert the kernel to a binary linux.bin image. Take a look at the instructions on SourceForge. Since I mainly use Rockbox, I have the Rockbox bootloader installed. It loads /linux.bin from the FAT32 partition if I hold down the play/pause key at the bottom of the wheel. You need a separate Linux partition for iPodLinux. If you need to resize partitions, be careful, because the original firmware partition is marked as unused but is actually required.

SansaLinux

The V1 Sansa players also use PortalPlayer chips. SansaLinux seems to be an adaptation of iPodLinux to those players. In some parts kernel code is the same but "ipod" has been replaced by "sansa". I have not investigated this in depth. It could potentually have some useful new PP502x functionality.

Friday, April 03, 2015

My laptop would sometimes wake up from sleep while closed. After some searching online I learned about the hinge switch. Replacement switches are inexpensive, but the replacement procedure seemed complicated and involved removing the top half of the laptop.

After opening up the laptop, I found that the switch can be removed without removing the top half. Just the hinge cover and keyboard are in the way. After unplugging the switch cable beneath the keyboard, the switch can be carefully manoeuvred out.

The hinge cover was the worst part. It's easy to open the screen 180 degrees and pry it up via the slot on the right, but the clips at the left side didn't disengage easily. I was afraid I would break something, but after looking at some videos I just continued, with carefully distributed force and some wiggling. The keyboard is easy to move out of the way, with just two screws at the top and easy pry points near Backspace and Esc. There is no need to unplug it, but be careful to not put stress on the flexible cable.

I also tightened screws connecting hinges to the bottom part of the laptop. They were a bit loose and this improved things, but the plastic itself flexes anyways. The top half would need to be opened up to tighten the hinge screws there, and that involves a lot of plastic clips.

I simply took the switch out and didn't replace it. I don't think I'll miss it. It's such a tiny delicate thing! Whoever designed that part of the laptop is an idiot. I assumed they would be using a magnet and reed switch or hall effect sensor.

This picture is with the switch removed. Its location is behind the black sleeved WiFi antenna cables where they enter the top half. The oval shape of the plastic where the wires enter actuates the switch.