RevPi makes itself independent
Revolution Pi is built for the tough industrial environment. Normally no software developer sits next to the plant to operate the RevPi. So at some point, there comes the moment when the RevPi leaves the parental home and has to manage on its own. The first step to independence is that the RevPi, whatever it has to do, starts by itself. So we have to make sure that processes are started automatically at startup.
If you search the internet you will often find rc.local as a solution. Admittedly this was my first idea. But a closer look showed me that rc.local is completely outdated and should not be used anymore. The magic word is now systemd, in lowercase. The developers attach great importance to this.
systemd
If you are now wondering “what the heck is systemd”, here are a few words about it. systemd is now the most common init process under Linux. init process is the first process that is started after the kernel is loaded and takes care of starting all other processes. Classically, almost all Linux systems have used the so-called SysVinit. This is basically nothing more than a collection of start scripts that are executed in a predefined order. SysVinit cannot exhaust modern computer architectures, which leads to unnecessarily slow starting systems. Therefore several alternatives to SysVinit have been created. systemd seems to have finally been accepted, although there is much criticism of it, and possibly better systems exist.
If you look at various pages about systemd, it kills you, but the core of the matter is very simple. Granted, before I wrote this article, I knew nothing about systemd except that it exists and what makes it crude.
For demonstration, I used RevPiBlink from the previous article again. For simplicity, I copied the executable file into ~/projects. Now I want to start this program automatically with RevPi. Therefore I have to create a service for systemd. This is simply a text file with configuration settings. For this I go into the directory /etc/systemd/system and start nano with a corresponding file:
sudo nano revpiblink.service
The file consists of a few lines:
[Unit] Description=Let LED A1 blink permanently [Service] Type=simple ExecStart=/home/pi/projects/revpiblink [Install] WantedBy=multi-user.target
What do the individual lines mean? The lines in square brackets mark different sections. Under [Unit] is the description. Description is free text. That’s all we need for now.
Chapter [Service] defines what is to be done. Type=simple, just leave it like that. Whoever is interested will find countless articles on the net. ExecStart describes what should be done when starting the process, similarly, there is also ExecStop. But we don’t need that right now.
[Install] tells systemd when the process should be started or who needs it. WantedBy thus defines a target state at which the corresponding process should run. In our case this is multi-user.target. This stands for multi-user operation on a console basis. Usually, this is the “end station” for the RevPi. Above that there is graphical.target, if a graphical user interface is running. Enough talk about things I only know a little bit about myself.
After revpiblink.service is created, systemd has to know that the file exists and the service has to be activated. That works with
sudo systemctl daemon-reload
and
sudo systemctl enable revpiblink
If you restart the RevPi now, LED A1 should flash after powering up. A look into the process list with ps -All | grep revpiblink should now list the corresponding process.
Shutdown
Thereupon I realized a first practical application, namely the automatic shutdown. As a basis I use RevPiTestInput. I modified the new program RevPiShutdown in a way that periodically the input IN is scanned and as soon as it is true, the shutdown is triggered. For this, I simply replaced the line
piC.GetBitValue(&spiValue); printf("%i, ",(int)spiValue.i8uValue);
… with these…
while (true) { piC.GetBitValue(&spiValue); if (spiValue.i8uValue == 1) { system("sudo shutdown -h now"); } usleep(100000); }
The last line of the loop simply pauses. Since we want to query a key, the query interval must be much smaller than one second, otherwise, keystrokes might be missed. Therefore I use usleep. The parameter specifies the waiting time in microseconds.
Again, I copy the program into ~/projects. Then I create a new service in /etc/systemd/system. For this, I simply made a copy of revpiblink.service
sudo cp revpiblink.service revpishutdown.service
and modified the ExecStart entry
ExecStart=/home/pi/projects/revpishutdown
and then…
Systemctl daemon-reload Systemctl enable revpishutdown
Tiny test (my wife insisted that “tiny” was the right word here)…
I set the input with my great cable solution
Connection to 192.168.178.32 closed by remote host. Connection to 192.168.178.32 closed.