Manchester encoding/decoding in LibHiJack

The hijack iPhone library implements Manchester encoding for digital communication.  Manchester encoding maps 0 to high-low transition, and 1 to low-high transition.

The iPhone library generates the transitions using full or half period of a sine wave, using a full period when a bit run is detected. An example of this is shown below.

Manchester encoding of 0110011101 by libHiJack

Detection of Manchester encoding is relatively simple: first the signal is regenerated into a square wave by setting all values above 0 to 1 and 0 otherwise. The number of samples between transitions (0 to 1 or 1 to 0) is then measured. When this interval is within an acceptable range (as determined by the baud rate) the bit is read simply by taking the value of the regenerated square wave immediately after the transition. This works out nicely because 1 maps to a low-high transition, and the value immediately after transition is 1, while 0 maps to high-low transition, and the value immediately after transition is 0.

The important thing to note is that detection of a bit occurs at the transition from one bit to the next, and the code ignores transitions during a bit period. Specifically a transition must occur between 3/4 and 3/2 bit periods from last bit detection, otherwise it is ignored.

For example the transition between sample 64 and 96 is ignored because it occurs 1/2 a bit period since the last bit detection at sample 64.

Finally, the UART frame used consists of a start bit, eight data bits, one parity bits and one stop bit. Note my example doesn't include the parity bit since I reimplemented the encoding algorithm in python to produce the graph.



Brendanites of the Brendanverse

Of all Brendanites, the worst off are the criminals and other malcontents. Water-boarding is par-for-course as is other cruel and unusual punishments, like electric-clamps-on-nipples and listening to boy bands non-stop. By the O'Neill doctrine, if it worked before then whatever it is is OK now and forever. Amen.

While criminals have it bad in Brendanverse, the entrepreneurs have it easy. Starting business in Brendanverse is simple: find a market and setup shop. No need to worry about established competition, they won't do things like undercut your prices or bad mouth you in front of their customers. No siree, that's not how Brendanverse works. 

You see, in Brendanverse a company that owns, say 70% of the market, will do nothing like leverage their market share and resources to drive out, hinder or crush their competitors. In fact, calling them competitors is a misnomer: it implies competition and we can't have that. Companies are more like friends, happily coexisting and sharing their toys, aka customers.

Even more blessed than the entrepreneurs are the Chosen - the Journalists (not the Jews). They have all the right the Government has, including and not limited to reading people's emails and tapping their phones. These are rights that, by the O'Neil Doctrine, the Government owes to journalist, because unlike the Government, a Journalist is the epitome of integrity and honesty. They rise above the law and accountability and other trifling matters like FOI requests.

Whoever they are though, every Brendanite is a completely rational human being unswayed by emotional rhetorics, who gives every opinion their due weight before making a decision.

What a brave new world, with such people in it.


Having had a glimpse of the mind of Brendan O'Neil, I can't help but think he is someone who when confronted with an uncomfortable question latches on to the nearest superficial answer and runs with it.

Some people call him a "passionate defender of free speech" which brings to mind the following quote by Jascha Heifetz:

“No matter what side of an argument you're on, you always find some people on your side that wish you were on the other side.”

I wonder if he supports the right of people to yell fire in theatres...



MYOB Not Printing Chinese Characters in Invoices

Simply set the language for non-unicode programs to Chinese (PRC) and it will magically work.

N.B. You must have first installed files for East Asia Languages in Languages Tab for this to work.



git with multiple svn-remotes

Use git init to create an empty git repository, then edit .git/config to add the svn remotes:

repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
[svn-remote "svn"]
url = file:///home/steve/code/svn-repos/foo
fetch = trunk:refs/remotes/trunk
branches = branches/*:refs/remotes/*
tags = tags/*:refs/remotes/tags/*
[svn-remote "svn-other"]
url = file:///home/steve/tmp/foo-svn-other
fetch = trunk:refs/remotes/svn-other/trunk
branches = branches/*:refs/remotes/svn-other/*
tags = tags/*:refs/remotes/svn-other/tags/*

It is assumed at this point svn-other is simply a copy of svn. They are allowed to diverge later.

Do a git svn fetch -R svn to initialise git svn. To manage commits between the two svn remotes, create local tracking branches of remote branches:

$ git checkout -b trunk-other remotes/svn-other/trunk

I ended up with something like :

* trunk-other

You can pull changes from one svn repository then push it to another:

$ git svn fetch -R svn
r1 = 049fed636e283096986e0eefa261be0525d8d7b3 (refs/remotes/trunk)
Checked out HEAD:
$ git svn dcommit
Committing to file:///home/steve/tmp/foo-svn-other/trunk ...
A test
Committed r2
A test
r2 = 10613af6701eca4b30a3ff89ab408e38ca157fa0 (refs/remotes/svn-other/trunk)
No changes between current HEAD and refs/remotes/svn-other/trunk
Resetting to the latest refs/remotes/svn-other/trunk



Find and svn add all untracked files

svn st | grep '^?' | sed 's/^[? ]*/"/' | sed 's/$/"/' | xargs svn add



Firehol and mDNS

Here is my firehol.conf that allows multicast mDNS packets through:

# define mdns so we will accept it

interface eth+ multi
   policy return
   server mdns accept
   server multicast accept                                                                                                        

interface eth+ home src "${home_ips}"
    server  all         accept
    client  all         accept

Initially I had the server mdns accept and server multicast accept inside the home interface, but this didn't work. Firehol's developer, Mr Costa Tsaousis, pointed out that src "${home_ips}" on home would exclude broadcast packets sent from MAC addresses, thus the second interface definition (multi).



Success for Science

Just finished packaging my engineering thesis project into a more portable format: an altoids tin! I have seen people put some neat stuff inside them, and I am chuffed I managed to as well :) Though I had to cut through the lid for the display. And I only had to use the hacksaw once.



Improved the DSO Nano Probes

Got parts from element14 today: hook probes and right-angle 3.5mm mono plug. Modded my DSO nano probes, replacing the micro-tweezer probes and the connector. Interestingly the factory probed using a stereo connector, but the mono replacement works just as well.

This along with BenF 3.61a firmware upgrade has improved the DSO nano somewhere between 100 to 1000 times.



My Err99 Resolution

Err99 is a somwhat common error encountered by Canon DSLR users. Because it is something of a catch-all error code a variety of causes and resolutions can be found via google. In my case the error was fixed by a firmware upgrade while it was in the hands of Canon camera servicing personnel, so if you find you have exhausted all options, send it back to Canon!
For what it is worth, the Camera already had what I thought was the latest firmware, perhaps I downloaded the wrong version, or Canon worked some additional magic.


Another Galaxy Down

Found NGC 4594, aka the Sombrero Galaxy.

In addition also found what is probably cataracts in my eyes >.<




TIL: const, NSError, NSApplicationsupportDirectory

  • const char *foo; is not the same as char * const foo; The former declares a pointer to constant char, while the latter declares a constant pointer to char.
  • - [NSError localizedDescription] returns the object for key NSLocalizedDescriptionKey in the error's userInfo dictionary. I always wondered how to set it since there is no setLocalizedDescription:.
  • On iOS the application's Application Support directory doesn't seem to exist by default, unlike the Documents directory. This has to be created programmatically.



ICBM: iOS OTA Distribution Webapp

Finding myself in the position of needing to distribute several apps OTA and unable to use the more well known OTA services like testflightapp.com due to client concerns, I made my own, ICBM.

ICBM is a small python webapp built using my favourite webapp framework,  bottle. You just put your application along with icons and the Info.plist (not the binary one) into a directory, and ICBM will generate the required HTML page and manifest plist.


  • icbm.py
    • AwesomeApp/
      • AwesomeApp.ipa
      • Icon.png
      • Icon_512.png
      • AwesomeApp-Info.plist

More detail over at its github page: https://github.com/freespace/icbm.



How to Tell if You Will Like Sucker Punch

Can you relate to the following image? If so, then yes.



Endianess, Thy art Sneaky

I took delivery of my Linksys WUSB600N V2 today and was very excited to get my G4 Mac Mini online. The many online sources suggests all I need to do is change a few values in an Info.plist. However as it turns out, that wasn't enough. In order for me to get it working, I had to change the values, but also write the new values in hexadecimal format. This is because even though 0x0079 translates to 121, that is only true for a little endian system. Likewise, 0x1737 also only translates to 5943 under a small endian system. Since OS X running on PPC is a big endian system, unless you write out the exact byte values using hexadecimal notation it isn't going to work.

So, for the record: Linksys WUSB600N V2 runs just fine on OS X 10.5.8 running on G4. It does 5GHz and successfully authenticates with my airport express, which the Monoprice USB 2.0 Wireless N it replaced didn't.


Tabbing in Vim With Tab Autocompletion

I use vim with a tab autocompletion macro, and sometimes I really do want to insert a tab character and autocompletion gets in the way.

Today I found out that if I hold down shift and hit tab, a tab is inserted and tab autocompletion doesn't get triggered. Prior to this I have been adding a space then hitting tab, which leaves ugly little space-tab sequences in my files.

Hope this helps some one out there.



Broken OS X Installers and How to Fix Them

The installers Ralink provides for some of their chipsets, like the RT2770 does something retarded: they attempt to unload a kext in a pre-install script, and when it fails the script fails and the entire install fails.

This means on a new machine, or one that never had the kext installed, you can't install their driver.


It used to be that pkg installers were just directories, and fixing something like this is easy: find the offending line and comment it out. But OS X 10.5 onwards introduced flat pkgs. These don't give up their secrets so easily.

An article on cnet tipped me off to pkgutil, a program that is installed by default. It lets you expand a flat pkg into a directory, and more importantly, allows to repackage it as a flat pkg after you have excised the cause of your troubles. This last step is important because a flat pkg when unpacked has a different directory structure to a "normal" pkg and thus can not simply be open'd.

Here is what I did to fix Ralink's installer:

  1. pkgutil --expand installer.pkg ~/Desktop/installer-expanded.pkg
  2. cd ~/Desktop/installer-expanded.pkg/installroot.pkg/Scripts/
  3. vim preinstall #alternatively, for ppl unfamilar with vim:
    1. open .
    2. right click on preinstall, open in TextEdit.app
  4. comment out the offending line which is trying to remove the kext
  5. save and exit your editor
  6. cd ~/Desktop
  7. pkgutil --flatten installer-expanded.pkg installer.pkg
  8. open ./installer.pkg



iOS Toolbar Pagecurl Icon

iOS 4.x's page curl UIBarButtonItem comes in blue, and blue, and blue. If you set a UIToolbar's tintColor, then it disappears for some reason.

So I had to make a replacement. Since I use a lot of icons made and given away by awesome people, I feel it is only fair to contribute my share, small though it maybe.

Released under WTFPL. Though it would be nice to hear from you if you do use it :)


iPhone 4 layer export script for Gimp

I often mockup iPhone interfaces on the Gimp, then exporting each layer for use as backgrounds. For iOS 4 each image needs to be exported twice: one at full resolution with @2x in its filename, and once at half-resolution without the @2x. e.g. nav_bg@2x.png and nav_bg.png.

Exporting layers by hand gets old real quick. Thankfully the Gimp supports scripting in my favourite language: python. Even better, Chris Mohler had already written a script to do something very similar, so all I needed to do was make some simple adjustments:
#!/usr/bin/env python
# -*- coding: <utf-8> -*-
# Author: Chris Mohler <cr33dog@gmail.com>
# Copyright 2009 Chris Mohler
# "Only Visible" and filename formatting introduced by mh
# License: GPL v3+
# Version 0.4
# GIMP plugin to export layers as PNGs
# modified by Shuning Bian 2011

from gimpfu import *
import os, re

gettext.install("gimp20-python", gimp.locale_directory, unicode=True)

def format_filename(layer):
    layername = layer.name.decode('utf-8')
    filename1 = layername + "@2x.png"
    filename2 = layername + ".png"
    return filename1,filename2

def get_layers_to_export(img):
    layers = []
    for layer in img.layers:
        if layer.visible:
    return layers

def export_layers(img, path):
    dupe = img.duplicate()
    savelayers = get_layers_to_export(dupe)
    for layer in dupe.layers:
        layer.visible = 0 
    for layer in dupe.layers:
        if layer in savelayers:
            layer.visible = 1

            if layer.mask:
                pdb.gimp_layer_remove_mask(layer, 0)

            filename1,filename2 = format_filename(layer)
            fullpath = os.path.join(path, filename1);
            tmp = dupe.duplicate()
            pdb.file_png_save(tmp, tmp.layers[0], fullpath, filename1, 0, 9, 1, 1, 1, 1, 1)

            imgwidth = pdb.gimp_image_width(img)
            imgheight = pdb.gimp_image_height(img)
            pdb.gimp_image_scale_full(tmp, imgwidth/2, imgheight/2, 2)

            fullpath = os.path.join(path, filename2)
            pdb.file_png_save(tmp, tmp.layers[0], fullpath, filename2, 0, 9, 1, 1, 1, 1, 1)


    blurb=("Export visible layers as PNG"),
    help=("Export all visible layers as individual PNG files."),
    author=("Chris Mohler <cr33dog@gmail.com> + sbian"),
    copyright=("Chris Mohler"),
    label=("as _PNG"),
        (PF_IMAGE, "img", "Image", None),
        (PF_DIRNAME, "path", "Save PNGs here", os.getcwd()),
    menu=("<Image>/File/E_xport Layers"), 
    domain=("gimp20-python", gimp.locale_directory)




Socket.IO Framing Protocol

Socket.IO is a great library and framework that doesn't seem to have a good description of the protocol available. In interest of helping others when they google "socket.io framing protocol", this post was born.

The description of the framing protocol used by Socket.IO below is taken from ajaxorg's Socket.IO-node fork on github. I have made some changes with regards to the annotations, specifically that they must be terminated by with newline. This description is current for v0.6+.

Socket.IO Framing Protocol

Socket.IO 's framing protocol is on top of the underlying transport. Messages have the following format:
(message type)":"(content length)":"(data)","
Where message type is one of:

  • 0 for forced disconnect - no data is sent, always sent as 0:0:,
  • 1 for messages - see below
  • 2 for heartbeats - data is an integer, e.g. 2:1:0, 
  • 3 for session ID handshake - data is a session ID, e.g. 3:3:253,


If you were familiar with the Socket.IO protocol you will notice there appears to be no way now to specify a message contains JSON data as the new protocol has no counter part to the JSON Frame indicator ~j~. Fear not - the new Socket.IO protocol provides a means for this and many other possible extensions via annotations which maybe attachd to messages in a manner reminiscent of HTTP headers. 

A Socket.IO message now has the following format:
In words: annotations are key-value pairs where the value may be omitted. Individual annotations are delimited by newlines, and annotations are separated from the message by another newline.

From examining the Socket.IO source, if no annotation is present then there should be no newline, but the colon is still required.

A JSON message is sent with a single annotation with key of j and no value. Below is an example taken from a debugging session:
Note there is a newline after the j. The official Socket.IO client uses an additional annotation: r for realm. e.g.
:Hello world,
Note the newline after chat.



UIGraphicsBeginImageContext on iPhone 4

I generate UIImages in some of my iOS applications, and prior to the iPhone 4 they all worked fine. With the introduction of the iPhone 4 and Retina Display, I realised my generated images were blurry even though I am rendering them at twice the resolution.

It turns out this is due to the scale property of my generated UIImages being set to 1. This is mainly due to my use of UIGraphicsBeginImageContext(), which creates a bitmap context that is a) non-opaque and b) scale=1. The fix is quite simple - use UIGraphicsBeginImageContextWithOptions() and specify the scale appropriately.

For images derived from an existing image, e.g. rotating an existing image, it is sufficient to use the scale property of UIImage. For images created "from scratch", I use the following bit of code:
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)])
  UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale);
else UIGraphicsBeginImageContext(size);