Update:
The Finish Line!
I have, finally, succeeded.
To recap:
The original requirements were to find a way to boot multiple operating systems on my 'bot, such that:
- It had to be entirely headless - that is, it must not depend on ANY display device or keyboard. (i.e. Needing a monitor for an operating system select menu is NOT acceptable, though a keyboard/display for initial configuration would be OK.)
- It is desirable to use GPIO pins, connected to either ground, (preferably), or +3.3v to select the operating system to run. Ideally it would use some kind of hardware selection process - a dip-switch for example - to select the O/S to boot.
- There should be a way to boot to a “recovery” process. It would be acceptable for the recovery process to require a monitor and keyboard.
- It should be as simple and easily maintained as possible. Ideally, it would be something I could post here and have people who don’t really want to know about the finer details of operating systems or partitioning would be able to use it.
As I have mentioned before, there were several possibilities. Out of those possibilities I eventually selected PINN.
-
Though the “first-cost” development process was significantly greater, ultimately the recurring cost to maintain it and the initial cost to install for subsequent installations is so much less as to be virtually trivial - no more difficult than flashing an SD card for use in the 'bot.
- The creation of the special “PINNified” images to use with PINN isn’t necessarily easy, but isn’t too bad once you’ve done it once or twice.
- Once the images are created, creating the bootable media is almost trivial.
-
The PINN forum and PINN’s developer, procount, were breathtakingly helpful, beyond what I could hope or think. He was with me every step of the way - offering advice, suggestions, implementing bug fixes virtually in real-time, adding essential features, and so on. This is as much his effort as it is mine. Other members of the forum, especially Lurch, were also very helpful.
- Direct access to those who are subject matter experts was essential for the success of this project.
- Direct access to those who are subject matter experts was essential for the success of this project.
-
Once the PINN boot manager and the PINNified images are installed, it becomes trivially easy to back up individual operating systems to external media.
-
The ability to script a modified behavior for PINN is an invaluable tool as it allows the generic nature of PINN to be customized and tailored to a particular need that might not be commonly used.
=============================
All that being said. . . .
First:
The software.
The software comes in two main parts - a customized config.txt that PINN itself boots with and a specially crafted pinn_init.sh script.
The config.txt for PINN:
The first part of the config.txt, configures the GPIO pins that are going to be used to select the operating system to boot, like this:
gpio=21=ip,pu
This takes Broadcomm GPIO pin 21, (physical pin 40), and sets it as an input, (ip), and attaches an internal pull-up resistor to it, (pu). This causes the pin to stay at a logical “1” until pulled low by a connection to physical pin 39, (ground).
This is done four more times for each of the pins I wanted to use for my OS selections. In my case I used the last six pins because:
- They weren’t being used by the GoPiGo controller board, nor any other software that the GoPiGo uses.
- I happened to have a five-position dip-switch laying around.
Of course, you can use any pins you want, so long as they are not being used for anything else either at boot-time, (or any other time while the device is running), because they stay tied to ground if selected.
The last two parts of the config.txt are required for PINN to boot properly and are not modified.
The next part is the special pinn_init.sh script that does “the heavy lifting” so to speak.
First there are some essential “functions”:
The gpio_export function uses the mini-Linux that PINN boots to enable access to the GPIO pin passed as an argument by exporting the pin itself, ($1) and the signal direction as specified in the config.txt file, (in)put.
This is done one at a time for each pin being read,
The next function, gpio_unexport,
releases the pin, ($1), after we’re done with it
The next function, gpio-value,
is what actually reads the value of the GPIO pin in question.
So, the logic flow is essentially like this:
- Decide what pin we want to read. That becomes the argument ($1).
- “Export” the pin so we can read it from within the script.
- Read the value of the pin, either a logic 1 or a logic zero, and return it so we can capture that value.
- “Un-export” the pin so it’s not being tied up.
Now that these functions have been defined, we can make use of them to choose what we want to do.
In a “standard” PINN installation, each operating system has two partitions just like Raspbian; a “boot” partition and a “root” partition. Each installed operating system’s boot partition, (the one we’re interested in), is the even numbered partition, starting with partition number six. So if there are three operating systems installed, their respective boot partitions will be partitions six, eight, and ten.
PINN boots the desired operating system by booting through the associated boot partition. It does this by using a special command “rebootp”. (i.e. “rebootp 6” causes PINN to force a reboot with partition six as the target boot partition.)
I create a loop that iterates through each pin, and associates that pin with a partition - the first pin in the list is associated with partition 6, the next with partition 8, and so on. Since, (for whatever reason), I pre-increment the partition, I start with it set to four.
In the “for x in [set of things]” statement
for n in 21 26 20 19 16; do
we iterate over each GPIO pin we want to use in turn. Note that here order is important because each pin is associated with a boot partition in turn, starting with partition six.
The “if” statement works almost like a switch-case construct - it checks a pin to see if it’s zero and if it is, it immediately boots to the associated operating system. If not, it goes back to check the next pin and repeats that until either a pin reads zero, or it runs out of pins to check.
It’s important to note that this script does not check to see if there is actually an operating system to boot, (or if the partition even exists!), so if you select a partition that doesn’t exist, it will lock up the 'bot and require a power-cycle. You can avoid this by only listing pins that are associated with valid partitions - or - using complex “sed” and “awk” expressions to parse the list of installed operating systems. I chose the former to avoid the complexity of sed and awk, as they are virtually unreadable and difficult to understand.
At the very end is the default case: If no operating system is selected it “falls through” and boots PINN as a recovery option. PINN, of course, requires a monitor, keyboard and, (optionally), a mouse.
Obviously this script could be made more robust with better error checking, etc., but I opted for simplicity and ease of use instead of several lines of Egyptian Hieroglyphics for the more complex logic.
Next: Hardware