A blog Write an awesome description for your new site here. You can edit this line in _config.yml. It will appear in your document head meta (for Google search results) and in your feed.xml site description. http://yourdomain.com/ Fri, 30 Nov 2018 22:22:05 +0000 Fri, 30 Nov 2018 22:22:05 +0000 Jekyll v2.5.3 Serial LIRC devices on recent Ubuntu releases <p>I tried to get a “homebrew” infrared receiver attached to the DCD line of a serial port working on Ubuntu Bionic. It seems that things have changed since Ubuntu 12.04, when I last had it working.</p> <p>The changes ended up being:</p> <ul> <li>The kernel modules are in the mainline kernel, but aren’t supplied with Ubuntu</li> <li>The LIRC driver’s name has changed from “serial” to “default”</li> </ul> <p>My first problem is that the receiver wasn’t working in the first place. I attached a DSO Nano to the data line, and noticed that the signal didn’t have a high enough voltage to trigger the serial port. The <a href="https://www.mouser.com/ds/2/348/rpm6900-313874.pdf">data sheet</a> shows the receiver’s output being a pull-up resistor with a transistor pulling the output low; maybe this serial port draws a particularly large amount of current. I wired a 2.2k resistor between the data line and VCC (which should be within the limits of the receiver), and everything works.</p> <p>I tested it with this program, which displays a time when the DCD line changes:</p> <pre><code>#include &lt;stdio.h&gt; #include &lt;unistd.h&gt; #include &lt;sys/types.h&gt; #include &lt;sys/stat.h&gt; #include &lt;fcntl.h&gt; #include &lt;sys/ioctl.h&gt; #include &lt;termios.h&gt; #include &lt;stdlib.h&gt; #include &lt;string.h&gt; #include &lt;errno.h&gt; #include &lt;time.h&gt; int die(const char* msg) { perror(msg); printf("%s\n", strerror(errno)); exit(1); } int main(void) { int fd = open("/dev/ttyS0", 0); if (fd == -1) die("open"); while (1) { struct timespec tm; ioctl(fd, TIOCMIWAIT, TIOCM_CD | TIOCM_RNG | TIOCM_DSR | TIOCM_CTS); if (clock_gettime(CLOCK_MONOTONIC, &amp;tm) == -1) die("clock_gettime"); printf("%ld\n", tm.tv_nsec); } close(fd); return 0; } </code></pre> <p>(So why does LIRC need the kernel driver, if this works in userspace? I suspect it’s because the LIRC API requires a timeout, which the <code>ioctl</code> doesn’t support.)</p> <p>LIRC’s serial port support works by using a kernel module to read the hardware, and sends the output to <code>/dev/lirc0</code>. LIRC connects to this device to read the input. The LIRC userspace driver that does this is called “default” (it used to be called “serial”).</p> <p>It seems a few releases ago the drivers were upstreamed, and aren’t supplied with Ubuntu. I got the driver installed with DKMS:</p> <ol> <li>Create a working directory</li> <li>Put the <a href="https://elixir.bootlin.com/linux/v4.15.18/source/drivers/media/rc/serial_ir.c">driver</a> in it. (Choose the appropriate version for your kernel.)</li> <li> <p>Add this Makefile:</p> <pre><code> obj-m += serial_ir.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean </code></pre> </li> <li> <p>Add this <code>dkms.conf</code>:</p> <pre><code> PACKAGE_NAME="lirc_serial_ir" PACKAGE_VERSION="4.15" CLEAN="rm -f *.*o" BUILT_MODULE_NAME[0]="serial_ir" DEST_MODULE_LOCATION[0]="/updates" AUTOINSTALL="no" </code></pre> </li> <li>Run <code>sudo dkms add .</code></li> <li>Run <code>sudo dkms install lirc_serial_ir/4.15</code>.</li> </ol> <p>Now run <code>sudo modprobe lirc_serial</code>. Run <code>dmesg</code>, and you should see:</p> <pre><code>[ 1627.908509] serial_ir serial_ir.0: port 03f8 already in use [ 1627.908515] serial_ir serial_ir.0: use 'setserial /dev/ttySX uart none' [ 1627.908516] serial_ir serial_ir.0: or compile the serial port driver as module and [ 1627.908517] serial_ir serial_ir.0: make sure this module is loaded first [ 1627.908532] serial_ir: probe of serial_ir.0 failed with error -16 </code></pre> <p>To fix this, install the “setserial” package, and <a href="http://www.lirc.org/html/configuration-guide.html#serial_port_reservation">disable the serial port as the instructions say</a>.</p> <p>Try running mode2, and press some buttons on the remote:</p> <pre><code>$ sudo mode2 --driver default Using driver default on device auto Trying device: /dev/lirc0 Using device: /dev/lirc0 Running as regular user space 504574 pulse 9015 space 4548 pulse 488 </code></pre> Wed, 28 Nov 2018 00:00:00 +0000 http://yourdomain.com/posts/2018/11/28/lirc-ubuntu-bionic/ http://yourdomain.com/posts/2018/11/28/lirc-ubuntu-bionic/ Sub 50 cent microcontrollers <p><a href="https://jaycarlson.net/microcontrollers/">$1 microcontrollers</a>, pfft. What useful ones are around for under 50 cents?</p> <p>The qualifications:</p> <ul> <li>There needs to be adequate documentation</li> <li>Programmamble with readly available (and cheap) hardware. This rules out a lot of ones from Megawin, Sinowealth and so on; while they have reasonable user manuals, there’s no information on how to program them, short of buying a $20 programmer.</li> <li>Are readily available. I ruled out parts only available from Taobao, for instance.</li> </ul> <p>I was left with these:</p> <ul> <li>The STM8S103. They’re not <em>the</em> cheapest, but are readily available in the West. There’s a cheaper STM8S003, but its flash is rated to only 100 writes, so it sounds like the idea is to develop for the S103 first.</li> <li>The Nuvoton N76E003. It has loads of peripherals, and is pin compatible with the STM8S103.</li> <li>The STC microcontrollers. Not quite as much bang for buck as the Nuvoton, and unavailable in the West, but come in 8 pin packages.</li> </ul> <p>The Atmel ATtiny13 also qualifies, but I already know how to program those!</p> <p>All should be programmable using <a href="http://sdcc.sourceforge.net/">SDCC</a>, and either a ST-Link or USB-Serial dongle. I’ve purchased development boards for the <a href="https://www.aliexpress.com/item/STM8S103F3P6-System-Board-STM8S-STM8-Development-Board-Minimum-Core-Board/32885918852.html">STM8</a>, <a href="https://www.aliexpress.com/item/51-Development-Board-N76E003AT20-Development-Board-System-Board-Core-Board-N76E003/32898770085.html">Nuvoton</a> and a <a href="https://www.aliexpress.com/item/STC15W204S-SCM-Minimum-System-Board-Development-Board-51-SOP8-STC15F104E/32899351974.html">STC15W204</a>. I hope to try these out and write about them.</p> Wed, 24 Oct 2018 00:00:00 +0000 http://yourdomain.com/posts/2018/10/24/sub-50c-microcontrollers/ http://yourdomain.com/posts/2018/10/24/sub-50c-microcontrollers/ Schematic for the "Bustodephon" brushed motor electronic speed controller (ESC) <p>I tried drawing the schematic for the common “Bustophedon” electronic speed controllers (ESC) for brushed motors.</p> <div class="content-image"> <a href="/images/bustodephonschematic.png"> <img src="/generated/400-bustodephonschematic.png" alt="" srcset=" /generated/400-bustodephonschematic.png 400w, /images/bustodephonschematic.png 1028w" sizes="400px" /> </a> </div> <p>The circuit is fairly straightforward to follow. The zener diode based regulator for the receiver power is a bit surprising - I would have thought another regulator would have been cheap enough instead of several components. I’m guessing the separate supply is to shield the microcontroller from the receiver, especially since it would be easy to supply power from another ESC.</p> <p>The microcontroller has no markings, but there <a href="https://www.lcsc.com/product-detail/_PMS153_C129129.html">are</a> <a href="https://www.lcsc.com/product-detail/_SN8P2501D-SOP-14_C80639.html">several</a> very cheap microcontrollers which have a suitable pinout.</p> <p>I’ll have to analyze the microcontroller’s output to see whether it does anything special.</p> Thu, 13 Sep 2018 00:00:00 +0000 http://yourdomain.com/posts/2018/09/13/brushed-bustophedon-esc-schematic/ http://yourdomain.com/posts/2018/09/13/brushed-bustophedon-esc-schematic/ The FlySky iBus protocol <p>This is the FlySky iBus protocol that I’ve gleaned from <a href="https://basejunction.wordpress.com/2015/08/23/en-flysky-i6-14-channels-part1/">a blog post</a> and a <a href="https://github.com/aanon4/FlySkyIBus">single library</a>.</p> <p>Data is transmitted as serial UART data, 115200bps, 8N1. A message is sent every 7 milliseconds. <a href="https://www.banggood.com/818CH-Mini-Receiver-With-PPM-iBus-SBUS-Output-for-Flysky-i6-i6x-AFHDS-2A-Transmitter-p-1183313.html">My receiver</a> sends this over its white wire, and stops sending a few tenths of a second after the transmitter is switched off (unlike the PPM signal on the yellow wire, which keeps sending its last value).</p> <p>The first byte is 0x20, the second is 0x40.</p> <p>Next are 14 pairs of bytes, which is the channel value in little endian byte order. The FS-i6 is a 6 channel receiver, so it fills in the first 6 values. The remainder are set to 0x05DC. My transmitter sends values between 0x3E8 and 0x7D0.</p> <p>Finally a 2 byte checksum is sent. It’s in little endian byte order, it starts at 0xFFFF, from which every byte’s value is subtracted except for the checksum.</p> <p>I’ve written <a href="https://github.com/33d/ibus-library">a library</a> to decode this data. An Arduino could measure the time of the message start to improve detection of the message start. One problem using an Arduino is that the board will interfere with programming - a resistor (maybe 10k) on the data line should help.</p> Sun, 22 Oct 2017 00:00:00 +0000 http://yourdomain.com/posts/2017/10/22/flysky-ibus-protocol/ http://yourdomain.com/posts/2017/10/22/flysky-ibus-protocol/ Build a Jekyll blog with Travis CI without granting write access <p>With the demise of Openshift Online and its free tier, I was looking for somewhere else to host my blog. Even though it’s a <a href="https://jekyllrb.com/">Jekyll</a> blog, it does some image resizing, so I can’t use Github’s native builder. I should be able to use <a href="https://travis-ci.org/">Travis CI</a> though, then push them to another Github repository for <a href="https://help.github.com/categories/github-pages-basics/">Pages</a> hosting.</p> <p>The <a href="https://docs.travis-ci.com/user/deployment/pages/">Travis instructions for Github Pages</a> instructions suggest you use Github personal access tokens for authentication, but that seems to give write access to all of my Github repositories - which I don’t want to do.</p> <p>You will need the <a href="https://github.com/travis-ci/travis.rb">command line client</a> installed and logged in.</p> <ol> <li> <p>Generate a key pair for Travis to use when pushing</p> <pre><code> ssh-keygen -t rsa -b 4096 -f travis-key </code></pre> <p>Don’t commit the generated files!</p> </li> <li> <p>Create a repository on Github for the generated site to be pushed to. In that repository, go to Settings, Deploy keys, then Add deploy key. Copy in <code>travis-key.pub</code> which you generated in the previous step, check “Enable write access”, then add the key.</p> </li> <li> <p>The private key should be <a href="https://docs.travis-ci.com/user/encrypting-files/">encrypted</a>. From the blog repository:</p> <pre><code> travis encrypt-file -r 33d/blog travis-key </code></pre> <p>where <code>travis-key</code> is one of the files created earlier by <code>ssh-keygen</code>.</p> <p>This command will suggest you add a line to your <code>before_install</code> section - do that.</p> </li> <li> <p>Put at the end of <code>.travis.yml</code>’s <code>before_install</code>, to stop <code>ssh-add</code> complaining about the key’s permissions:</p> <pre><code> - chmod 400 ../travis-key </code></pre> </li> <li> <p>Add this to <code>.travis.yml</code>, to perform the Git push:</p> <p><code> after_success: - eval "$(ssh-agent -s)" - ssh-add ../travis-key - git clone git@github.com:33d/blog-pages.git target - cp -pr _site/* target - git -C target checkout -b gh-pages - git -C target add . - git -C target commit -m "$( date --utc --iso-8601=seconds )" - git -C target push --force origin gh-pages </code></p> <p>I use a different repository for this, because I don’t want the build artifacts clogging the blog repository.</p> </li> </ol> <p>You can see <a href="https://github.com/33d/blog/blob/blog/.travis.yml">my completed <code>.travis.yml</code> file</a>.</p> Sun, 08 Oct 2017 00:00:00 +0000 http://yourdomain.com/posts/2017/10/08/jekyll-blog-travis-ci/ http://yourdomain.com/posts/2017/10/08/jekyll-blog-travis-ci/ Check that your flash memory isn't fake <p>Here’s how I’ve checked that my flash memory (USB stick, SD card etc) isn’t fake. The idea is to use a cipher to produce a psuedorandom stream, write its output to the flash memory, then genenrate the stream again comparing it to the card.</p> <p>First, find out how big the flash is:</p> <pre><code>$ cat /proc/paritions major minor #blocks name ... 8 16 30736384 sdb </code></pre> <p>Some quick maths tells me the block size is 1024 bytes. Next, use <code>openssl</code> to encrypt some zeroes, writing the output to the card:</p> <pre><code>$ dd if=/dev/zero bs=1024 count=30736384 | openssl enc -aes128 -k some-passworrd -nosalt | sudo tee /dev/sdb &gt; /dev/null 30736384+0 records in 30736384+0 records out 31474057216 bytes (31 GB) copied, 989.076 s, 31.8 MB/s tee: /dev/sdb: No space left on device </code></pre> <p>I don’t know why it complains about no space, but the number of bytes written looks correct.</p> <p>(Change some-password to some other word.) <code>-nosalt</code> prevents openssl writing a header, which contains the password salt. Because our encryption key (the <code>some-password</code> above) doesn’t need to be secure, we don’t care about it, and will stop the same stream being output next time.</p> <p>Now check the result:</p> <pre><code>$ dd if=/dev/zero bs=1024 count=30736384 | openssl enc -aes128 -k some-password -nosalt | sudo cmp - /dev/sdb 30736384+0 records in 30736384+0 records out 31474057216 bytes (31 GB) copied, 367.183 s, 85.7 MB/s cmp: EOF on /dev/sdb </code></pre> <p>If it hits the end without complaining about differences, what’s on the card is what was produced again by the cipher stream, so the card contains the advertised flash chip.</p> Sat, 11 Jul 2015 00:00:00 +0000 http://yourdomain.com/posts/2015/07/11/check-for-fake-flash/ http://yourdomain.com/posts/2015/07/11/check-for-fake-flash/ Save space used by an Ubuntu VM by using the live CD, the slightly easier way <p>Yesterday I worked out how to use the Ubuntu live CD to save space on Ubuntu VMs. It turns out you don’t need to change <code>initrd.lz</code>.</p> <p>Instead, all of the options in <code>casper.conf</code> except <code>root_persistence</code> can be specified on the kernel command line - simply add them (without the quotes) to <code>extlinux.conf</code>.</p> <ol> <li>Create a virtual machine with a hard disk of your choosing. Boot the Ubuntu live CD in it.</li> <li>Create a partition on the virtual hard disk for persistence, and make it bootable.</li> <li> <p>Format it, give it a label:</p> <pre><code>$ sudo bash # mkfs.ext2 /dev/sda1 -L overlay </code></pre> </li> <li> <pre><code># mount /dev/sda1 /mnt </code></pre> </li> <li> <pre><code># mkdir /mnt/boot </code></pre> </li> <li> <pre><code># cp -p /cdrom/casper/vmlinuz.efi /mnt/boot </code></pre> </li> <li> <p>We need to <a href="https://wiki.ubuntu.com/CustomizeLiveInitrd">edit <code>/etc/casper.conf</code> inside the initrd</a>:</p> <pre><code># cd /tmp # mkdir i # cd i # lzcat /cdrom/casper/initrd.lz | cpio -i </code></pre> <p>now put in /tmp/i/etc/casper.conf (I found out the variables by looking through <a href="http://bazaar.launchpad.net/~ubuntu-branches/ubuntu/trusty/casper/trusty/view/head:/scripts/casper"><code>/usr/share/initramfs-tools/scripts/casper</code></a>, which is run by the kernel command line’s <code>boot</code> parameter.):</p> <pre><code># This file should go in /etc/casper.conf # Supported variables are: # USERNAME, USERFULLNAME, HOST, BUILD_SYSTEM, FLAVOUR export USERNAME="user" export USERFULLNAME="Live session user" export HOST="vm" export BUILD_SYSTEM="Ubuntu" # USERNAME and HOSTNAME as specified above won't be honoured and will be set to # flavour string acquired at boot time, unless you set FLAVOUR to any # non-empty string. export FLAVOUR="Ubuntu" export PERSISTENT="Yes" export root_persistence="overlay" </code></pre> <p>You can customize your username and host name in this file too. Note <code>root_persistence</code> is the label we specified in step 3. Now compress the initramfs:</p> <pre><code># cd /tmp/i # find . | cpio --quiet --dereference -o -H newc | lzma -7 &gt; /mnt/boot/initrd.lz </code></pre> </li> <li> <p>Now for a bootloader which uses the above stuff. Install the extlinux package. I grabbed the .deb <a href="http://packages.ubuntu.com/trusty/extlinux">from the package search</a>.</p> </li> <li> <p>Install extlinux:</p> <pre><code># mkdir /mnt/boot/extlinux # extlinux -i /mnt/boot/extlinux </code></pre> <p>Put this in <code>/mnt/boot/extlinux/extlinux.conf</code>:</p> <pre><code>DEFAULT linux LABEL linux KERNEL /boot/vmlinuz.efi APPEND boot=casper initrd=/boot/initrd.lz noprompt </code></pre> </li> <li> <p>The hard disk is probably missing a master boot record.</p> <pre><code># dd if=/usr/lib/syslinux/mbr.bin of=/dev/sda </code></pre> </li> <li>Unmount <code>/mnt</code> and reboot.</li> </ol> Wed, 22 Apr 2015 00:00:00 +0000 http://yourdomain.com/posts/2015/04/22/save-space-used-by-an-ubuntu-vm-mk-ii/ http://yourdomain.com/posts/2015/04/22/save-space-used-by-an-ubuntu-vm-mk-ii/ Save space used by an Ubuntu VM by using the live CD <p>I like to use VMs when doing things which might put stuff all over the filesystem or needs root access to install. But at a few gigabytes each they quickly take up space. I managed to use the live CD image as a base, which is compressed and can be shared among virtual machines.</p> <ol> <li>Create a virtual machine with a hard disk of your choosing. Boot the Ubuntu live CD in it.</li> <li>Create a partition on the virtual hard disk for persistence, and make it bootable.</li> <li> <p>Format it, give it a label:</p> <pre><code>$ sudo bash # mkfs.ext2 /dev/sda1 -L overlay </code></pre> </li> <li> <pre><code># mount /dev/sda1 /mnt </code></pre> </li> <li> <pre><code># mkdir /mnt/boot </code></pre> </li> <li> <pre><code># cp -p /cdrom/casper/vmlinuz.efi /mnt/boot </code></pre> </li> <li> <p>We need to <a href="https://wiki.ubuntu.com/CustomizeLiveInitrd">edit <code>/etc/casper.conf</code> inside the initrd</a> (<em>Edit</em>: You don’t need to do this; see the end of the post):</p> <pre><code># cd /tmp # mkdir i # cd i # lzcat /cdrom/casper/initrd.lz | cpio -i </code></pre> <p>now put in /tmp/i/etc/casper.conf (I found out the variables by looking through <a href="http://bazaar.launchpad.net/~ubuntu-branches/ubuntu/trusty/casper/trusty/view/head:/scripts/casper"><code>/usr/share/initramfs-tools/scripts/casper</code></a>, which is run by the kernel command line’s <code>boot</code> parameter.):</p> <pre><code># This file should go in /etc/casper.conf # Supported variables are: # USERNAME, USERFULLNAME, HOST, BUILD_SYSTEM, FLAVOUR export USERNAME="user" export USERFULLNAME="Live session user" export HOST="vm" export BUILD_SYSTEM="Ubuntu" # USERNAME and HOSTNAME as specified above won't be honoured and will be set to # flavour string acquired at boot time, unless you set FLAVOUR to any # non-empty string. export FLAVOUR="Ubuntu" export PERSISTENT="Yes" export root_persistence="overlay" </code></pre> <p>You can customize your username and host name in this file too. Note <code>root_persistence</code> is the label we specified in step 3. Now compress the initramfs:</p> <pre><code># cd /tmp/i # find . | cpio --quiet --dereference -o -H newc | lzma -7 &gt; /mnt/boot/initrd.lz </code></pre> </li> <li> <p>Now for a bootloader which uses the above stuff. Install the extlinux package. I grabbed the .deb <a href="http://packages.ubuntu.com/trusty/extlinux">from the package search</a>.</p> </li> <li> <p>Install extlinux:</p> <pre><code># mkdir /mnt/boot/extlinux # extlinux -i /mnt/boot/extlinux </code></pre> <p>Put this in <code>/mnt/boot/extlinux/extlinux.conf</code>:</p> <pre><code>DEFAULT linux LABEL linux KERNEL /boot/vmlinuz.efi APPEND boot=casper initrd=/boot/initrd.lz noprompt </code></pre> </li> <li> <p>The hard disk is probably missing the master boot record code, so write that.</p> <pre><code># dd if=/usr/lib/syslinux/mbr.bin of=/dev/sda </code></pre> </li> <li>Unmount <code>/mnt</code> and reboot.</li> </ol> <p><em>Edit:</em> It turns out you don’t need to change <code>initrd.lz</code>.</p> <p>Instead, all of the options in <code>casper.conf</code> except <code>root_persistence</code> can be sp ecified on the kernel command line - simply add them (without the quotes) to <code>ex tlinux.conf</code>, like this:</p> <pre><code>APPEND boot=casper initrd=/boot/initrd.lz noprompt username=user hostname=host </code></pre> <p>You also need to label your hard disk partition <code>casper-rw</code>.</p> Tue, 21 Apr 2015 00:00:00 +0000 http://yourdomain.com/posts/2015/04/21/save-space-used-by-an-ubuntu-vm/ http://yourdomain.com/posts/2015/04/21/save-space-used-by-an-ubuntu-vm/ Back up the flash of a Huawei Mediapad 7 Lite <p>I recently purchased a Huawei Mediapad 7 Lite 4GB very cheaply on clearance. It’s based on a Rockchip RK2918, which there are tools for to read and write the flash directly. Before I start trying to hack it, I should get a backup of what’s already on it.</p> <p>I found <a href="http://valentijn.sessink.nl/?p=382">a post</a> which describes how the flash of a different Rockchip tablet can be backed up. Maybe I can catch the USB device being recognized as I restart the tablet.</p> <p>So, in one terminal:</p> <pre><code>tail -f /var/log/kern.log </code></pre> <p>and then turn off the tablet. The battery charge screen appears, and there’s nothing useful yet.</p> <p>So I held down Volume + and the power button, the screen goes blank. So I switched it off. But wait: in the kernel log:</p> <pre><code>Aug 24 22:29:24 xpee kernel: [ 2187.324056] usb 1-5: new high-speed USB device number 7 using ehci-pci Aug 24 22:29:25 xpee kernel: [ 2187.869050] usb 1-5: unable to get BOS descriptor Aug 24 22:29:25 xpee kernel: [ 2187.869674] usb 1-5: New USB device found, idVendor=2207, idProduct=290a Aug 24 22:29:25 xpee kernel: [ 2187.869681] usb 1-5: New USB device strings: Mfr=0, Product=0, SerialNumber=0 </code></pre> <p>and a quick search for vendor 2207… Rockchip! Interesting…</p> <p>Following <a href="http://valentijn.sessink.nl/?p=382">the post mentioned earlier</a>:</p> <pre><code>$ sudo ./rkflashtool r 0x0000 0x2000 &gt; dump^C $ strings dump PARM FIRMWARE_VER:0.2.3 MACHINE_MODEL:MediaPad 7 Lite MACHINE_ID:007 MANUFACTURER:HUAWEI MAGIC: 0x5041524B ATAG: 0x60000800 MACHINE: 2929 CHECK_MASK: 0x80 KERNEL_IMG: 0x60408000 COMBINATION_KEY: 0,6,A,1,0 CMDLINE: console=ttyS1,115200n8n androidboot.console=ttyS1 init=/init initrd=0x62000000,0x800000 mtdparts=rk29xxnand:0x00002000@0x00002000(misc),0x00004000@0x00004000(kernel),0x00008000@0x00008000(boot),0x00008000@0x00010000(recovery),0x00002000@0x00018000(backup),0x00006000@0x0001a000(oeminfo),0x00004000@0x00020000(vrcb),0x00008000@0x00024000(reserved),0x00100000@0x0002c000(cust),0x000e6000@0x0012c000(system),0x00080000@0x00212000(cache),0x00008000@0x00292000(userdata),0x00002000@0x0029a000(kpanic),-@0x0029c000(user) </code></pre> <p>I notice that this text appears several times, so I’d better keep this in mind.</p> <p>The <a href="https://www.kernel.org/doc/menuconfig/drivers-mtd-Kconfig.html#MTD_CMDLINE_PARTS">Linux MTD documentation describes what <code>mtdparts</code> is for</a>. So after copying the <code>mtdparts</code> bit to a file, with a bit of Perl magic I can dump each “part” to a file:</p> <pre><code>$ perl -pe 's/([0-9a-fx-]*)@([a-f0-9x]*)\(([a-z]*)\).?/\2 \1 \3\n/g' &lt; mtdparts | while read off len name ; do sudo ./rkflashtool r $off $len 2&gt;/dev/null | xz &gt; $name.xz ; done </code></pre> <p>But what about the last one, which lists the size as <code>-</code>? I’ll try reading a block which shouldn’t exist:</p> <pre><code>$ sudo ./rkflashtool r 0xfffffffd 1 | hexdump -C </code></pre> <p>It doesn’t seem to matter what I change the offset to, it seems to output part of the first block at some seemingly arbitrary offset. Also, the offset seems to be the start offset in 512 byte blocks, but trying to read one block returns 0x4000 bytes of data. Looking at <a href="http://sourceforge.net/p/rkflashtool/Git/ci/2bd62daeb5e63f4f1f92d1876b053a2be8cf428c/tree/rkflashtool.c#l248">the source</a> suggests that it reads blocks of 0x4000 bytes, so that’s the minimum it’s going to return. I tried hacking the code to fail <a href="http://sourceforge.net/p/rkflashtool/Git/ci/2bd62daeb5e63f4f1f92d1876b053a2be8cf428c/tree/doc/protocol.txt#l46">if the error flag in the response</a> is set, but that didn’t help.</p> <p>But <a href="http://sourceforge.net/p/rkflashtool/Git/ci/2bd62daeb5e63f4f1f92d1876b053a2be8cf428c/tree/doc/protocol.txt#l94">the bottom of the protocol description lists a FlashInfo structure</a>, which contains the number of blocks of flash, but I notice that command hasn’t been implemented. I hope they didn’t leave it out because it bricks devices… (<a href="https://github.com/33d/rkflashtool/commit/3955541b14adbb8ad55198e870165752a52e4271">hack hack hack</a>) I tried implementing it, but got this:</p> <pre><code>$ sudo ./rkflashtool l | hexdump -C 00000000 00 00 80 00 00 08 08 18 21 04 01 00 00 00 00 00 |........!.......| 00000010 44 4e 41 4e 20 01 65 00 02 00 00 00 01 01 01 00 |DNAN .e.........| 00000020 01 01 18 21 04 10 08 70 00 10 00 00 00 08 00 00 |...!...p........| 00000030 00 01 00 00 00 00 10 00 00 00 80 00 00 00 80 00 |................| 00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00000060 00 00 00 00 00 00 00 00 30 00 10 80 d0 60 70 00 |........0....`p.| 00000070 30 60 10 80 d0 60 70 00 80 80 78 00 78 00 15 80 |0`...`p...x.x...| 00000080 85 00 e0 05 e0 06 10 85 35 00 00 00 00 00 00 00 |........5.......| 00000090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00000200 </code></pre> <p>No permutations of those first 6 bytes and their endianness seem to produce anything useful, so I’ll try something else.</p> <p>Maybe <code>/proc/mtd</code> will yield some secrets:</p> <pre><code>1|shell@android:/ $ cat /proc/mtd dev: size erasesize name mtd0: 00400000 00004000 "misc" mtd1: 00800000 00004000 "kernel" mtd2: 01000000 00004000 "boot" mtd3: 01000000 00004000 "recovery" mtd4: 00400000 00004000 "backup" mtd5: 00c00000 00004000 "oeminfo" mtd6: 00800000 00004000 "vrcb" mtd7: 01000000 00004000 "reserved" mtd8: 20000000 00004000 "cust" mtd9: 1cc00000 00004000 "system" mtd10: 10000000 00004000 "cache" mtd11: 01000000 00004000 "userdata" mtd12: 00400000 00004000 "kpanic" mtd13: 9a800000 00004000 "user" </code></pre> <p>Everything in the “size” column seems to be 512*what was listed in <code>mtdparts</code>. This makes the <code>user</code> part 0x4D4000 long. I can finally back up that part:</p> <pre><code>$ sudo ./rkflashtool r 0x0029c000 0x4d4000 2&gt;user.log | xz &gt; user.xz </code></pre> <p>I ran <code>fsck.ext4 -c</code> on the result, and it was happy, so I guess I have the right length.</p> <p>But I think it might be better to just grab the whole lot:</p> <pre><code>$ sudo ./rkflashtool r 0 0x800000 2&gt;all.log | xz &gt; all.xz </code></pre> <p>where 0x800000 is 4GB/512, and is a bit bigger than the 0x0029c000+0x4d4000 that I calculated earlier. I can verify various parts:</p> <pre><code>$ diff &lt;(xzcat user.xz | dd bs=512 ) &lt;( xzcat all.xz | dd bs=512 count=$((0x4d4000)) skip=$((0x29c000)) ) 5062656+0 records in 5062656+0 records out 2592079872 bytes (2.6 GB) copied, 56.8184 s, 45.6 MB/s 5062656+0 records in 5062656+0 records out 2592079872 bytes (2.6 GB) copied, 56.8161 s, 45.6 MB/s </code></pre> <p><code>diff</code> produced no output, so the data are the same. I’ll keep a copy of <code>all.xz</code> and the output from <code>./rkflashtool p</code> and <code>cat /proc/mtd</code>, which will let me recover whatever I need to.</p> Mon, 25 Aug 2014 00:00:00 +0000 http://yourdomain.com/posts/2014/08/25/huawei-mediapad-7-lite-backup/ http://yourdomain.com/posts/2014/08/25/huawei-mediapad-7-lite-backup/ Running a Z-machine on an AVR <p>Can you make a <a href="http://en.wikipedia.org/wiki/Z-machine">Z-machine</a> console - a virtual machine for text adventure games -  complete with screen and keyboard on an AVR?</p> <p>No. Well, probably not on a ATmega328P.</p> <p>I <a href="ftp://sunsite.unc.edu/pub/Linux/games/textrpg/zipinfocm-2.0.linux.tar.gz">got the code for ZIP</a>, and stripped out all of the code for reading files and displaying stuff on the screen.  This let me compile it with avr-gcc.</p> <p>I looked at the result of objdump:</p> <pre><code>$ avr-objdump -h zip_linux zip_linux:     file format elf32-avr Sections: Idx Name          Size      VMA       LMA       File off  Algn   0 .data         000001e4  00800100  0000579c  00005830  2**0                   CONTENTS, ALLOC, LOAD, DATA   1 .text         0000579c  00000000  00000000  00000094  2**1                   CONTENTS, ALLOC, LOAD, READONLY, CODE   2 .bss          00000ac8  008002e4  008002e4  00005a14  2**0                   ALLOC   3 .stab         0000dcec  00000000  00000000  00005a14  2**2                   CONTENTS, READONLY, DEBUGGING   4 .stabstr      00003aad  00000000  00000000  00013700  2**0                   CONTENTS, READONLY, DEBUGGING   5 .comment      00000022  00000000  00000000  000171ad  2**0                   CONTENTS, READONLY </code></pre> <p>The good news is that the code (the .text section) fits into 22k.  That leaves 10k for the screen rendering code (probably from <a href="http://www.batsocks.co.uk/products/Other/TellyMate.htm">TellyMate</a>), the keyboard and the SD card code.</p> <p>The .data section is quite small too, which means there aren’t many strings in the interpreter itself.</p> <p>The problem is the .bss section, which gets copied to RAM on startup.  It’s 2760 bytes, much more than the 2048 which this chip has.</p> <p>Let’s look at this further:</p> <pre><code>$ avr-objdump -t zip_linux | grep bss | sort -t $'\t' -k 2 ... 0080030c g     O .bss    00000004 pc 00800da6 g     O .bss    00000006 __iob 00000114 g       .text    00000010 __do_clear_bss 00800552 g     O .bss    0000004e lookup_table 00800436 l     O .bss    00000100 record_name 00800332 l     O .bss    00000100 save_name 008005a0 g     O .bss    00000800 stack </code></pre> <p>There’s a 2048 byte stack, which fills the entire memory!  The Infocom games <a href="http://www.gnelson.demon.co.uk/zspec/sect06.html">might only need a 1k stack</a>, which will help.</p> <p>Tellymate has a 38x25 screen, which needs 950 bytes.  This could be brought down to 10 lines, but games might be tricky to play.  The ZX80 didn’t store a full line if it didn’t fill the width of the screen, but adventure games tend to be wordy so this won’t help much.</p> <p>An SD card library needs about 600 bytes of RAM, which blows the budget.  We’d have to go without a filesystem on the SD card, because it takes up too much flash space.  It sounds like the 512 byte buffer might be optional.</p> <p>4k of RAM should be plenty.  But with ARM chips being much cheaper than the larger AVRs, that might be the way to go - if I can sort out the <a href="http://sourcegate.wordpress.com/2012/11/04/code-to-produce-video-signals-on-the-stm32l-discovery/">jittering image problems</a>.</p> <p>You might be able to squeeze the interpreter only onto the chip, and communicate with it via its serial port, or another AVR running TellyMate.</p> <p><strong>Update:</strong> It turns out I wasn’t the only one to look at this - Rossum <a href="http://rossumblog.com/2011/04/19/zork-for-the-microtouch/">implemented it on the 2560-byte ATmega32U4</a>, but needed to store a 1MB swap file on the SD card!  I don’t know why you need that much - maybe you don’t - but I forgot to include dynamic memory and room for the stack.</p> Sun, 06 Apr 2014 06:44:08 +0000 http://yourdomain.com/posts/2014/04/06/running-a-z-machine-on-an-avr/ http://yourdomain.com/posts/2014/04/06/running-a-z-machine-on-an-avr/ advenure arduino avr infocom text tv video z-machine