Category: computers suck

  • another partial success…

    chuckie_egg-loading

    I guess I’ve had some qualified success in getting the ZX Spectrum going. After finding the right (mono) cable, sticking it in the Spectrum’s EAR socket, converting tape images to audio with tape2wav, and getting a PAL/NTSC converter, I can load stuff. Sort of.

    chuckie_egg-dotcrawl

    The problem is mostly with the video converter; it’s too slow. The screen refreshes a couple of times a second, which is enough to lose many Hen-House Harrys. I know, I should’ve gone for a more expensive one.

    I’ve found that the audio files made by tape2wav are very loud; 0 dB, full deflection, distort-o-matic. Dropping the volume to -3 dB made games load better. Adding a couple of seconds of silence at the beginning of the file wouldn’t hurt, either.

  • A (mostly) colour-managed workflow for Linux for not too many $$$

    Colour management is good. It means that what I see on the screen is what you meant it to look like, and anything I make with a colour-managed workflow you’ll see in the colours I meant it to have. (Mostly.) You can spend a lot of money to do this professionally, but you can also get most of the benefits for about $125, if you’re prepared to do some fiddly stuff.

    The most important part is calibrating your display. Hughski’s ColorHug (which I’ve mentioned before) is as close to plug-and-play as you’ll get: plug it in, and the colour management software pops up with prompts on what to do next. Attach the ColorHug to the screen (with the newly supplied stretchy band), let it burble away for 10–20 minutes, and the next time you log in, colours will be just right.

    Calibrating the scanner on my Epson WorkForce WF-7520 was much more work, and the process could use optimization. To calibrate any scanner, you need a physical colour target to scan and compare against reference data. The cheapest place to get these (unless there was one in the box with your scanner) is Wolf Faust’s Affordable IT 8.7 (ISO 12641) Scanner Colour Calibration Targets. If there are a bunch of likeminded folk in your area, it’s definitely worth clubbing together on a group buy to save on shipping. It’s also less work for Wolf, since he doesn’t have to send out so many little packages.

    (I’ve known of Wolf Faust since my Amiga days. He produced the most glorious drivers for Canon printers, and Jeff Walker produced the camera-ready copy for JAM using Wolf’s code. While Macs had the high end DTP sewn up back then, you could do amazing things on a budget with an Amiga.)

    colour targetThe target comes packed in a protective sleeve, and along with a CD-R containing the calibration data which matches the print run of the target. Wolf makes a lot of targets for OEMs, and cost savings from his volume clients allow him to sell to individuals cheaply.

    Scanning the thing without introducing automatic image corrections was the hard part. I found that my scanner had two drivers (epson2 and epkowa), the latter of which claimed to support 48-bit scanning. Unfortunately, it only supports 24-bit, like the epson2 driver, so whichever I chose was moot. I used the scanimage command line tool to make the scan:

    scanimage --mode Color -x 175 -y 125 --format=tiff --resolution 300 > Epson-Workforce_WF-7520-WFaust-R1.tiff

    which looks, when reduced down to web resolution, a bit like this:

    Epson-Workforce_WF-7520-WFaust-R1It looks a lot darker than the physical target, so it’s clear that the scanner needs calibrating. To do this, you need two tools from the Argyll Colour Management System. The first creates a text representation of the scanned target’s colour patches:

    scanin -v Epson-Workforce_WF-7520-WFaust-R1.tiff /usr/share/color/argyll/ref/it8.cht IT87/r130227.txt diag.tiff

    The result is a smallish text file Epson-Workforce_WF-7520-WFaust-R1.ti3 which needs one more step to make a standard ICC profile:

    colprof -A Epson -M 'Workforce WF-7520' -D 'WFaust R1' -ax -qm Epson-Workforce_WF-7520-WFaust-R1

    I didn’t quite need to add that much metadata, but I could, so I did. The resultant ICC file can be used to apply colour calibrations to scanned images. Here’s the target scan, corrected:

    Epson-Workforce_WF-7520-WFaust-R1-corrected

    (I’ve made this a mouseover with the original image, so you can see the difference. Also, yes, there is a greasy thumb-print on my scanner glass near the bottom right, thank you so much for noticing.)

    I used tifficc from the Little CMS package to apply the colour correction:

    tifficc -v -i Epson-Workforce_WF-7520-WFaust-R1.icc Epson-Workforce_WF-7520-WFaust-R1.tiff Epson-Workforce_WF-7520-WFaust-R1-corrected.tiff

    There are probably many easier, quicker ways of doing this, but this was the first thing I found that worked.

    To show you a real example, here’s an un-retouched scan of the cover of Algrove Publishing‘s book “All the Knots You Need”, scanned at 75 dpi. Mouseover to see the corrected version:

    all-the-knots-you-need_algrove

    (Incidentally, there are two old but well-linked programs that are out there that purport to do scanner calibration: Scarse and LPROF. Don’t use them! They’re really hard to build on modern systems, and the Argyll tools work well.)

    The last part of my workflow that remains uncalibrated is my printer. I could make a target with Argyll, print it, scan it, colour correct it, then use that as the input to colprof as above. I’m suspecting the results would be mediocre, as my scanner’s bit depth isn’t great, and I’d have to do this process for every paper and print setting combination. I’d also have to work out what magic CUPS does and compensate. Maybe later, but not yet.

  • Using large format paper with Linux and the Epson WorkForce WF-7520 printer

    Update: Nope, I can’t get this to work any more.

    I have an Epson WorkForce WF-7520, and I really like it: excellent built-in duplex large format scanner with ADF, CIFS network storage, giant paper bins, photo quality printing up to 330×482 mm, only slightly expensive print cartridges… Under Linux, though, it’s not so well behaved, especially if you want to print on large format paper. This is the workaround I developed:

    1. Put the B-size/11×17″ paper in Tray 1 (the upper one), and the Letter paper in Tray 2. This, unfortunately, matters — the driver that can print large format can only access the upper tray. On the setup menu on the printer console, tell the printer which tray holds what size of paper.
    2. Install the epson-inkjet-printer-escpr driver; it should be in the standard Ubuntu repos. Define a printer (wf7520-lf, for example) that uses this driver. Set the paper size to “US B 11 x 17 in”.
    3. Ensure that the lsb and lsb-printing packages are installed:
      sudo apt-get install lsb lsb-printing
    4. Download and install the non-free epson-201115w driver from the EPSON Download Center. Define a printer (I used wf-7520 for the name) using this driver, making sure that the correct PPD (epson-inkjet-printer 1.0.0-1lsb3.2 (Seiko Epson Corporation LSB 3.2)) is used. Set it up to use Letter paper, and (important!) set the source to Paper Cassette 2. You might want to make this printer the system default.

    To print to large format, use the command:

    lp -d wf7520-lf -o PageSize=USB file.pdf
    
    

    To print regular size, just send the job to the wf-7520 device.

    (modified from my Ask Ubuntu question/answer: Selecting Large Format Paper: what printing options work?)

    Update for the (rightly) confused: Epson appear to have hoiked US B / 11×17″ support for this printer. Here are my PPDs:

    Copying PPDs from one driver to another may not work, but you’ve likely nothing to lose.

  • ZX Spectrum → Canada

    Ah, the ZX Spectrum… so many hours of my youth wasted on this book-sized computer. Now anything with a display can emulate one in its spare processor cycles, the 30 year old hardware itself is a bit chunky:
    IMG_0623That’s a lot of discrete components; all through-hole, too. I brought this one back from the UK earlier this year in the hope of getting it working.

    First item that needed attention was the power supply. The original had a 230 V AC to 9 V DC, 1.4 A supply of some extremely dodgy regulation. I replace this with a Circuit-Test AC/DC Adapter – 9 V DC 2.2 A, which will have plenty of current. Since the adapter has a 2.1 mm centre positive DC barrel connector, and the Spectrum uses a centre negative connector, I used the soldering opportunity to wire in an inline switch. The Speccy’s famous lack of a power or reset switch really isn’t part of my retrocomputing experience.

    Next up, bypass the UK PAL TV modulator. This required disassembling the computer, and disconnecting the legendarily fragile keyboard membrane edge connectors. It’s a very simple soldering job to re-route the composite video feed (dot crawl and all) from the PCB to the Video Out. Put it all back together, plug it into the TV, and:

    IMG_0971

    … another partial success. My TV doesn’t talk 50 Hz PAL composite well, giving an oversized black and white display. I’ll either need to buy a PAL to NTSC converter box, or spring for a tiny monitor which supports both standards.

  • Artisanal Hardware Random Number Generator

    Artisanal Hardware Random Number Generator

    Artisanal Hardware Random Number Generator — scruss
    (the Flickr page has popup notes about the circuit.)

    Trickles out a few thousand made-with-love organic random numbers per second to the attached Arduino. The circuit is essentially Rob Seward’s True Random Number Generator v1 (after Will Ware, et al) which uses a MAX232 to power two reverse-biased 2N3904s to create avalanche noise. Another 2N3904 amplifies the resulting noise into something an Arduino can sample using AnalogRead(). Many modern processors include hardware RNGs (such as RdRand in recent Intel chipsets) so this circuit is just a toy now.

    My interest in random number generators didn’t just arise from yesterday’s post. I’ve had various circuits breadboarded for months gathering dust, so I thought I’d pull out the most successful one and photograph it. Hardware RNGs seem to be a popular hobby electronics obsession, and there are many designs out there in variable states of “working” and/or “documented”. I wanted one that could be powered from the 5V rail of an Arduino, and didn’t use too many expensive components. Rob’s RNG Version 2 circuit and code is the basis, but I replaced the 12V external supply with the MAX232 circuit he used in version 1.

    Perhaps the reason that there are so many RNG projects out there in various states of abandonment is that making a good, reliable hardware RNG is hard. Just a few of the things you have to think about are:

    • Analogue sources of noise can fade over time; power supplies droop as capacitors age, contacts can corrode, … How do you deal with this fade? If the output becomes so small, can you rely on those few bits from your A→D converter to be useful noise?
    • Could someone try to attack your RNG so they can influence the results of your secure transactions? How would you detect it? How would you signal to the data user that something is amiss securely, such that an attacker couldn’t fake distress behaviour?
    • What if the generator just stops? How do you flag that in a trusted “no really i mean it and it’s really me saying this not some attacker honest no” way? There may still be a tiny bit of noise that your circuit picks up; are you sure it’s your kind of noise, or some attacker trying to inject noise into your system? Remember, testing for real noise is exceptionally hard, and you can’t guarantee that a hardware RNG that worked today will work properly tomorrow.

    (I’d like to thank Peter Todd for providing most of those issues over a pint and a chat during from a keysigning event. Peter saved me from spending too many hours working on this by hinting that — just maybe — I didn’t actually know what I was doing…)

    If you want to read more on how to build a proper hardware RNG, the article “Understanding Intel’s Ivy Bridge Random Number Generator” and its references make a good (if very technical in places) introduction. I’m nowhere near paranoid enough to experiment further with RNG design, although I do have all the components to build an LM393-based XR232USB…

  • “Well, that was unexpected …”: The Raspberry Pi’s Hardware Random Number Generator

    Hey! This is a bit old! Things may have changed and I haven’t necessarily fixed them.

    Most computers can’t create true random numbers. They use a formula which makes a very long stream of pseudo-random numbers, but real randomness comes from thermal noise in analogue components. The Raspberry Pi has such a circuit in its SoC, as it helps making the seed data for secure transactions. It was only recently that a driver for this circuit was supplied. To enable it (on Raspbian): I think the module is enabled by default now for the different versions of the SoC.

    1. Make sure your system is up to date with
      sudo apt-get update
      sudo apt -y upgrade
    2. Install the module:
      sudo modprobe bcm2708-rng
    3. To make sure it’s always loaded, add the following line to /etc/modules (editing as root):
      bcm2708-rng
    4. For some RNG-related stuff, install rng-tools:
      sudo apt-get install rng-tools

    The /dev/hwrng device should now be available, but can only be read by the root user.

    Nico pointed out that you also need to:

    1. Edit /etc/default/rng-tools, and remove the # at the start of the line
      HRNGDEVICE=/dev/hwrng
    2. Restart rng-tools with
      sudo service rng-tools restart

    What random looks like

    random20130606210642random20130606210630

    Random data look pretty dull. Here are random RGB values made with:

    sudo cat /dev/hwrng  | rawtoppm -rgb 256 256 | pnmtopng > random$(date +%Y%m%d%H%M%S).png

    (you’ll need to install the netpbm toolkit to do this.)

    What random sounds like

    Two short WAV samples of, well, noise:

    Yup, sounds like static. It was made with the rndsound.sh script. You’ll need to install sox to run it.

    This is not random

    If it sounds like static, and even if it sometimes looks like static, it may not actually be true random noise. An infamous case of a pseudo random number generator being not very random at all was RANDU, which at first glance appeared to produce nearly random results, but close study showed it to be very predictable.

    I wrote (what I think to be) a C implementation of RANDU: randu.c. While it produces appropriately random-sounding audio data (randu17.wav), if you output it as an image:

    randu17_rgbThose stripes are a giveaway; there should be no order in the output. (Then again, I have no idea if I’ve implemented RANDU correctly.) Testing random data is hard, then — you really need a barrage of tests, and even some of them might fail even for truly random output. Thankfully, when you installed rngtools, it included rngtest, a simple checker for random data:

    sudo cat /dev/hwrng | rngtest -c 1000
    rngtest 2-unofficial-mt.14
    Copyright (c) 2004 by Henrique de Moraes Holschuh
    This is free software; see the source for copying conditions.  There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

    rngtest: starting FIPS tests…
    rngtest: bits received from input: 20000032
    rngtest: FIPS 140-2 successes: 1000
    rngtest: FIPS 140-2 failures: 0
    rngtest: FIPS 140-2(2001-10-10) Monobit: 0
    rngtest: FIPS 140-2(2001-10-10) Poker: 0
    rngtest: FIPS 140-2(2001-10-10) Runs: 0
    rngtest: FIPS 140-2(2001-10-10) Long run: 0
    rngtest: FIPS 140-2(2001-10-10) Continuous run: 0
    rngtest: input channel speed: (min=67.969; avg=921.967; max=1953125.000)Kibits/s
    rngtest: FIPS tests speed: (min=842.881; avg=3208.336; max=6407.890)Kibits/s
    rngtest: Program run time: 27658884 microseconds

    We were lucky that none of the tests failed for that run; sometimes there are a few failures. RANDU, on the other hand fares very badly:

    ./randu 17  | rngtest -c 1000
    rngtest 2-unofficial-mt.14
    Copyright (c) 2004 by Henrique de Moraes Holschuh
    This is free software; see the source for copying conditions.  There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

    rngtest: starting FIPS tests…
    rngtest: bits received from input: 20000032
    rngtest: FIPS 140-2 successes: 0
    rngtest: FIPS 140-2 failures: 1000
    rngtest: FIPS 140-2(2001-10-10) Monobit: 730
    rngtest: FIPS 140-2(2001-10-10) Poker: 1000
    rngtest: FIPS 140-2(2001-10-10) Runs: 289
    rngtest: FIPS 140-2(2001-10-10) Long run: 0
    rngtest: FIPS 140-2(2001-10-10) Continuous run: 0
    rngtest: input channel speed: (min=45.630; avg=14255.221; max=19073.486)Mibits/s
    rngtest: FIPS tests speed: (min=23.694; avg=154.238; max=176.606)Mibits/s
    rngtest: Program run time: 141071 microseconds

    See? Lots of failures there. It’s hardly random at all. If you really want to get out testing randomness, there are the dieharder tests. They takes ages to run, though.

    (Note: newish Intel machines also have a real hardware RNG in the shape of Rdrand.)

    I trust you all got the obvious Strictly Ballroom reference in the title?

  • fixing firefox’s fugly fonts on Ubuntu

    Update 2015-09: Better yet, install Infinality. It makes font rendering pretty.


     

    Switching back to Linux from Mac is still a process of ironing out minor wrinkles. Take, for example, this abomination (enlarged to show texture):—

    Screenshot from 2013-05-19 11:42:18

    … No, I’m not talking about Mr Paul’s antics (or the typo in the TP post, either), but the horrid non-matching ligatures (‘attack’, ‘flubbed’, ‘targeting’) in a sea of blocky text. Almost every programme I was running had this problem. Mouse over the image to see how it could look if you apply this easy fix.

    Create (or edit) the file ~/.fonts.conf ~/.config/fontconfig/conf.d, and add the following lines:

    <match target="font" >
      <edit name="embeddedbitmap" mode="assign">
        <bool>false</bool>
      </edit>
    </match>
    

    Log out, log back in again, and text is properly pretty. Yay!

  • Compose yourself, Raspberry Pi!

    Years ago, I worked in multilingual dictionary publishing. I was on the computing team, so we had to support the entry and storage of text in many different languages. Computers could display accented and special characters, but we were stuck with 8-bit character sets. This meant that we could only have a little over 200 distinct characters display in the same font at the same time. We’d be pretty much okay doing French & English together, but French & Norwegian started to get a little trying, and Italian & Greek couldn’t really be together at all.

    We were very fortunate to be using Sun workstations in the editorial office. These were quite powerful Unix machines, which means that they were a fraction of the speed and capabilities of a Raspberry Pi. Suns had one particularly neat feature:

    Compose_key_on_Sun_Type_5c_keyboard

    (source: Compose key, Wikipedia.)

    That little key marked “Compose” (to the right of the space bar) acted as a semi-smart typewriter backspace key: if you hit Compose, then the right key combination, an accented character or symbol would appear. Some of the straightforward compose key sequences are:

     Compose +  
    AccentFirst keySecond keyResultExample
    Acuteeécafé
    Grave`aàdéjà
    Cedilla,cçsoupçon
    Circumflex^oôhôtel
    Umlautuüküche
    RingoaåHåkon
    Slash/LŁŁukasiewicz
    Tilde~nñmañana

    Like every (non-embedded) Linux system I’ve used, the Raspberry Pi running Raspbian can use the compose key method for entering extra characters. I’m annoyed, though, that almost every setup tutorial either says to disable it, or doesn’t explain what it’s for. Let me fix that for you …

    Setup

    Run raspi-config

    sudo raspi-config

    and go to the configure_keyboard “4 Internationalisation Options” → “I3 Change Keyboard Layout” section. Your keyboard’s probably mostly set up the way you want it, so hit the Tab key and select <Ok> until you get to the Compose key section:

    raspi-config: Compose key selection

    Choose whatever is convenient. The combined keyboard and trackpad I use (a SolidTek KB-3910) with my Raspberry Pi has a couple of “Windows® Logo” keys, and the one on the right works for me. Keep the rest of the keyboard options the same, and exit raspi-config. After the message

    Reloading keymap. This may take a short while
    [ ok ] Setting preliminary keymap...done.

    appears, you now have a working Compose key.

    Using the Compose key

    raspi-config hints (‘On the text console the Compose key does not work in Unicode mode …’) that Compose might not work everywhere with every piece of software. I’ve tested it across quite a few pieces of software — both on the text console and under LXDE — and support seems to be almost universal. The only differences I can find are:

    • Text Console — (a. k. a. the texty bit you see after booting) Despite raspi-config’s warning, accented alphabetical characters do seem to work (é è ñ ö ø å, etc). Most symbols, however, don’t (like ± × ÷ …). The currency symbol for your country is a special case. In Canada, I need to use Compose for  and £, but you’ve probably got a key for that.
    • LXDE — (a. k. a. the mousey bit you see after typing ‘startx’) All characters and symbols I’ve tried work everywhere, in LXTerminal, Leafpad, Midori, Dillo (browser), IDLE, and FocusWriter (a very minimal word processor).
    Special characters in Python's IDLE
    Special characters in Python’s IDLE
    Some Compose key sequences — Leafpad
    Some Compose key sequences — Leafpad

    To find out which key sequences do what, the Compose key – Wikipedia page is a decent start. I prefer the slightly friendlier Ubuntu references GtkComposeTable and Compose Key, or the almost unreadable but frighteningly comprehensive UTF-8 (Unicode) compose sequence reference (which is essentially mirrored on your Raspberry Pi as the file /usr/share/X11/locale/en_US.UTF-8/Compose). Now go forth and work that Compose key like a boß.

    (If you’re on a Mac and feeling a bit left out, you can do something similar with the Option key. Here’s how: Extended Keyboard Accent Codes for the Macintosh. On Windows®? Out of luck, I’m afraid WinCompose!)

  • Mac to Linux: 1Password to KeePassX

    I have too many passwords to remember, so I’ve been using a password manager for years. First there was Keyring for Palm OS, then 1Password on the Mac. 1Password’s a very polished commercial program, but it only has Mac and Windows desktop clients. Sadly, it had to go.

    Finding a replacement was tough. It needed to be free, and yet cross-platform. It needed to work on iOS and Android. It also needed to integrate with a cloud service like Dropbox so I could keep my passwords in sync. The only program that met all of these requirements was KeePassX. I’ve stuck with the stable (v 0.4.3) branch rather than the flashy 2.0 version, as the older database format does all I need and is fully portable. MiniKeePass on iOS and KeePassDroid on Android look after my mobile needs. But first, I needed to get my password data out of 1Password.

    1Password offers two export formats: a delimited text format (which seemed to drop some of the more obscure fields), and the 1Password Interchange Format (1PIF). The latter is a JSONish format (ಠ_ಠ) containing a dump of all of the internal data structures. There is, of course, no documentation for this file format, because no-one would ever move away from this lovely commercial software, no …

    So armed with my favourite swiss army chainsaw, I set about picking the file apart. JSON::XS and Data::Dumper::Simple were invaluable for this process, and pretty soon I had all the fields picked apart that I cared about. I decided to write a converter that wrote KeePassX 1.x XML, since it was readily imported into KeePassX, would could then write a database readable by all of the KeePass variants.

    To run this converter you’ll need Perl, the JSON::XS and Data::Dumper::Simple modules, and if your Perl is older than about 5.12, the Time::Piece module (it’s a core module for newer Perls, so you don’t have to install it). Here’s the code:

    #!/usr/bin/perl -w
    # 1pw2kpxxml.pl - convert 1Password Exchange file to KeePassX XML
    # created by scruss on 02013/04/21
    
    use strict;
    use JSON::XS;
    use HTML::Entities;
    use Time::Piece;
    
    # print xml header
    print <<HEADER;
    <!DOCTYPE KEEPASSX_DATABASE>
    <database>
     <group>
      <title>General</title>
      <icon>2</icon>
    HEADER
    
    ##############################################################
    # Field Map
    #
    # 1Password			KeePassX
    # ============================  ==============================
    # title        			title
    # username			username
    # password			password
    # location			url
    # notesPlain			comment
    #    -				icon
    # createdAt			creation
    #    -				lastaccess	(use updatedAt)
    # updatedAt			lastmod
    #    -				expire		('Never')
    
    # 1PW exchange files are made of single lines of JSON (O_o)
    # interleaved with separators that start '**'
    while (<>) {
        next if (/^\*\*/);    # skip separator
        my $rec = decode_json($_);
    
        # throw out records we don't want:
        #  - 'trashed' entries
        #  -  system.sync.Point entries
        next if ( exists( $rec->{'trashed'} ) );
        next if ( $rec->{'typeName'} eq 'system.sync.Point' );
    
        print '  <entry>', "\n";    # begin entry
    
        ################
        # title field
        print '   <title>', xq( $rec->{'title'} ), '</title>', "\n";
    
        ################
        # username field - can be in one of two places
        my $username = '';
    
        # 1. check secureContents as array
        foreach ( @{ $rec->{'secureContents'}->{'fields'} } ) {
            if (
                (
                    exists( $_->{'designation'} )
                    && ( $_->{'designation'} eq 'username' )
                )
              )
            {
                $username = $_->{'value'};
            }
        }
    
        # 2.  check secureContents as scalar
        if ( $username eq '' ) {
            $username = $rec->{'secureContents'}->{'username'}
              if ( exists( $rec->{'secureContents'}->{'username'} ) );
        }
    
        print '   <username>', xq($username), '</username>', "\n";
    
        ################
        # password field - as username
        my $password = '';
    
        # 1. check secureContents as array
        foreach ( @{ $rec->{'secureContents'}->{'fields'} } ) {
            if (
                (
                    exists( $_->{'designation'} )
                    && ( $_->{'designation'} eq 'password' )
                )
              )
            {
                $password = $_->{'value'};
            }
        }
    
        # 2.  check secureContents as scalar
        if ( $password eq '' ) {
            $password = $rec->{'secureContents'}->{'password'}
              if ( exists( $rec->{'secureContents'}->{'password'} ) );
        }
    
        print '   <password>', xq($password), '</password>', "\n";
    
        ################
        # url field
        print '   <url>', xq( $rec->{'location'} ), '</url>', "\n";
    
        ################
        # comment field
        my $comment = '';
        $comment = $rec->{'secureContents'}->{'notesPlain'}
          if ( exists( $rec->{'secureContents'}->{'notesPlain'} ) );
        $comment = xq($comment);    # pre-quote
        $comment =~ s,\\n,<br/>,g;  # replace escaped NL with HTML
        $comment =~ s,\n,<br/>,mg;  # replace NL with HTML
        print '   <comment>', $comment, '</comment>', "\n";
    
        ################
        # icon field (placeholder)
        print '   <icon>2</icon>', "\n";
    
        ################
        # creation field
        my $creation = localtime( $rec->{'createdAt'} );
        print '   <creation>', $creation->datetime, '</creation>', "\n";
    
        ################
        # lastaccess field
        my $lastaccess = localtime( $rec->{'updatedAt'} );
        print '   <lastaccess>', $lastaccess->datetime, '</lastaccess>', "\n";
    
        ################
        # lastmod field (= lastaccess)
        print '   <lastmod>', $lastaccess->datetime, '</lastmod>', "\n";
    
        ################
        # expire field (placeholder)
        print '   <expire>Never</expire>', "\n";
    
        print '  </entry>', "\n";    # end entry
    }
    
    # print xml footer
    print <<FOOTER;
     </group>
    </database>
    FOOTER
    
    exit;
    
    sub xq {                         # encode string for XML
        $_ = shift;
        return encode_entities( $_, q/<>&"'/ );
    }
    

    To run it,

    ./1pw2kpxxml.pl data.1pif > data.xml

    You can then import data.xml into KeePassX.

    Please be careful to delete the 1PIF file and the data.xml once you’ve finished the export/import. These files contain all of your passwords in plain text; if they fell into the wrong hands, it would be a disaster for your online identity. Be careful that none of these files accidentally slip onto backups, too. Also note that, while I think I’m quite a trustworthy bloke, to you, I’m Some Random Guy On The Internet. Check this code accordingly; I don’t warrant it for anything save for looking like line noise.

    Now on github: scruss / 1pw2kpxxml, or download: 1pw2kpxxml.zip (gpg signature: 1pw2kpxxml.zip.sig)

    SHA1 Checksums:

    • 3c25eb72b2cfe3034ebc2d251869d5333db74592 — 1pw2kpxxml.pl
    • 99b7705ff30a2b157be3cfd29bb1d4f137920c25 — readme.txt
    • de4a51fbe0dd6371b8d68674f71311a67da76812 — 1pw2kpxxml.zip
    • f6bd12e33b927bff6999e9e80506aef53e6a08fa — 1pw2kpxxml.zip.sig.txt

    The converter has some limitations:

    • All attached files in the database are lost.
    • All entries are stored under the same folder, with the same icon.
    • It has not been widely tested, and as I’m satisfied with its conversion, it will not be developed further.
  • Ubuntu on the Samsung Series 7

    My Late 2008 MacBook was getting a little slow, so I went laptop shopping. I ended up with the Samsung Chronos 7 (NP700Z5CH). Under my budget, but met my spec in every way.

    Installing Ubuntu was a minor trial, but it works, and has preserved the Win 8 (blecch!) dual-boot. If it helps anyone, the procedure I followed was:

    • Updated the BIOS, made a recovery DVD and shrank the Windows partition using the DISKPART app (which reminds me so much of the old VMS admin tools).
    • Broadly following the UEFI instructions, I got the 64-bit Linux-Secure-Remix ISO and wrote it to a USB stick with UNetbootin.
    • In the BIOS (F2 when the Samsung logo shows), I disabled Secure Boot and Fast Boot, but kept EFI on, as Win8 won’t work without it. I also disabled (temporarily, with Shift+1) the HD and Windows Boot Manager from the boot sequence, moving USB boot up to first place.
    • After trying Ubuntu from the LiveUSB, I installed it. Once it had finished and rebooted, I re-enabled HD and Windows Boot Manager in the BIOS.
    • Ubuntu would work fine from here, but to restore Win8 to a usable (?) state, I had to reboot with the LiveUSB image and run Boot-Repair as suggested in the UEFI documentation.

    The fan maybe runs a little more than it should, but everything I’ve tried works. There’s clearly been a lot of work done on Samsung/UEFI support recently, as any of the web tutorials I found from even 8 months ago recommended really arcane stuff I didn’t actually need.

    (abstracted from my Reddit query: Linux-friendly future-proof MacBook replacement [13-15″, CA, $1600] : SuggestALaptop)

  • X11-Basic: Compiler Insanity!

    Screen Shot 2013-03-11 at 22.13.31Markus Hoffmann has been very helpful with getting X11-Basic running on the Raspberry Pi. Remember how I said that the simple Mandelbrot Set test took nearly 1¼ hours to run using the interpreter? How about 2′ 6″ when compiled? That’s a speedup of 35 times! What you need to do is:

    xbc -virtualm -o mandel-simple mandel-simple.bas

    The “-virtualm” bit is the secret key to speed. Without it, the compiled code is a bit faster than interpreted.

    If you’re running from the source code posted to SourceForge yesterday, you might want to replace xb2csol.h with this new xb2csol.h. It’s supposed to help with the compiled code. Just make clean; make; sudo make install to replace the code.

  • Running X11-Basic (almost perfectly) on Raspberry Pi

    Update: Markus Hoffmann uploaded a new version of X11Basic-1.20.tar.gz to SourceForge that addresses most of these problems. I’ve edited the article to remove the obsolete bits.


    More than 20 years ago, I really liked GFA-Basic. It ran blindingly fast on the Atari ST, and when it didn’t crash on the Amiga, it ran blindingly fast there too. I even wrote a review of it for comp.sys.amiga.programmer, which you can read to this day in all its textual glory. One of the e-mail addresses in that article still works, too.

    I still sometimes think in BASIC, and there is much wringing of hands (not by me, really) that there isn’t a good interpreter for Raspbian on the Raspberry Pi. So when I found X11-Basic — a cross-platform GFA-Basic-like system — I had to take a look.

    While I have managed to get X11-Basic demos to run, I have to say it’s not running super well. I’ll show you how to install X11-Basic 1.20 and get it (mostly) running, but it’s a bit rough on the ARM. Incidentally, these instructions also work on Ubuntu 12.mumble LTS on x86.

    First, you need to install some (okay, a lot of) packages:

    sudo apt-get install libreadline-dev tcsh libncurses5-dev xutils-dev libc6-dev libsdl1.2-dev libtool

    Now download and extract the package:

    tar xvzf X11Basic-1.20.tar.gz
    cd X11Basic-1.20

    For X11Basic-1.20, you have to issue an extra command before the standard ‘./configure ; make ; make install‘ sequence:

    sudo mkdir -p /usr/local/share/man/man1
    ./configure
    make
    sudo make install

    This is enough to make a working xbasic interpreter. I made some screenshots of some of the graphics demos —

    Screen Shot 2013-03-08 at 16.34.51 Screen Shot 2013-03-08 at 14.59.37 Screen Shot 2013-03-08 at 14.57.21 Screen Shot 2013-03-08 at 14.54.08 Screen Shot 2013-03-08 at 14.49.48As you can see, there’s some screen corruption, but most demos just worked. Incidentally, the Mandelbrot one took almost 1¼ hours to run. Took me right back, that did (or it would have, if I hadn’t been outside bombing about in the slush on my bicycle while it churned away).

    In order to see just how fast the interpreter is, I ran the formerly fearsome Personal Computer World Benchmark #8 under X11-Basic. PCW#8 used to bring 8-bit home computers to their knees, typically taking more than a minute to run. Here’s the code, indented a bit and with a timing wrapper added:

    	LET start=TIMER
    	LET K=0
    L30:
    	LET K=K+1
    	LET A=K^2
    	LET B=LN(K)
    	LET C=SIN(K)
    	IF K<1000
    		GOTO L30
    	ENDIF
    	PRINT TIMER-start
    	QUIT
    

    (yeah, GFA-style BASIC isn’t too pretty …)

    It takes about ¼s to run. The old BBC B was supposed to take about 50s. By comparison, X11-Basic on a manky old dual-core Atom took 0.04s.

    The native compiler xbc seems to work. To make a standalone binary of the above code, you do:

    xbc -o PCWBenchmark PCWBenchmark.xbas

    The compiled binary runs roughly twice as fast as the interpreted code. Not blazing fast, but a useful increase.

    Unfortunately, the bytecode compiler xbbc doesn’t actually do anything on the Raspberry Pi yet. So here I leave it up to you to play with X11-Basic, and see what it can and can’t do.

  • .awesome

    Here are the complete 1988-vintage Sun manuals “Using NROFF and TROFF” and “Formatting Documents” scanned just for you. I’d scanned these in 2000, and they’d sat on a forgotten archive volume since then.

    Update: there are better versions on the Internet Archive: Using NROFF and TROFF and Formatting Documents, all as part of the Sun Microsystems, Inc. manual collection.

    (if you need to get your troff on, go to Ralph’s troff.org.)

  • USB Fart Detector (unfortunately)

    It is a truth universally acknowledged, that an engineer in possession of a solid-state flammable gas detector, will shortly make a fart detector with it. I’m sorry, but call it childishness, simple-minded curiosity, or the results of a diet high in polysaccharides, but this is something I have to get out of my system. (It’s okay; I’ll waft the door.)

    This all started when our carbon monoxide detector decided it was past its best, and started to emit an ear-splitting shriek. Thinking there might be some cool parts inside, I took it apart. Inside, in amongst the other stuff, I found this:

    gas sensor boardThankfully, David Cook of Robot Room had once had the same idea as me (well, minus the puerile bits), and he documented the sensor board very well: Explosive Gas Detector Board. Here are the four pins that you really need to get the thing going:

     Pin # (from left)    Function
    ===================  ==========
           1              Vcc
           2              /Enable
           3              /Gas
           5              Gnd

    Pins 2 and 3 are active low signals. To be typographically correct, I’d write them as Enable and Gas, but that’s hard to do in fixed-pitch ASCII. I can understand why the Gas signal should be active low (think about it; if the Figaro TGS 2611 sensor fails or shorts, it will likely fail to an alarm state, so you’ll still be alive to curse the bloody noise that woke you at 03h00), but the Enable being active low? Dunno.

    I was hoping to have presented a little sketch for the Digispark that would have typed something unhelpful every time that gas was detected, but it was not to be. It seems that Macs and Digispark keyboard emulation is a thing of great wobbliness, so I had to resort to an Arduino and a serial connection.

    Here’s the code:

    /*
     gas_detector - uses board scavenged from CO detector
     
     scruss - 2013-02-18 (unfortunately)
     */
    
    int gas     = 2;               // /Gas line on pin 2
    int val     = 0;
    int lastval = 0;
    
    void setup() {                
      pinMode(gas, INPUT);
      Serial.begin(115200);
    }
    
    void loop() {
      val = digitalRead(gas);
      if (val != lastval) {
        if (val == LOW) {          // LOW means gas detected
          Serial.println("gas");
          Serial.println();
          delay(1000);             // wait 1s for air to clear
        }
      }
      lastval = val;
    }
    

    Before you ask, I tested the circuit by briefly hitting the button on a gas lighter. Honest.

    I’ll keep working on the Digispark; it’s such a nifty little device, and this is such a worthy project …

  • A Murder of Crows on your Raspberry Pi with Boodler

    Boodler is rather fun. It generates ambient music based on user-defined or downloaded ‘soundscapes’. If you’ve got a modern (HTML5/Opus-capable) browser, you can hear a streaming demo here: http://repeater.xiph.org:8000/clock.opus. It’s using the FM3 Buddha Machine samples in this demo, but it can run lots more: a tree full of crows, a thunderstorm, dripping water, …

    It’s pretty easy to run on a Raspberry Pi running a recent version of Raspbian. The only technical glitch I had was that there’s something deeply confused about ALSA sound handling on the Raspberry Pi. I’m sure it’ll get fixed soon, but for now, you have to use PulseAudio. (If you want to read about my ALSA woes, go here.)

    The installation prerequisites are simple:

    sudo apt-get install pulseaudio pulseaudio-utils libpulse-dev python-dev

    Now download and configure Boodler:

    wget http://boodler.org/dl/Boodler-2.0.4.tar.gz
    tar xvzf Boodler-2.0.4.tar.gz
    cd Boodler-2.0.4
    python setup.py build

    It takes a while to do this, but make sure it does something useful when it’s building the various sound drivers. You don’t want it to say:

    skipping 'boodle.cboodle_pulse' extension

    If it says that, you haven’t installed Pulseaudio. Go back and check your apt-get line.

    Once it’s built, now install it:

    sudo python setup.py install

    Now test it:

    boodler --hardware --output pulse --testsound

    Not merely should you get some pleasant tones from your Raspberry Pi’s audio, but you sound get some informative and non-threatening terminal output. Mine looks like:

    Boodler: PulseAudio sound driver.
     PulseAudio library: 2.0.0.
     Sample rate is 44100 fps.
     Samples are 16-bit little-endian.
     Buffer size is 32768.
     21:37:46 (root) Running "Boodler test sound"

    If that works, let’s get those crows a-cawin’. Download the soundscapes you need:

    boodle-mgr install http://boodler.org/lib/org.boodler.old.crow.1.0.boop
    boodle-mgr install http://boodler.org/lib/com.eblong.zarf.crows.1.0.boop

    and run it:

    boodler --output pulse com.eblong.zarf.crows/ParliamentOfCrows

    Crows everywhere!

    I really like the Buddha Machine samples. It’s quite big (> 80 MB), so this next set will take a while to download:

    boodle-mgr install  http://boodler.org/lib/com.azulebanana.buddhamachine.1.5.1.boop
    boodle-mgr install http://boodler.org/lib/com.azulebanana.buddhaagent.1.5.1.boop

    It’s worth the wait:

    boodler --output pulse com.azulebanana.buddhaagent/ChangingLoops

    Boodler has tons of options, prebuilt packages, and instructions to build your own: Boodler Documentation.

    One thing I’ve tried to get working, but failed, is streaming from Boodler via icecast. Sure, I can install and run it, it’s just that the results are, um, undesirable. If you want to have a play, here’s how to install icecast:

    sudo apt-get install icecast2 ices2 libshout3-dev

    Icecast will configure itself, and ask for a couple of passwords. You’ll have to rebuild and reinstall Boodler for it to catch the new configuration. You can then try streaming:

    boodler --output shout --define shout-password=mypassword --define shout-mount='/boodler-buddha.ogg' com.azulebanana.buddhaagent/ChangingLoops

    If you open a web browser at this address http://raspberrypi:8000/ you should see a config page listing your boodler-buddha.ogg stream. Click on the M3U link next to it, and your streaming music player should start making a joyful noise …

    … except in my case, something went very wrong, and it started to produce industrial ultra-glitch nightmare noise: boodler-streaming_test-fail. I’m sure it’s fixable with some tweaking, but I’m not there yet.

  • X10 for Raspberry Pi on the Cheap [North American Edition]

    Now I’ve got my X10 system running and know its limitations, I could have saved a wheen of money not buying stuff I don’t need. Our house appears to have been wired by an, um, spirited amateur, so powerline signalling is of limited use. Thankfully, the tiny and cheap X10 FireCracker CM17A (warning: too many flashing GIFs at this link!) can be driven from heyu [previously]. You can score these on eBay for under $10, and all you need is a serial adapter to drive them.

    Leviton X10 controller - cheap!The really cheap bit in my system was discovered in Active Surplus. I found a case of Leviton “Plug-in Frequency Transceiver Modules” for $4/each. One was out of its case, and wouldn’t you know it, it’s the same as a RR501 module, which typically retails for about $30. Sure, these are old stock and are a nasty beige colour, but they provide a way of switching a two-pin appliance. They can also relay remote commands from RF to wired controls.

    The only X10 controller I can’t get to work with the Raspberry Pi is the CM19a USB PC Transceiver. I suspect it draws a bit too much power to run from a Raspberry Pi, as it makes the machine unresponsive if it’s plugged it. Running from my bench setup it works fine with the mochad driver, but no dice with the other machine. The CM19a reads wireless RF X10 commands, and it would be useful if I’d added a motion sensor. As is, I’ll stick to the lights going on and off.

    (Update: there’s a good chance that my CM19a problems are down to the ancient dwc_otg* fixes I still run on my Raspberry Pi’s kernel. You probably don’t need them, and this device could work fine. One day I will find time to fix ’em …)

    (Incidentally, this is the “North American Edition” because X10 RF controls are completely different in Europe, and none of the above is useful to you. Yeah, I know this article is the equivalent of PC Load Letter to you; sorry.)

  • Simple ADC with the Raspberry Pi

    Raspberry Pi wearing an MCP3008

    Hey! This is a really old article. You should really be using gpiozero these days.

    I hadn’t realised it, but the The Quite Rubbish Clock did something that a lot of people seem to have trouble with on the Raspberry Pi: communicating using hardware SPI. Perhaps it’s because everything is moving so fast with Raspberry Pi development, tutorials go out of date really quickly. Thankfully, hardware SPI is much easier to understand than the older way of emulation through bit-banging.

    SPI is a synchronous serial protocol, so it needs a clock line as well as a data in and data out line. In addition, it has a Chip Enable (CE, or Chip Select, CS) line that is used to choose which SPI device to talk to. The Raspberry Pi has two CE lines (pins 24 and 26) so can talk to two SPI devices at once. It supports a maximum clock rate of 32 MHz, though in practice you’ll be limited to the rate your device supports.

    The device I’m testing here is an MCP3008 10-bit Analogue-to-Digital Converter (ADC). These are simple to use, cheap and quite fast converters with 8 input channels. If you hook them up to a 3.3 V supply they will convert a DC voltage varying from 0-3.3 V to a digital reading of 0-1023 (= 210 – 1). Not quite up there in quality for hi-fi audio or precision sensing, but good enough to read from most simple analogue sensors.

    The sensor I’m reading is the astonishingly dull LM35DZ temperature sensor. All the cool kids seem to be using TMP36s (as they can read temperatures below freezing without a negative supply voltage). One day I’ll show them all and use a LM135 direct Kelvin sensor, but not yet.

    To run this code, install the SPI libraries as before. Now wire up the MCP3008 to the Raspberry Pi like so:

     MCP 3008 Pin          Pi GPIO Pin #    Pi Pin Name
    ==============        ===============  =============
     16  VDD                 1              3.3 V
     15  VREF                1              3.3 V
     14  AGND                6              GND
     13  CLK                23              GPIO11 SPI0_SCLK
     12  DOUT               21              GPIO09 SPI0_MISO
     11  DIN                19              GPIO10 SPI0_MOSI
     10  CS                 24              GPIO08 CE0
      9  DGND                6              GND

    The wiring for the LM35 is very simple:

     LM35 Pin        MCP3008 Pin
    ==========      =============
     Vs              16 VDD
     Vout             1 CH0
     GND              9 DGND

    The code I’m using is a straight lift of Jeremy Blythe’s Raspberry Pi hardware SPI analog inputs using the MCP3008. The clever bit in Jeremy’s code is the readadc() function which reads the relevant length of bits (by writing the same number of bits; SPI’s weird that way) from the SPI bus and converting it to a single 10-bit value.

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    # mcp3008_lm35.py - read an LM35 on CH0 of an MCP3008 on a Raspberry Pi
    # mostly nicked from
    #  http://jeremyblythe.blogspot.ca/2012/09/raspberry-pi-hardware-spi-analog-inputs.html
    
    import spidev
    import time
    
    spi = spidev.SpiDev()
    spi.open(0, 0)
    
    def readadc(adcnum):
    # read SPI data from MCP3008 chip, 8 possible adc's (0 thru 7)
        if adcnum > 7 or adcnum < 0:
            return -1
        r = spi.xfer2([1, 8 + adcnum << 4, 0])
        adcout = ((r[1] & 3) << 8) + r[2]
        return adcout
    
    while True:
        value = readadc(0)
        volts = (value * 3.3) / 1024
        temperature = volts / (10.0 / 1000)
        print ("%4d/1023 => %5.3f V => %4.1f °C" % (value, volts,
                temperature))
        time.sleep(0.5)
    

    The slightly awkward code temperature = volts / (10.0 / 1000) is just a simpler way of acknowledging that the LM35DZ puts out 10 mV (= 10/1000, or 0.01) per °C. Well-behaved sensors generally have a linear relationship between what they indicate and what they measure.

    If you run the code:

    sudo ./mcp3008_lm35.py

    you should get something like:

      91/1023 => 0.293 V => 29.3 °C
      93/1023 => 0.300 V => 30.0 °C
      94/1023 => 0.303 V => 30.3 °C
      95/1023 => 0.306 V => 30.6 °C
      96/1023 => 0.309 V => 30.9 °C
      97/1023 => 0.313 V => 31.3 °C
      97/1023 => 0.313 V => 31.3 °C
      98/1023 => 0.316 V => 31.6 °C
      99/1023 => 0.319 V => 31.9 °C
      99/1023 => 0.319 V => 31.9 °C
     100/1023 => 0.322 V => 32.2 °C
     100/1023 => 0.322 V => 32.2 °C
     100/1023 => 0.322 V => 32.2 °C
     101/1023 => 0.325 V => 32.5 °C
     101/1023 => 0.325 V => 32.5 °C
     102/1023 => 0.329 V => 32.9 °C
     102/1023 => 0.329 V => 32.9 °C
     103/1023 => 0.332 V => 33.2 °C

    Note that the sensor had been sitting over the Raspberry Pi’s CPU for a while; I don’t keep my house at 29 °C. I made the temperature go up by holding the LM35.

    So, you’ve just (fairly cheaply) given your Raspberry Pi 8 analogue input channels, so it can behave much more like a real microcontroller now. I remember from my datalogging days that analogue inputs can be pretty finicky and almost always return a value even if it’s an incorrect one. Check the chip’s datasheet to see if you’re doing it right, and if in doubt, meter it!

  • qrclock, the demo reel

    classy cable for the Quite Rubbish clock

    The video of the Quite Rubbish Clock isn’t running the same code that’s in the listing. Here it is, showing off some of the handy code that’s in bgreat’s nokiaSPI Python class:

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    # qrmovie
    
    import time
    # need to use git://github.com/mozillazg/python-qrcode.git
    import qrcode
    from PIL import Image, ImageFont
    import ImageOps
    # uses bgreat's SPI code; see
    # raspberrypi.org/phpBB3/viewtopic.php?f=32&t=9814&p=262274&hilit=nokia#p261925
    import nokiaSPI
    
    noki = nokiaSPI.NokiaSPI()              # create display device
    qr = qrcode.QRCode(version=1,           # V.1 QR Code: 21x21 px
    error_correction=qrcode.constants.ERROR_CORRECT_M,
    box_size=2, border=1)
    bg = Image.new('1', (84, 48))           # blank (black) image background
    
    # intro
    noki.cls()
    noki.led(0)
    time.sleep(3)
    for i in range(0,769,32):
        noki.led(i)
        time.sleep(0.04)
    
    # display is 14 columns by 8 rows
    noki.centre_word(1, 'scruss.com')
    noki.centre_word(3, 'presents')
    time.sleep(3)
    noki.cls()
    noki.centre_word(1, 'qrclock')
    noki.centre_word(2, 'the')
    noki.gotorc(3,3)
    noki.text("[Q]uite")
    noki.gotorc(4,3)
    noki.text("[R]ubbish")
    noki.gotorc(5,3)
    noki.text(" Clock")
    time.sleep(3)
    
    elapsed=0
    start_time = time.time()
    while (elapsed<12):
        qr.clear()
        newbg = bg.copy()                   # copy blank background
        s = time.strftime('%Y-%m-%d %H:%M:%S')
        qr.add_data(s)                      # make QR Code of YYYY-MM-DD HH:MM:SS
        qr.make()
        qrim = qr.make_image()              # convert qrcode object to PIL image
        qrim = qrim.convert('L')            # make greyscale
        qrim = ImageOps.invert(qrim)        # invert colours: B->W and W->B
        qrim = qrim.convert('1')            # convert back to 1-bit
        newbg.paste(qrim, (18, 0))          # paste QR Code into blank background
        noki.show_image(newbg)              # display code on LCD
        time.sleep(0.4)                     # pause before next display
        elapsed = time.time() - start_time
    
    noki.cls()
    noki.centre_word(1, 'for')
    noki.centre_word(2, 'more')
    noki.centre_word(3, 'details')
    time.sleep(3)
    noki.cls()
    noki.load_bitmap("blogpost-nokia.bmp", True)
    time.sleep(7)
    noki.cls()
    noki.centre_word(3, 'fin')
    noki.centre_word(5, 'scruss, 2013')
    time.sleep(1)
    for i in range(768,-1,-32):
        noki.led(i)
        time.sleep(0.05)
    time.sleep(1)
    noki.cls()
    

    (This source, plus nokiaSPI class: qrclock-movie.zip)

    Lines 43-58 show off the QR clock for a maximum of 12 seconds. Any more, and you’d get really bored.

    The screen handling functions I used are:

    • cls() — Clears the screen.
    • led(brightness) — sets the backlight to brightness. For me, full brightness is at 768. A value of zero turns the backlight off. If you don’t have the screen LED connected to one of the Raspberry Pi’s PWM pin, this will either be full on (for any brightness >= 1), or off, for brightness=0. This is used to fade up the screen in lines 24-26, and fade it down far too theatrically in lines 72-74.
    • show_image(PILImage) — display a single bit depth black and white Python Imaging Library object PILImage. This can be no larger than 84×48 pixels.
    • load_bitmap(file, Invert) — load a single bit depth black and white BMP file of maximum size 48×84. If Invert is true, keep the colours as they are, otherwise swap black and white to make a negative image. nokiSPI flips images by 90°, so the image I loaded to show the URL of the blog post looks like this:
      blogpost-nokia
      (I know, I could have generated this in code, but I’d already made the image using qrencode. I couldn’t be bothered working out the image size and offsets.)

    The text handling functions I used are:

    • gotorc(row, column) — move the text cursor to row, column. The screen only has 14 columns by 8 rows if you use the standard 6×6 pixel font, so keep your text short to avoid disappointment.
    • text(text) — write text at the current cursor position.
    • centre_word(row, text) — write text centred in row row. Since the text rows are a maximum of 14 columns, text with an odd number of characters will appear slightly off-centre.

    There are many more functions in the nokiaSPI class; watch the demo, have a dig through the source and see what you can use.

  • The Quite Rubbish Clock

    Hey! This article is really old and probably doesn’t work any more: things have changed a lot in Raspberry Pi world since 2013

    Update 3: code for the demo video is here.

    Update 2: In which I actually post working code.

    Update: Eep! This post was featured on the Raspberry Pi blog today. Thanks, Liz!

    And now for something completely different:

    … a clock that isn’t human readable. You’ll need a QR code reader to be able to tell the time.

    Nokia screen on Raspberry Pi

    This, however, is not the prime purpose of the exercise. I was looking for an excuse to try some direct hardware projects with the GPIO, and I remembered I had a couple of Nokia-style surplus LCDs lying about that could be pressed into service. These LCDs aren’t great: 84×48 pixels, 3V3 logic, driven by SPI via an 8-pin header which includes PWM-controllable LED backlighting. They are cheap, and available almost everywhere: DealExtreme ($5.36), SparkFun ($9.95), Adafruit ($10, but includes a level shifter, which you really need if you’re using a 5V logic Arduino), Solarbotics ($10) and Creatron (about $12; but you can walk right in and buy one). Despite being quite difficult to use, helpful people have written drivers to make these behave like tiny dot-addressable screens.

    I’d been following the discussion on the Raspberry Pi forum about driving the Nokia LCD from a Raspberry Pi. Only when user bgreat posted some compact code that was supposed to run really fast did I dig out the LCD board and jumper wires. Building on bgreat’s nokiaSPI.py class and a few other bits of code, here’s what I built to make this singularly pointless clock:

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    # qrclock - The Quite Rubbish Clock for Raspberry Pi - scruss, 2013-01-19
    
    import time
    # need to use git://github.com/mozillazg/python-qrcode.git
    import qrcode
    from PIL import Image
    import ImageOps
    # uses bgreat's SPI code; see
    # raspberrypi.org/phpBB3/viewtopic.php?f=32&amp;amp;amp;amp;t=9814&amp;amp;amp;amp;p=262274&amp;amp;amp;amp;hilit=nokia#p261925
    import nokiaSPI
    
    noki = nokiaSPI.NokiaSPI()              # create display device
    qr = qrcode.QRCode(version=1,           # V.1 QR Code: 21x21 px
                       error_correction=qrcode.constants.ERROR_CORRECT_M,
                       box_size=2, border=1)
    bg = Image.new('1', (84, 48))           # blank (black) image background
    
    while 1:
        qr.clear()
        newbg = bg.copy()                   # copy blank background
        s = time.strftime('%Y-%m-%d %H:%M:%S')
        qr.add_data(s)                      # make QR Code of YYYY-MM-DD HH:MM:SS
        qr.make()
        qrim = qr.make_image()              # convert qrcode object to PIL image
        qrim = qrim.convert('L')            # make greyscale
        qrim = ImageOps.invert(qrim)        # invert colours: B-&amp;amp;amp;gt;W and W-&amp;amp;amp;gt;B
        qrim = qrim.convert('1')            # convert back to 1-bit
        newbg.paste(qrim, (18, 0))          # paste QR Code into blank background
        noki.show_image(newbg)              # display code on LCD
        time.sleep(0.4)                     # pause before next display
    

    (Convenient archive of all the source: qrclock2.zip, really including bgreat’s nokiaSPI class this time …)

    To get all this working on your Raspberry Pi, there’s a fair amount of configuration. The best references are bgreat’s own comments in the thread, but I’ve tried to include everything here.

    Enabling the SPI kernel module

    As root, edit the kernel module blacklist file:

    sudo vi /etc/modprobe.d/raspi-blacklist.conf

    Comment out the spi-bcm2708 line so it looks like this:

    #blacklist spi-bcm2708

    Save the file so that the module will load on future reboots. To enable the module now, enter:

    sudo modprobe spi-bcm2708

    Now, if you run the lsmod command, you should see something like:

    Module                  Size  Used by
    spi_bcm2708             4421  0

    Installing the WiringPi, SPI and other required packages

    WiringPi by Gordon is one of the neater Raspberry Pi-specific modules, as it allows relatively easy access to the Raspberry Pi’s GPIO pins. For Raspbian, there are a few other imaging libraries and package management tools you’ll need to install here:

    sudo apt-get install python-imaging python-imaging-tk python-pip python-dev git
    sudo pip install spidev
    sudo pip install wiringpi

    Installing the Python QR code library

    Finding a library that provided all the right functions was the hardest part here. I ended up using mozillazg‘s fork of lincolnloop‘s python-qrcode module. mozillazg’s fork lets you use most of the lovely PIL methods, while the original hides most of them. Since I had to do some image compositing and colour remapping to make the image appear correct on the Nokia screen, the new fork was very helpful.

    To install it:

    git clone git://github.com/mozillazg/python-qrcode.git
    cd python-qrcode/
    sudo python ./setup.py install

    The tiny 84×48 resolution of the Nokia screen doesn’t give you many options for sizing QR codes. For the time display of the clock, a 21×21 module Version 1 code with two pixels per module and one module margin just fits into 48 pixels. Using a medium level of error correction, you can fit the 19-character message (such as “2013-01-19 18:56:59”) into this tiny screen with a very good chance of it being read by any QR code reader.

    (In the video, there’s a much larger QR code that’s a link to this blog post. That’s a Version 7 code [45×45 modules] at one pixel per module and no margin. This doesn’t meet Denso Wave’s readability guidelines, but the Nokia screen has large blank margins which seem to help. It won’t read on every phone, but you’re here at this link now, so you don’t need it …)

    Wiring it all up

    (Do I really need to say that you’ll be messing around with the inner delicate bits of your Raspberry Pi here, and if you do something wrong, you could end up with a dead Raspberry Pi? No? Okay. Just make sure you take some static precautions and you really should have the thing shut down and powered off.)

    You’ll need 8 female-female right-angled ones). Note that the thick border of the LCD is the top of the screen. These boards are made who-knows-where by who-knows-whom, and there’s a huge variety of labels and layouts on the pins. My one appears to be yet another variant, and is labelled:

    1. VCC
    2. GND
    3. SCE
    4. RST
    5. D/C
    6. DNK(MOSI)
    7. SCLK
    8. LED
    screen labels

    This is how I wired it (from comments in bgreat’s code and the GPIO reference):

     LCD Pin       Function      Pi GPIO Pin #   Pi Pin Name
    ============= ============= =============== =============
     1 VCC         Vcc            1              3.3 V
     2 GND         Ground        25              GND
     3 SCE         Chip Enable   24              GPIO08 SPI0_CE0_N
     4 RST         Reset         11              GPIO17
     5 D/C         Data/Command  15              GPIO22
     6 DNK(MOSI)   Data In       19              GPIO10 SPI0_MOSI
     7 SCLK        Serial Clock  23              GPIO11 SPI0_SCLK
     8 LED         Backlight     12              GPIO18 PWM0
    GPIO wiring
    back of screen

    Wire it up, and fire up the program:

    sudo ./qrclock.py

    Yes, code that accesses GPIO needs to be run as root. Pesky, but helps you avoid running code that accidentally scrams the nuclear power station you’re controlling from your Raspberry Pi …

  • Too many QR Codes

    I have, of late, been rather more attached to QR Codes than might be healthy. I’ve been trying all sorts of sizes and input data, printing them, and seeing what camera phones can scan them. I tried three different devices to scan the codes:

    • iPhone 4s – 8 MP, running either i-nigma (free) or Denso Wave’s own QRdeCODE ($2). QRdeCODE is better, but then, it should be, since it was created by the developer of the QR Code standard.
    • Nexus 7 – 1.2 MP, running Google Goggles.
    • Nokia X2-01Catherine‘s new(ish) phone, which I can’t believe only has a 0.3 MP VGA camera on it. Still, it worked for a small range of codes.

    QR Code readability is defined by the module size; that is, the number of device pixels (screen or print) that represent a single QR Code pixel. Denso Wave recommends that each module is made up of 4 or more dots. I was amazed that the iPhone could read images with a module size of 1 from the screen, like this one:

    hello_____-ei-m01-300dpi

    On this laptop, one pixel is about 0.24 mm. The other cameras didn’t fare so well on reading from the screen:

    • iPhone 4s – Min module size: 1-2 pixels (0.24-0.48 mm/module)
    • Nexus 7 – Min module size: 2-3 pixels (0.48-0.72 mm/module)
    • Nokia X2-01 – Min module size: 3-4 pixels (0.72-0.96 mm/module)

    So I guess for screen scanning, Denso Wave’s recommendation of 4 pixels/module will pretty much work everywhere.

    I then generated and printed a bunch of codes on a laser printer, and scanned them. The results were surprisingly similar:

    • iPhone 4s – Min module size: 3-4 dots (0.25-0.34 mm/module)
    • Nexus 7 – Min module size: 4-5 dots (0.34-0.42 mm/module)
    • Nokia X2-01 – Min module size: 8-9 dots (0.68-0.76 mm/module)

    A test print on an inkjet resulted in far less impressive results. I reckon you need to make the module size around 25% bigger on an inkjet than a laser, perhaps because the inkjet is less crisp.

    I have to admit I went a bit nuts with QR Codes. I made a Vcard: my vcard

    (and while I was at it, I created a new field for ham radio operators: X-CALLSIGN. Why not?). I even encoded some locations in QR Codes.

    Just to show you what qrencode can do, here’s a favourite piece of little prose:

    a_real_man