Tuesday, 29 January 2019

How to get fall through behaviour in bash case statements

As many people know C has the famous (or infamous) fall through behaviour in switch statements. Is something similar available for bash?

Indeed, just look at the man page:

Using ;& in place of ;; causes execution to continue with the list associated with the next set of patterns. Using ;;& in place of ;; causes the shell to test the next pattern list in the statement, if any, and execute any associated list on a successful match.

In other words, where you would leave out the break; in C you would write ;& instead of ;; in bash. Hope you have a good use case for it (sorry for the pun).

Wednesday, 23 January 2019

Upgrading DVD burner firmware from Linux via a VirtualBox VM

I was given a TSSTcorp SH-224DB DVD burner. This has a SATA interface. The firmware revision shown in dmesg was SB00. I decided to update this to SB01, the last available. Problem was the file was a Win32 executable. How to run this from Linux?

The drive in question is connected to my Linux machine via a USB to SATA dongle. I have a Windows XP VM so I decided to see if it could access the drive. The first time I tried connecting the drive which appeared as /dev/sr1 to the VM. The update executable said it couldn't find any suitable drive.

After some reading I tried another tack, I allowed XP to access the dongle via USB forwarding. This time running the update executable found the drive and duly updated the firmware.

The first attempt didn't work because VirtualBox was presenting a virtual DVD to the VM. But what the program wanted was access to the SATA interface, albeit via the USB layer.

This may work for other drives for which only a Windows executable is available.

Wednesday, 16 January 2019

MPLABX 5.0 IDE error: (1180) directory "build/default/production" does not exist

Posting this so that people can find the solution.

I experienced the same problem as posted here where compilation would fail with this error if the project file is on a network drive, a NFS mount in my case. Running make in the directory from the CLI got the same error. Strange to say, the fix of copying it to a local directory worked.

I don't know what the root cause is but this is another thing you could try.

Thursday, 27 December 2018

k3b, mkisofs, and hard linked files

As it's the end of the year, I decided to back up photos from my trips onto DVD. A du -sh of the directories showed that they would fit onto a standard DVD. But when I went to create the image in k3b, it wanted a double layer DVD.

I knew what the problem was, in those albums I had made heavy use of hard links to provide multiple access paths to photos without using extra disk space.

Checking the man page of mkisofs showed that there were a pair of options, --cache-inodes and the negative form. I added this option to the arguments passed by k3b to mkisofs and bingo, the space of the image halved, even though the preview claimed that it required almost 8GiB of DVD.

Looking at the verbose output of k3b on the terminal showed that --no-cache-inodes is the default, presumably to avoid problems with dumping filesystems that don't have working inodes.

Thursday, 20 December 2018

Travails installing openSUSE on Samsung 2012 Chromebook (Snow)

I have a 2012 Chromebook made by Samsung, codenamed Snow. I like this machine as it is light, has a decent sized screen, and is suited for travel. Google stopped issuing updates to ChromeOS for this Chromebook in July 2018. So I was pleased to see that openSUSE Linux developers had issued builds for this hardware. For one thing I might be able to do things on the Chromebook not possible from ChromeOS.

So I went to the wiki page that had instructions for preparing boot media for it. First thing I had to do was enable developer mode. I lost my personalisation of the Chromebook but I didn't have much anyway, and most of the config was backed up to the cloud.

Ever optimistic, I chose the Leap KDE build image. I got it to boot and then the troubles began. I needed to get a network connection to update the packages, and this needed to be set up from the desktop. But the Plasma desktop kept crashing. Most of the time it would restart by itself after a hiatus at the desktop. But sometimes the machine froze and the only to get out was by turning off the machine by holding down the power button. On power up, sometimes it wouldn't boot far enough to show kernel messages and then it was power off again. Perhaps it was trying to repair the filesystem and I should have waited longer, but I did wait a long time. Finally I managed to download all the updates, some 600 packages in all. But by this time the machine wouldn't boot up anymore. Perhaps the CPU had overheated.

After a rest for the machine and for me, I decided I was too ambitious so I tried the JeOS (Just enough OS) image. Unfortunately this turned out to be NQeOS (Not Quite enough OS) as it didn't boot to a GUI. I might have been able to configure the WLAN interface from the command line but IHeOI (I Had enough Of It).

So I decided to try booting the LXQT image, I reasoned that perhaps without Plasma the desktop would be more stable. After quite a few tries and retries with the WLAN interface, I managed to fetch all the update packages, some 570 IIRC, and I installed them with zypper up -y from the CLI.

Then there was some to and fro with NetworkManager and wickedd. I decided to go for wickedd as this works at boot rather than when the user logs in on the desktop. But both were active after install causing some clashes.

So I have a desktop of sorts which can stay up for a while. I may keep LXQT, even though I'm used to KDE on my desktop, because this is a low RAM machine (1GB) after all.

But here's the main problem: after all that work I could not locate some key packages like a web browser, e.g. Firefox. Perhaps it's in a repo I don't know about, certainly it's not in the main repos. Looks like these builds are for people who are willing to experiment and not ready for normal usage. In retrospect perhaps I should have tried a Tumbleweed image as this might have all the updates to build date rolled in. I also see there's are experimental 15.1 builds which I might try and report back.

Other approaches I could have tried are Crouton, which keeps the kernel used by ChromeOS but runs applications over it. I don't know if this can be installed on a SD card. To the openSUSE developers' credit, getting a boot image which supports all of the peripherals I needed is a fair achievement. There is Internet documentation on how to install Debian on it but there is a lot of cross compilation and manual configuration.

The main motivation for installing a Linux distro on the Chromebook is to be able to get access to things like VPN software with a decent sized desktop and multiple terminal windows. But this motivation has faded a bit as I don't need as much to connect to my home or work machines during travels. If I do, my smartphone, with its 4GB RAM, and lots of VPN apps under Android, coupled with a Bluetooth keyboard, is much more capable, with the caveat that the display is smaller, even though the resolution is higher. So that only leaves local development when on the road as a rationale for carrying a Linux enabled Chromebook.

Wednesday, 7 November 2018

sizeof operator in C and C++ should be better known

Having seen some code examples on the Internet where sizeof should be used, I thought I'd offer a short reminder of a couple of useful cases:

1. A EPROM burner program to run on Arduino where the data was embedded as a byte array in the sketch which is then compiled and downloaded to run:

What was written:

const int progSize = 1024;
const byte hexProg[progSize] = { ... };
...
for (i = 0; i < progSize; i++) {
...
}

What should have been written:

const byte hexProg[] = { ... };
...
for (i = 0; i < sizeof(hexProg); i++) {
...
}

This has the advantage of automatically adapting to the number of bytes that actually need to be programmed instead of always 1024.

2. An Arduino program to test a LCD display:

What was written:

char row1[] = "I'm Arduino";
...
for (int positionCounter1 = 0; positionCounter1 < 26; positionCou
nter1++) {


This prints junk after the greeting because it strays past the end of the string, which is also a security hazard.

What should have been written:

for (int positionCounter1 = 0; positionCounter1 < sizeof(row1) - 1; positionCounter1++) {

The - 1 is to not print the NUL byte at the end of the string. A reminder, if the string is say UTF-8, sizeof gives the number of bytes in the string, not the number of characters. But usually the number of bytes is what you want.

Also do not make this mistake:

char *row1 = "I'm Arduino";

In this case sizeof(row1) will be sizeof(char *) on the machine, not the length of the phrase I'm Arduino.

A couple of other idioms.

Getting the number of elements in an array:

int divisors[] = { 2273, 2145, 2025, 1911, ... };
const int ndivisors = sizeof(divisors)/sizeof(int);

Or even better:

const int ndivisors = sizeof(divisors)/sizeof(divisors[0]);

which means you can change the type of the divisors array to be other than an int without changing the second line.

Allocating the right amount of memory from heap:

double *readings;
...
readings = malloc(NREADINGS * sizeof(double));

And a reminder, sizeof is a compile-time operator, so there is no runtime cost to using it. If the expression provided to sizeof cannot be evaluated at compile-time, the compiler will tell you.

Wednesday, 31 October 2018

A comparison of the TM1637 protocol with I2C protocol

The TM1637 is a Chinese made IC designed to drive up to 6 7-segment LEDs. It offers serial data input so that only 4 wires are need to connect to the display: POWER, GND, CLOCK and DATA. In fact it can also scan a keyboard matrix and return the key status to the controller. It can be found on integrated 4 digit displays available on eBay from Chinese sellers for a dollar or two. It follows on from the trend by MAXIM display chips serving similar functions. It's an attractive component if your microcontroller project needs a display and you don't want to use up lots of lines, drivers and resistors driving LED digits yourself, not to mention the coding of the multiplexing. A display board incorporating this controller costs only a little more than the displays on it.

The serial protocol has already been explained in this blog post. It's fairly easy to implement in the language of your choice, provided you can do low level bit-banging. This post is to explain the differences between and I2C protocol and the custom protocol designed by Titan Micro Electroncs, the manufacturer. TM explicitly says their protocol (call it TMP) is not compatible with I2C, but it's easy to see it has similarities. You can see that TM pared the protocol down to only what they needed.

These are the major differences:

  • I2C has addresses so a master can drive multiple slaves. TMP doesn't have this. So I2C is a bus and TMP is point-to-point. This means each display needs two lines. No daisy-chaining either. This also means TM didn't have to pay to get a slave address assigned to their chip. BTW I2C assigns the lowest bit in the address byte to indicate the direction of the data flow. Alternatively you may regard the slave as having two consecutive addresses.
  • I2C specifies that after the address comes the register address within the slave. TMP is flatter, you send a command followed by any data expected.
  • I2C sends the most significant bit first, TMP sends the least significant bit first. This only shows up in the low-level bit-banging.
  • I2C has the concept of clock-stretching. TMP has no way for the slave to tell the master to wait. It isn't needed as the chip will respond within the specified time. There is also no need to worry about a pull-up resistor as a result.
  • I2C specifies various clock speed tiers. TMP only implements their speed, a max of about 250kHz, which is fast enough.
  • As it's a custom protocol you won't be able to use any silicon or firmware assists for I2C that may be present.
Here's a project of mine that uses a display board with this controller.